SPF ~all vs -all: The Softfail Epidemic

Most domains end their SPF record with ~all, which tells receivers to accept mail that fails. It's the safe default that quietly guarantees SPF can't stop spoofing on its own.

Look at almost any domain’s SPF record and it ends the same way: ~all. Not -all. That single character — a tilde instead of a hyphen — is the difference between “reject mail that fails this check” and “accept mail that fails this check, but maybe look at it funny.” The internet overwhelmingly chose the second one. And most of the people who published ~all have no idea they told the world’s mail servers to let unauthorized senders through.

This is the softfail epidemic, and it’s worth understanding because it explains a thing that confuses people constantly: why SPF, a protocol whose entire job is to stop forged senders, so rarely stops anyone.

Four characters, four very different policies

SPF (RFC 7208) is a DNS TXT record that lists which IP addresses are allowed to send mail for your domain. The mechanisms — ip4:, include:, mx, a — build up the allowed set. The record almost always ends in an all mechanism, and the qualifier in front of all is where the actual policy lives. There are four:

  • +all — Pass. Everything is authorized. This is “anyone may send as me,” which is to say no policy at all. Nobody sane publishes this.
  • -all — Fail. Hardfail. Any IP not in your list is explicitly unauthorized.
  • ~all — SoftFail. The IP is probably not authorized, but the domain isn’t willing to say so firmly.
  • ?all — Neutral. No statement, treated exactly like having no policy.

The default qualifier, if you write a bare all, is +. That’s the first footgun, but not the interesting one. The interesting one is the gap between -all and ~all, because that gap is where SPF’s promise quietly dissolves.

What softfail actually instructs a receiver to do

Here’s the part people miss. These qualifiers aren’t just labels for your own peace of mind — they’re instructions to the receiving mail server, and RFC 7208 spells out what each one means.

For a hardfail (-all), section 8.4 says the result “is an explicit statement that the client is not authorized to use the domain in the given identity,” and the receiver may reject the message outright.

For a softfail (~all), section 8.5 is remarkably candid. A softfail “ought to be treated as somewhere between ‘fail’ and ‘neutral’/‘none’.” The domain “believes the host is not authorized but is not willing to make that strong of a statement.” And then the operative line: “Receiving software SHOULD NOT reject the message based solely on this result, but MAY subject the message to closer scrutiny than normal.”

Read that again. ~all is a documented instruction not to reject on the basis of SPF alone. When you publish ~all, you are telling every receiver on the internet: mail that fails my SPF check should still be delivered. Maybe filtered a little harder. Probably not. The spec itself tells receivers to let it through.

So the question “does my SPF stop spoofed mail?” has a precise answer for the majority of domains, and the answer is no — not because SPF is broken, but because they explicitly asked it not to.

Why the whole internet picked the weaker option

If ~all is so toothless, why did it win? Because -all breaks legitimate mail, and it breaks it in a way that’s infuriating to debug.

SPF has a structural flaw that has nothing to do with qualifiers: it authenticates the connecting IP against the envelope sender, and it re-checks at every hop. The moment someone forwards your message — a user with a .edu address auto-forwarding to Gmail, a mailing list, a “contact us” form that relays mail — the forwarding server becomes the connecting IP. That server was never in your SPF record. SPF fails. Not because anything was forged, but because forwarding is, from SPF’s narrow point of view, indistinguishable from an impostor.

With -all, that forwarded-but-legitimate mail gets rejected. With ~all, it survives. Faced with “occasionally reject real mail from real users” versus “occasionally let a spoof through,” an enormous number of operators — and, more decisively, the platforms and wizards that generate SPF records for them — picked the tilde. Public measurements bear this out: scans of the SPF-publishing internet consistently put softfail in the majority, with ~all outnumbering -all across millions of domains, and most major sending platforms defaulting to ~all in their setup docs. The default became the norm, and the norm became the internet’s actual email posture.

The tragedy is that everyone treated this as an SPF tuning decision — hardfail brave, softfail cautious — when it was really an admission that SPF cannot safely be enforced on its own. And that admission points directly at the thing that was supposed to fix it.

SPF was never checking the address you think it was

The deepest reason ~all vs -all matters less than people fight about it: SPF doesn’t check the sender your users see.

SPF validates the MAIL FROM — the envelope sender, the return-path used during the SMTP conversation — and the HELO name. It does not look at the From: header, the human-readable address in the mail client. RFC 7208 is explicit that these are the identities it checks, and the header From is not among them. A spammer can put anything in the From: header, use their own domain in the envelope where SPF passes cleanly, and your SPF record — hardfail or softfail, it makes no difference — never had jurisdiction over the address the victim actually reads.

This is why “we have -all, we’re protected from spoofing” is wrong even in the brave case. SPF hardfail protects your envelope domain from being used as the return-path. It does nothing about someone forging your domain in the visible From: while passing their own SPF. The check and the deception are looking at different fields.

The protocol that finally connects the From: header to authentication is DMARC. DMARC requires that a passing SPF (or DKIM) result align with the From: domain, and — this is the part that makes the softfail argument almost moot — DMARC lets the domain owner publish the reject policy that SPF’s ~all refused to. Under DMARC, whether your SPF ends in ~all or -all barely matters, because DMARC re-derives the pass/fail from alignment and applies your p=reject regardless. The enforcement moved up a layer, to the layer that’s actually looking at the right address.

What to actually do

Two honest positions, depending on where you are.

If you have DMARC with an enforcing policy (p=quarantine or p=reject), stop agonizing over ~all versus -all. DMARC is doing the enforcement, on the correct identity, with alignment. Keeping ~all is fine and arguably safer, because it avoids double-penalizing forwarded mail that DMARC will catch through DKIM anyway. The tilde is not your weak link.

If you don’t have DMARC, then understand what your ~all actually is: a note to the world’s mail servers politely asking them not to enforce your SPF. It is not spoofing protection. It never was. Moving to -all buys you a little — it lets receivers reject forged envelope senders — at the cost of breaking forwarded mail, and it still leaves your visible From: wide open. The real fix isn’t picking a better qualifier. It’s publishing DMARC, so that something is finally checking the address your users read.

The tilde epidemic isn’t a mistake millions of admins made. It’s the correct reading of a protocol that can’t safely say “reject” by itself. The mistake is stopping there and thinking the job is done.

Continue the conversation

← Back to Blog