Defaults.Exposed

Should your SPF record end in ~all or -all, and what +all authorises

An SPF (Sender Policy Framework) record can sensibly end in -all or ~all, and the two trade off differently. -all lets a receiver reject mail on SPF alone, which can stop forged mail before DMARC (Domain-based Message Authentication, Reporting and Conformance) is checked and can also bounce forwarded mail before DKIM (DomainKeys Identified Mail) gets a look. ~all leaves the decision to your DMARC policy, which keeps the DKIM route open for forwarded mail and relies on DMARC to reject forgery. If your record ends in +all you’ve told the world that anyone may send as you, and the fix is one character.

What the last token asks a receiver to do

An SPF record is a list of sending sources followed by a verdict for anything that isn’t on the list. The qualifier in front of all is that verdict.

v=spf1 ip4:203.0.113.0/24 include:_spf.example.net ~all

The receiver checks the connecting IP (Internet Protocol) address against 203.0.113.0/24 and against whatever _spf.example.net expands to. If it matches, SPF passes. If it doesn’t, the receiver reaches ~all and records a softfail. With -all in that position it records a fail, with ?all it records neutral, and with +all it records a pass for anything at all.

The receiver writes the outcome into the message headers, and that line is worth learning to read because it’s how you’ll diagnose bounces later:

Received-SPF: softfail (domain of transitioning example.com does not designate 198.51.100.7 as permitted sender)
Received-SPF: fail (domain of example.com does not designate 198.51.100.7 as permitted sender)

The word “transitioning” is the softfail tell. It comes from the original SPF specification, which described ~all as the setting for a domain still moving its senders into the record. That framing is twenty years old and it’s the reason so many guides still call ~all a temporary state.

SPF on its own produces a verdict and nothing more; the receiver decides what to do with it. Some receivers reject a hard fail during the SMTP (Simple Mail Transfer Protocol) conversation, before DMARC is evaluated. A receiver that applies DMARC uses your DMARC policy to decide what happens to the message, so where your DMARC policy enforces, it decides more than the qualifier does.

The case for -all

The -all argument is the one you’ll hear from anyone who learned SPF before DMARC existed, and it’s coherent. You know your senders and you listed them. Anything else is forged, so say so in the strongest term the protocol offers. A receiver that honours a hard fail refuses the forged message during the SMTP conversation, and the sender sees a bounce like this one:

550 5.7.23 The message was rejected because of Sender Policy Framework violation

That’s a rejection with no DMARC involved, and it’s the outcome the -all camp wants. There’s a tidiness argument as well. -all reads as a decision and ~all reads as a hedge, and audits reward records that look decided. When a supplier questionnaire asks whether your SPF record uses a hard fail, ~all earns you a follow-up email and a paragraph of explanation.

The argument holds cleanly for a domain that never sends anything a human might forward. A transactional subdomain that emits receipts and password resets and nothing else can carry -all and lose nothing by it.

The case for ~all

Forwarding is where -all stops being free. Someone with a mailbox at one provider sets up a rule that forwards their mail to a mailbox at another. Your message leaves your server, lands at the first provider, and the first provider passes it on to the second with your envelope sender still on it. The second provider evaluates your SPF record against the first provider’s IP address, and that address isn’t in your record because it isn’t yours.

With -all, the final receiver sees a hard fail. A receiver that acts on SPF at SMTP time rejects the message right there, and the person who forwarded it sees the bounce, or more often sees nothing at all and stops getting your mail. With ~all, the receiver records a softfail and carries on to DMARC. DMARC passes if either SPF or DKIM aligns, and DKIM survives forwarding because the signature travels inside the message, so the forwarded message is delivered.

At a receiver that applies DMARC, ~all with DMARC at p=reject rejects forged mail as firmly as -all does, because DMARC acts on its own result and doesn’t care which SPF verdict fed it. What ~all adds is that legitimate mail which lost its SPF alignment on the way still has a route home through DKIM, where -all closes that route at some receivers before DMARC gets a look.

