SPF: your record, the ~all ending, and why it never rejects
An SPF (Sender Policy Framework) record is one line of text in your domain’s DNS (Domain Name System) that names the servers allowed to send email with your domain after the @. Every receiving mail server looks that line up for every message you send. It checks whether the connecting server is on the list and writes the verdict into the message headers. If your mail keeps landing in junk and nobody can tell you why, that verdict is the first thing to read, because it is the one part of the story the receiver spells out in plain text.
You do not need to find the record yourself. The scan below reads your domain’s DNS the way a receiver does, prints the exact SPF record it found, counts the DNS lookups inside it, and tells you how the record ends. The ending is the part that tends to go unread.
What the record is made of
A small business with a hosted mailbox and one marketing tool ends up with a record like this:
v=spf1 include:_spf.mailhost.example include:mail.crm.example ip4:203.0.113.25 -all
It lives as a TXT record on the bare domain (the DNS name with nothing in front of it, shown as @ in most control panels). v=spf1 says which version this is; there has only ever been one. Everything after it is a list of mechanisms, read left to right, and the first one that matches the sending server decides the result.
include:_spf.mailhost.example pulls in another domain’s SPF record and treats its servers as yours. This is how you authorise a provider without knowing its IP (Internet Protocol) addresses. ip4:203.0.113.25 names one address directly; ip4:203.0.113.0/24 would name a block of them. a and mx mean “whatever my A record or MX records point at”. They are cheap to write and expensive to evaluate, because each one costs the receiver a DNS lookup.
-all at the end is the terminal qualifier. It says what to do with a server that matched nothing before it. -all means fail. ~all means softfail, a weaker verdict: the SPF standard (RFC 7208) tells receivers to accept the message and mark it. ?all means neutral, which is the same as saying nothing. +all means every server on the internet passes, so the record no longer excludes anyone and receivers give it no weight.
A receiver will follow at most ten DNS lookups while evaluating the record. include, a, mx, ptr, redirect and exists each cost one, and includes inside includes count against the same ten. Past that, the receiver stops and returns permerror, which is worse than having no record at all, because the receiver treats it as a broken policy.
The census view of the live internet
You are far from alone in having a record and still getting junked. The October 2026 census ran the SPF check on 332,492,319 domains across the whole registered internet. Of those, 87,173,390 publish a record ending in ~all (softfail) and 61,408,709 publish one ending in -all (hard fail).
More of the domains that publish a record chose the ending that tells receivers “mark it, do not refuse it” than chose the one that tells them to refuse. A softfail record still works, and the consequence is the one you asked for: a message from an unlisted server arrives with a mark against it instead of being refused, and the mark counts towards the junk decision.
Choosing how the record ends
Both endings tell receivers that a server missing from your list is not authorised. They differ in how hard they say it, and each choice has a cost.
With -all, a receiver that acts on SPF alone may refuse a message from an unlisted server. A forger gets turned away more firmly, and so does your own mail from any sending tool you forgot to list. RFC 7489 (Request for Comments), the DMARC (Domain-based Message Authentication, Reporting and Conformance) standard, also notes that some receivers check SPF before DMARC runs, so a -all fail can reject a message before an aligned DKIM (DomainKeys Identified Mail) signature gets the chance to carry it.
With ~all, the same message arrives with a mark against it and the mark counts towards the junk decision. A sender you forgot costs you placement instead of a bounce, and a forger’s message gets the same softer treatment.
Either way, the record is only as good as its list. DMARC aggregate reports show every server sending as your domain, so switching on DMARC reporting first lets you build the list from evidence before you decide. Which ending suits a domain depends on how sure you are that the list is complete and how much a bounced message would cost you.
How a receiver reads it
SPF checks the envelope sender: the address in the SMTP (Simple Mail Transfer Protocol) MAIL FROM command, which shows up in delivered mail as the Return-Path header. It also checks the name the sending server announced in its HELO greeting. The From line your customer sees in their inbox is a different field, and SPF never reads it.
Bulk senders and helpdesk tools often put their own domain in the envelope and your domain in From, so a message can pass SPF on their domain while doing nothing for yours. That gap is why SPF on its own settles nothing about junk placement. DMARC is where the two addresses get compared, and the DMARC piece covers that comparison.
After the check, the receiver stamps the result into the message. You will see one of these two lines, sometimes both:
Received-SPF: softfail (mx.receiver.example: domain of transitioning bounce@yourshop.example does not designate 198.51.100.7 as permitted sender) client-ip=198.51.100.7;
Authentication-Results: mx.receiver.example; spf=fail (sender IP is 198.51.100.7) smtp.mailfrom=yourshop.example
The results a receiver can write are pass, fail, softfail, neutral, none, permerror and temperror. Only pass helps you. none means no record was found. With permerror the record exists and the receiver could not make sense of it. temperror says DNS did not answer in time, so your nameservers are the problem and the record is fine.
Where to find your own verdict
Send a message from your normal mail client to a mailbox you control at a different provider, then open the raw message. Webmail clients call this “Show original”, “View source”, “View message details” or just “Headers”. Search the text for spf=. Whatever follows is the verdict that receiver reached, and the bracketed text after it is the receiver’s own explanation, usually with the IP address it saw.
If the address in that line is one you do not recognise, you have the whole diagnosis. A service is sending as you, and your record does not list it. Ask that tool’s support page which include: it wants. Every legitimate mail service publishes one.
To read the record as it stands, from any terminal:
nslookup -type=txt yourshop.example
or, on a Mac or Linux machine:
dig +short TXT yourshop.example
You should see exactly one line beginning v=spf1. Two such lines is a fault in its own right, covered below.
Match the line you found
The headings below are the verdicts as receivers write them, so search your headers for the one you have.
spf=none
There is no SPF record on the domain, or it sits on the wrong name (putting it on www or on mail is a common slip). Publish a TXT record on the bare domain at your DNS host. Start with your mailbox provider’s include and the servers you know about, and end it with ~all or -all once you have read the trade-off.
spf=fail or spf=softfail on mail you sent yourself
Your record exists, and the server that carried the message is missing from it. Read the IP in the Received-SPF line and work out which service owns it; the tool that sent the message will tell you. Add that service’s include:, or the address itself as ip4:. Publish it and wait for the old TTL (Time to Live) to expire. Then send again.
spf=permerror with “too many DNS lookups”
The line in the header reads:
spf=permerror (SPF PermError: too many DNS lookups)
Your record, once every include is unpacked, asks the receiver for more than ten lookups. Remove any include: for a service you no longer use. Replace a and mx mechanisms with the literal ip4: addresses they resolve to, since a literal address costs nothing. If you still cannot get under ten, the record is telling you that too many outside services send as this domain, and some of them should move to a subdomain with an SPF record of its own.
spf=permerror with “multiple SPF records”
Two TXT records on the same name both start with v=spf1. Receivers must treat this as an error, so every message fails, even from servers that both records list. This happens when a second tool’s setup wizard adds its own record instead of editing the one already there. Merge the mechanisms into a single record, delete the other, and check with nslookup that only one line remains.
spf=pass and the mail is still junk
SPF has passed, so the problem sits one layer up. Check that the domain in Return-Path matches the domain in From. If a sending tool uses its own bounce domain, SPF passes for the tool and does nothing for you, and only a DKIM signature in your domain rescues the message. The DKIM piece explains how to find out whether your provider is signing. If both pass and mail is still junked, authentication is fine and the cause is reputation or content, which no DNS change will fix.
Forwarded mail fails, everything else passes
When a recipient forwards your message to another mailbox, the forwarding server becomes the sender, and it is nowhere in your record. SPF cannot fix this by design. The forwarding side should rewrite the envelope (a technique called SRS), and not every forwarder does. Your defence is DKIM, which survives forwarding because the signature travels inside the message.
The record ends in +all or ?all
The record authorises everyone, or nobody in particular. Receivers know this pattern and give it no credit. Replace the ending with ~all or -all. The trade-off between them is above, and the qualifier piece goes through each qualifier in more depth.
Where the record goes
No mailbox provider has an SPF setting in its admin console. The record goes at whichever company answers DNS for the domain. To find it, open the domain at the registrar and read its Nameservers section. In that company’s DNS settings, usually under a menu called DNS, Records or Advanced DNS, add or edit a TXT record with @ in the Name or Host field, which means the domain itself. Typing the full domain name there can create the record in the wrong place. Paste the v=spf1 line into the Value, Data or Content field without quote marks, because most hosts add their own and a second pair breaks the record.
When the DNS host is Cloudflare
Cloudflare only answers DNS for a domain once the nameservers at the registrar point at the two Cloudflare nameservers shown in its dashboard, and the domain’s Overview page says whether Cloudflare is active. Until then, a record added in Cloudflare does nothing, and the SPF record belongs wherever the DNS actually lives. In Cloudflare, go to DNS, then Records, add a record of type TXT with Name @, put the SPF text in Content and leave TTL on Auto. TXT records are never proxied, so the orange cloud plays no part. Cloudflare does not stop you adding a second v=spf1 record. The SPF standard forbids two, so edit the one already there.
Email Routing is the Cloudflare trap. It forwards mail arriving at your domain and publishes its own records for that inbound forwarding. It sends nothing as your domain and gives the mail you send no SPF coverage, so your record still has to name the service you actually send from.
Mailbox provider values
Each mailbox provider publishes the include its servers need, and every sender goes into the same single record, space-separated, before the all term:
v=spf1 include:_spf.google.com include:servers.mcsv.net include:<your helpdesk> ~all
Each include costs lookups against the ten-lookup ceiling, and a provider’s include often expands to several more on its side, so a line with four or five senders is closer to the limit than it looks.
Google Workspace
Google publishes include:_spf.google.com. For a domain whose mail all leaves through Google, the record Google documents is v=spf1 include:_spf.google.com ~all, published at your DNS host because the Admin console has no SPF setting. If a newsletter tool or CRM already has a record, add Google’s include into that one.
A Google Group that relays mail to outside members forwards it instead of resending it. Forwarded mail fails SPF at the receiving end because the connecting server is no longer on your list, and no change to your record fixes that. A DKIM signature survives the forward.
Microsoft 365
Microsoft publishes include:spf.protection.outlook.com, and the include host has to read exactly that. A copied record naming a different host won’t authorise Microsoft’s servers. Microsoft’s documented record ends on -all:
v=spf1 include:spf.protection.outlook.com -all
Microsoft writes the record for you only when it also runs the domain’s DNS, in the admin center under Settings, then Domains, then DNS records. Otherwise, publish it at your DNS host. Before you settle the ending, check what the include covers:
- Exchange Online itself: covered.
- A connector relaying mail from an on-premises server or an application through Exchange Online: covered, because it sends from your tenant.
- An application sending with SMTP AUTH and a mailbox’s credentials: covered, because the mail still leaves through Microsoft.
- A CRM, invoicing system, helpdesk, campaign tool, scan-to-email printer or website contact form: each needs its own
include:in this line, or has to stop sending as your domain. - Anything sending straight out of your own network or from a third party’s platform: not covered.
Whatever on those last two lines is missing from the record is what -all lets receivers refuse and ~all lets them mark. The trade-off applies to Microsoft’s value as much as to anyone’s.
Publish the change and confirm it
In your DNS control panel, edit the existing TXT record on the bare domain; do not add a second one. Set the TTL to 300 seconds while you are making changes, so mistakes expire fast, and put it back to an hour or more once the record has been stable for a week.
Then send a test to an outside mailbox and read spf= in the headers again. Rerun the scan above and it will show the new record as receivers now see it, with the lookup count and the ending. Once the verdict reads pass from every service you use, the SPF half of your junk problem is closed, and the rest of the fix lives on the DMARC and DKIM pages.
Figures from the defaults.exposed census, data as of 12 October 2026. Census numbers move every month; the current values are on the census data page.