A free SPF record generator that does the part other builders leave to you. Pick your senders, or import the record you already publish, and get a valid record back. Every include: is resolved live and its chain counted against the ten-lookup limit — not read from a table that went stale when your provider last changed their record.
Tick the services that send mail for your domain. Add any servers of your own as IP addresses — those cost no lookups at all. The counter updates from live DNS every time you build.
Quick Answer: how do I create an SPF record?
List every service that sends mail for your domain, then publish one TXT record at the domain in the form v=spf1 followed by an include: for each provider, ip4: for any servers of your own, and ~all or -all at the end. The one rule that breaks most records: the whole thing may cost at most ten DNS lookups, counting the includes inside your providers’ records too. The builder above resolves each one live and tells you the real number.
Robert Harrison
OSINT & Network Utility Expert
Works on DNS records, network utilities and the developer tooling around them — the same lane as the SPF checker, DMARC checker and DNS lookup on this site.
This builder resolves provider costs instead of printing them because the printed ones are wrong. Measuring fifteen provider includes against four independent public resolvers in September 2026 found the leading published table disagreeing with live DNS on ten of them — _spf.google.com costs one lookup, not the four every table still prints, because Google inlined its netblocks. One provider was under-counted, which is the direction that lets you publish a record already over the limit. The counting logic was checked against 118 test cases before it went near a real domain.
Last reviewed 22 September 2026 · Published 22 September 2026
View all articles by Robert HarrisonAn SPF record is one line of text in your DNS that names every server allowed to send email using your domain. When a message arrives claiming to be from you, the receiving server reads that record and checks whether the machine that just connected is on your list. SPF is defined in RFC 7208, and the record lives as a TXT record at the domain itself.
Here is a record with every part named:
v=spf1 ip4:203.0.113.5 include:_spf.google.com include:sendgrid.net ~all
| Part | What it does | DNS lookups |
|---|---|---|
v=spf1 | Marks this TXT record as an SPF record. Must come first, and must be exactly this. | 0 |
ip4:203.0.113.5 | Authorises one address or range directly. The cheapest possible term. | 0 |
include:_spf.google.com | Authorises whatever that domain authorises. Pulls in their whole record, including any includes inside it. | 1 plus their chain |
~all | What to do with everything else. ~ softfail, - hard fail, ? neutral. | 0 |
That third row is where records break. An include: does not cost one lookup — it costs one lookup plus every counted term inside the record it pulls in, and inside theirs, all the way down. You cannot see that cost by looking at your own record, which is why a record that reads as four lines can quietly need fifteen lookups.
Key fact: RFC 7208 §4.6.4 sets a hard ceiling: implementations “MUST limit the total number of those terms to 10” and “MUST return permerror” if it is exceeded. A permerror is not a partial failure — SPF stops working for every recipient, including the servers you listed correctly.
Most SPF generators are forms. You tick boxes, they join strings together, and you paste the result into DNS. The better ones print a lookup cost next to each provider from a stored table. That table is the problem.
In September 2026 we resolved fifteen provider include hosts against four independent public resolvers and compared the result with the most complete published table we could find. It disagreed on ten of the fifteen. The clearest case is Google: every table prints four lookups for Google Workspace, because _spf.google.com once contained three nested include:_netblocks terms. It does not any more — it lists IP ranges directly, and costs one. Microsoft 365 is published as two and measures one. SendGrid is published as five and measures two.
Over-counting is annoying: it pushes people into flattening records that never needed it. Under-counting is dangerous, and we found that too — one provider published as a single lookup measured two, which is how a builder tells you that you are inside the limit when you are already over it. A stored table cannot tell you which way it is wrong. A live resolution cannot be wrong about today, because it is today.
Two ways in, depending on whether you are starting fresh or fixing something that broke.
~all while you are still discovering your senders, -all once the list is complete. Section four below explains why the order matters more than the choice.Tip: the address bar carries your whole build. Send that link to whoever manages your DNS and they will see the same record, the same count and the same warnings — recalculated live when they open it, so it stays honest if a provider changes their record in the meantime.
The counter is the only number on this page that decides whether your record works. RFC 7208 §4.6.4 names exactly which terms are counted, and the list is shorter than people expect.
| Costs a lookup | Costs nothing |
|---|---|
include: · a · mx · ptr · exists: · redirect=and include and redirect then recurse into whatever they point at |
ip4: · ip6: · all · exp=the RFC notes exp is only resolved later, after evaluation |
So a record with twenty ip4: ranges and one include costs one lookup. A record with four includes can cost fifteen. Length has nothing to do with it.
A total on its own does not tell you what to do about it. Once you build, the SPF record generator lists every term that costs a lookup, what it costs, and what share of your ten it is using — alongside the record it resolved to and the names it pulls in behind the scenes.
That is usually the moment the problem becomes obvious. A record at sixteen lookups is rarely sixteen small costs; it is normally two providers eating three quarters of the budget while five others cost one each. You do not need to redesign your mail estate, you need to deal with those two. None of the other generators we could inspect shows this breakdown, which is why “over the limit” usually arrives as a number with no instruction attached.
There is a separate cap that almost no generator mentions and no ranked SPF builder we examined counts at all. RFC 7208 §4.6.4 also says implementations “SHOULD limit void lookups to two” and that exceeding it “produces a permerror result”. A void lookup is a term whose DNS query comes back with nothing — either an empty answer or a name that no longer exists.
This matters because it fails records that are comfortably inside the ten. The usual cause is an include for a service you stopped using: the contract ended, they removed the record, your DNS still points at it. Three of those and SPF permerrors even though you are only at six lookups. The builder counts them and shows the total next to the main counter.
The same section adds two limits that behave differently from each other, and the RFC explains why. An mx term “MUST NOT result in querying more than 10 address records”, and going over is a permerror. A ptr term has the same cap, but there “all records other than the first 10 MUST be ignored” — no error, just silent truncation. The asymmetry is deliberate: you control your own MX records, but you do not control the PTR records of whoever is connecting to you.
Limit: this count is correct for the moment you pressed build. Your providers can add an include to their own record tomorrow and push you over without touching your DNS. That is not a flaw in the counting — it is the reason to leave headroom rather than sit on exactly ten.
~all, -all and ?allThe last term tells receivers what to do with a server that is not on your list.
| Term | Means | Use it when |
|---|---|---|
~all | Softfail — mark the message, do not reject it | You are still finding your sending sources, or DKIM is not signing yet |
-all | Hard fail — the message is not authorised | Your list is complete and DKIM is signing every stream |
?all | Neutral — no opinion at all | Almost never. It is barely different from having no record |
+all | Authorises the entire internet | Never. This builder will not produce it |
The usual advice stops at “-all is stronger, so get there eventually”. That is incomplete, and the specification that changed it is recent enough that most guides have not caught up.
DMARC was re-published as RFC 9989 in May 2026, replacing RFC 7489. Section 7.4 contains a sentence that reorders this whole decision: a domain publishing p=reject “MUST NOT rely solely on SPF to secure a DMARC pass and MUST apply valid DKIM signatures to their messages”.
The reason is forwarding. SPF authenticates the server that connected, so it breaks the moment a message is relayed — a mailing list, a university alias, a forwarded mailbox. A DKIM signature travels with the message and survives the hop. The same section warns that with -all, a message that would have passed DMARC on an aligned DKIM signature can be rejected on the SPF failure alone.
So the order is: get DKIM signing first, confirm it with the DKIM record checker, and only then tighten SPF to -all. Tightening SPF before DKIM works is how you lose forwarded mail. Your DMARC policy and alignment mode is the third piece, and it is what actually decides what happens to a failure.
Key fact: RFC 9989 §7.4 also advises that domains whose users post to mailing lists “SHOULD NOT publish” p=reject at all, because list software routinely modifies messages in ways that invalidate signatures. -all with p=reject is right for a transactional or marketing domain. It is not a universal goal for every domain.
TXT. Do not edit an existing SPF record into a second one — two v=spf1 records at the same name is a permanent error.@ or an empty field; a few want the full domain typed out.v=spf1. If it is long enough to need several strings, see below.The record goes at the domain itself, not at a subdomain of it and not at a special name. Most DNS panels want @ or an empty host field to mean “the domain itself”; some want the full domain typed out. If you are unsure which, publish it and then read it back with the DNS lookup tool — if it appears at example.com rather than @.example.com, you got it right.
The TTL on the record controls how long resolvers keep the old answer. A day before a planned change, drop it to something short — 300 seconds is a common choice. Make the change, confirm it, then put the TTL back up. Without that, a mistake stays cached for as long as the old TTL said.
There is a second cache that catches people out, and it works in the opposite direction. If you check a name before publishing anything there, the resolver caches the fact that nothing exists. RFC 2308 sets how long that negative answer is kept, from your zone’s SOA record. So a record you definitely published can still read as missing, and waiting is the fix rather than editing. The often-repeated “wait 24 to 48 hours” is folklore — check the actual TTL instead.
A single DNS character-string cannot exceed 255 octets. Longer records are published as several strings that the resolver joins back together — RFC 7208 §3.3 says they are concatenated “without adding spaces”. This looks alarming in a DNS panel and is completely normal. The builder shows you the exact split when your record needs one.
Two things go wrong here. Some panels split the record for you when you paste it, and some expect you to enter each quoted string yourself — so always read the saved value back. And splitting in the wrong place, mid-term, produces a record that parses into nonsense while looking fine at a glance.
There is also an upper bound on the whole answer. RFC 7208 §3.4 asks that a query for your record fit within 512 octets, and gives a practical guideline of 450 octets for everything published at that name — which includes your verification strings and every other TXT record you have there, not just SPF. Records too long for one UDP packet, the RFC warns, “could be silently ignored”.
The builder shows which term is costing what, so start by reading that table rather than guessing. In most records one or two includes account for most of the bill. Four options, roughly in order of how much trouble they cause later.
This is the one that works most often and costs nothing. Records accumulate: a trial of a marketing tool three years ago, a helpdesk you migrated away from, an invoicing service that was replaced. Each of those is still costing lookups, and a dead one is costing you a void lookup as well. If a service no longer sends mail for you, delete its include.
If a provider publishes a small, stable set of addresses, listing them as ip4: terms costs nothing instead of one lookup plus their chain. This is what “flattening” means, and it is worth being precise about, because the advice you will read elsewhere is louder than the evidence behind it.
The word “flattening” does not appear in RFC 7208 at all, nor in M3AAWG’s best-practice documents, nor in Google’s SPF documentation. Microsoft is the only major authority that documents it, and its guidance is conditional rather than an endorsement:
In other words, a flattened record is correct on the day you publish it and silently wrong afterwards. It converts a lookup problem into a maintenance problem. That is sometimes the right trade — but it is a trade, and the services most people want to flatten are exactly the ones Microsoft says not to.
Subdomains do not inherit the parent’s SPF record — Microsoft states it plainly: “the SPF TXT record for contoso.com doesn’t cover marketing.contoso.com; marketing.contoso.com needs its own SPF TXT record.” That sounds like extra work, and it is also a way out. Send your marketing mail from news.example.com, give that subdomain its own record containing only the marketing provider, and the two records have separate ten-lookup budgets.
This has a second benefit worth more than the lookups: a deliverability problem on the marketing stream stops dragging down the domain your invoices and password resets come from.
You will find advice that SPF macros are “a better alternative” to flattening. No standards body or mailbox provider says so. RFC 7208 §7.3 cautions the other way — macros “severely limit the ability of implementations to cache results” — and the exists: mechanism they rely on is itself one of the ten counted terms. Macros can collapse many includes into one lookup, which is genuinely useful, but they do not escape the limit and no authority recommends them for this.
And do not publish a second SPF record to hold the overflow. Two v=spf1 records at one name is a permanent error, not a continuation.
Every domain you own and never send from should still publish an SPF record, and it is the shortest one there is:
v=spf1 -all
That authorises nothing at all, which is the point. RFC 7208 §10.1.2 calls publishing it “a well-established best practice”, and M3AAWG’s parked domains guidance calls it a “naked -all”. A domain with no SPF record is an open invitation: anyone can send mail claiming to be from it, and when recipients report that mail as spam the complaint attaches to your name. To build it here, leave every field empty and choose hard fail.
Worth doing on the defensive registrations nobody uses, and the old domain you redirect to the new one.
A subdomain does not inherit the parent’s SPF record. Microsoft puts it plainly: “the SPF TXT record for contoso.com doesn’t cover marketing.contoso.com; marketing.contoso.com needs its own SPF TXT record.” So news.example.com is unprotected even when example.com is locked down, and a spoofer can use it.
That cuts two ways, and the second is useful. Any subdomain that sends mail needs its own record here — but because each name carries its own ten-lookup budget, moving a heavy sender onto a subdomain is a legitimate way out of the limit, as section six describes. For subdomains that never send, publish v=spf1 -all on each, or a wildcard record covering the tree if your DNS provider allows it. RFC 7208 §3.5 discourages wildcards generally and notes the declaration “MUST be repeated for any host that has any RR records at all”, so a wildcard is a convenience, not a substitute for records on the names you actually use.
One documented disagreement: Google’s guidance for non-sending domains recommends ~all rather than -all, where RFC 7208, M3AAWG and Microsoft all say -all. We are flagging it rather than picking a winner quietly: if a domain genuinely sends no mail, there is nothing legitimate for a hard fail to break.
Spoofing your unused domains is a reputation problem before it is a security problem, and reputation is what receivers actually weigh — our guide to how receivers build a reputation score covers the signals, and what puts a domain on an email blacklist explains where it ends up when it goes wrong.
Every generator we were able to inspect accepts whatever you type and writes it into the record. That is how a typo becomes a DNS entry that fails silently for months. These are refused instead.
/33, an IPv6 prefix over /128, a hostname pasted into the IP box. All refused with the reason.ptr term. RFC 7208 §5.5 is titled, literally, “ptr (do not use)” and says the mechanism “SHOULD NOT be published”. It is slow, unreliable under DNS errors, and loads the .arpa nameservers. Verifiers must still support it, so an existing one keeps working — but this builder will not write a new one.redirect= and all together. RFC 7208 §6.1: a redirect “MUST be ignored if there is an ‘all’ mechanism anywhere in the record”. Choose redirect and the all term is dropped, with the reason shown.+all. It authorises the entire internet to send as your domain. There is no legitimate use, so it is not offered.One mistake no tool can catch for you: forgetting a sender. SPF only helps if the list is complete, and the services people forget are the quiet ones — the helpdesk that emails ticket replies, the CRM that sends from a salesperson’s address, the monitoring system that pages you at 3am. If mail from one of those starts going missing after you tighten to -all, that is the cause. The fastest way to find them is to read the authentication results on a message that actually arrived, which the email header analyzer lays out hop by hop.
And if mail is still being refused after SPF, DKIM and DMARC all pass, the problem has moved from authentication to reputation — why an address gets blocked in the first place is the next thing to read.
Count every include:, a, mx, ptr, exists and redirect= term, then count the same terms inside every record those pull in. ip4:, ip6: and all cost nothing. You cannot work this out from your own record alone, because most of the cost is inside your providers’ records — which is why the builder above resolves each chain rather than asking you to guess.
Because it resolved _spf.google.com instead of reading a stored table. The number four is a fossil from when that record nested three include:_netblocks terms; it now lists IP ranges directly. The practical lesson is broader than Google: a provider can change their record at any time and never tell you. Re-run the builder after any provider migration, and treat any lookup cost you read on another site as a guess about the past.
RFC 7208 §4.6.4 requires receivers to return permerror, and that is the whole record failing, not just the term that crossed the line. What you actually observe is confusing: mail that worked for years starts landing in spam, and it happens to all your senders at once, including servers you listed correctly by IP. If deliverability fell off a cliff with no DNS change of your own, a provider adding an include to their record is a prime suspect.
It is a term whose DNS query returns nothing — an empty answer, or a name that no longer exists. RFC 7208 §4.6.4 says implementations “SHOULD limit void lookups to two”, so a record can be comfortably inside the ten and still fail. To find which term is responsible, build your record above: any include that resolves to nothing is refused and named, which is usually a service you stopped paying for whose record was deleted.
-all or ~all?~all while you are still finding your sending sources, -all once the list is complete. But sequence matters more than the choice: RFC 9989 §7.4 states that a domain publishing p=reject “MUST NOT rely solely on SPF … and MUST apply valid DKIM signatures”. Get DKIM signing first, because -all rejects forwarded mail that an aligned DKIM signature would have rescued.
No — two v=spf1 records at one name is a permanent error, not a merge and not a fallback. This is the most common way a working setup breaks: somebody adds a new provider by creating a second TXT record instead of editing the existing one. To fix it, combine every term from both into one record and delete the other. Paste both into the builder above and it will deduplicate them and tell you what the combined record costs.
No. Each subdomain that sends mail needs its own record — Microsoft states it plainly: “the SPF TXT record for contoso.com doesn’t cover marketing.contoso.com”. Two consequences worth knowing. A subdomain you never send from should get its own v=spf1 -all, or a wildcard record covering the tree, because otherwise it is spoofable even when the parent is locked down. And a subdomain is a legitimate escape from the ten-lookup limit, since each name carries its own budget.
v=spf1 -all and nothing else. To build it here, leave every field empty and choose hard fail. Worth applying to more names than people expect: defensively registered domains, an old domain you now redirect, and any subdomain that exists for a website rather than for mail. One caveat if you also publish DMARC — a naked -all stops nothing on its own unless a policy tells receivers what to do with the failure.
Only for vendors whose address ranges are genuinely stable and documented, and never for Microsoft 365, whose sending infrastructure “uses dynamic IP addresses that change frequently”. The hard part is judging “stable”: if a vendor publishes its ranges on a versioned page or in a machine-readable file, that is a reasonable sign; if the only source is a support article, assume it will change without notice. Whatever you flatten, you have signed up to re-check it — Microsoft says quarterly.
They are a different thing, not a better one, and no standards body or mailbox provider recommends them for this. What macros genuinely do well is per-connection authorisation — an exists: term built from the connecting IP lets one lookup stand in for a list that would otherwise need many. That is useful at real scale. It does not get you out of the limit, because exists: is itself one of the ten counted terms.
ptr?RFC 7208 §5.5 is titled, literally, “ptr (do not use)”. If you already have one, you do not need to panic: verifiers must still support it, so it keeps working. Remove it at your next edit, and replace whatever it was authorising with the actual IP addresses of those hosts — which costs zero lookups instead of one, and does not depend on the reverse DNS of the connecting machine being correct.
redirect= and when should I use it?It hands evaluation entirely to another domain’s record, which suits a group of domains sharing one sending policy. Two rules catch people out: RFC 7208 §6.1 says a redirect “MUST be ignored if there is an ‘all’ mechanism anywhere in the record”, so the two cannot be combined; and if the target publishes no SPF record the result is permerror, not a quiet “none”. For a single domain, include: is almost always the better choice.
There is no fixed answer, and the “wait 24 to 48 hours” advice is folklore. It depends on the TTL of the record, and on negative caching if you happened to check the name before publishing — RFC 2308 derives how long a cached “this does not exist” answer survives from your zone’s SOA. The practical routine: lower the TTL a day ahead, make the change, verify, then raise it again.
Yes, and the order is worth getting right: SPF, then DKIM, then DMARC policy. SPF authenticates the connecting server, so it breaks the moment a message is forwarded; a DKIM signature travels with the message. That is why RFC 9989 §7.4 makes DKIM a requirement rather than a suggestion for any domain at p=reject. Publishing an enforcing DMARC policy before DKIM is signing every one of your streams is how legitimate mail starts disappearing.
Yes — your whole build lives in the address bar, so sending the link passes the record, the lookup count and every warning to whoever manages your DNS. The count is recalculated live when they open it rather than stored, so if a provider changed their record in between, the link shows the new number instead of a stale one. Nothing you enter is kept on our side.
Build the record here, then confirm it is doing its job. SPF is one of three checks a receiver runs, and it is the one that breaks on forwarding.
Publish it, wait for the TTL, then read it back from DNS. The checker counts the chain again from what you actually published and can simulate whether a given sending IP would pass.
Last updated 22 September 2026 · Lookup costs resolved live from public DNS on every build; rules from RFC 7208