Mailing lists are the second forwarding case and the same logic applies. List software resends your message from the list’s server, your SPF fails there whichever qualifier you chose, and whether the message survives depends on DKIM and on whether the list rewrote the From header.

Which way the internet went

The census counts which way operators went. Of the domains that publish an SPF record at all in the October 2026 census, 87,173,390 end in ~all and 61,408,709 end in -all. Those counts come from a separate parse of each published record, so they differ by a few domains from the SPF check’s own totals on the SPF page. Softfail is the more common choice among the domains that publish SPF.

Some of those operators chose ~all because the record they pasted ended that way, and some chose it after their first forwarding bounce, and the census can’t tell those apart. The counts are of domains, so they say nothing about how much mail each one sends. The “transitioning” wording in the header is a leftover from the specification, and it doesn’t mean the domain is part way through a migration.

A smaller group ended the record in ?all, which tells the receiver nothing, and another group has no terminal all at all, which the receiver also treats as neutral. Both are worse than either side of the argument. A record that lists your senders and then declines to say anything about the rest leaves receivers with no instruction for mail from anyone else.

What +all authorises

+all means pass. Put it at the end of the record and the receiver’s check is over before it starts, because any IP address on the internet is now a permitted sender for your domain. The mechanisms in front of it don’t matter, since anything that fails to match them matches +all.

v=spf1 include:_spf.example.net +all

That record is worse than having no SPF record. With no record, a receiver gets no SPF verdict at all. With +all, every server on the internet gets a pass, and a pass that aligns with your From domain is enough to satisfy DMARC. The census found 40,988 domains ending in +all among those that publish SPF. Each of them has written down, in public DNS (Domain Name System), that forgery is authorised.

+all tends to arrive by accident: a record copied from a forum answer that used it as a placeholder, or a setup wizard that offered “allow all” as a way to stop a bounce during a migration. If you find it in your record, the record is void until that one character changes.

The same effect hides in ip4:0.0.0.0/0 and in an include: of a domain whose own record ends in +all. The receiver evaluates the include, its +all matches, and your record passes the forgery as if you’d written the token yourself.

The record to publish

Read what you have first. From any terminal:

dig +short TXT example.com

or from PowerShell:

Resolve-DnsName example.com -Type TXT

You’re looking for the single line starting v=spf1. If two lines start that way, receivers treat the result as a permanent error and that has to be fixed before the qualifier matters. Then look at the last token. The free scan reads the same record and reports the qualifier alongside whether a DMARC policy exists to back it, so run it on your domain before you change anything and again after.

If the last token is +all, change it today to -all or ~all, choosing by the trade-off above. The same applies when it’s ?all or missing. If the record already ends in -all and DMARC is at p=quarantine or p=reject, both endings are defensible. Keeping -all keeps the SMTP-time rejection some receivers make on a hard fail, along with the risk to forwarded mail. Moving to ~all leaves the decision to DMARC at receivers that apply it and lets forwarded mail reach the DKIM check. If the record ends in -all and there is no DMARC record, the -all is the only enforcement you have, so publish DMARC before you think about changing the qualifier.

A record that pairs SPF with an enforcing DMARC policy looks like this. It ends in ~all; -all in the same place is the other ending the trade-off allows.

example.com.          TXT  "v=spf1 ip4:203.0.113.0/24 include:_spf.example.net ~all"
_dmarc.example.com.   TXT  "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"

The enforcement lives in the second line. The first line lists your senders and then, with ~all, tells the receiver to treat anything else as suspect and consult the second. Forged mail fails both SPF and DKIM and DMARC rejects it. Forwarded mail fails SPF, passes DKIM, and gets through.

The qualifier is one token in a record that has other ways to be wrong. The lookup limit and stale includes from a provider you left are covered in the SPF piece, and the policy that makes ~all safe is in the DMARC piece. If a specific bounce on forwarded mail brought you here, email delivery walks through reading the headers on the message that came back.

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.