The difference
The last term of an SPF record says what to do with servers the record doesn't list. -all produces fail: the domain says those servers are not allowed to send for it. ~all produces softfail: they probably aren't, but don't reject on that alone. Both are defined in RFC 7208.
example.com. TXT "v=spf1 include:_spf.google.com -all"
example.com. TXT "v=spf1 include:_spf.google.com ~all"
| Qualifier | Result | Meaning |
|---|---|---|
+all |
pass | Anyone may send (never use this) |
?all |
neutral | No statement |
~all |
softfail | Probably not authorized |
-all |
fail | Not authorized |
What you see in headers
The receiver records the result in Authentication-Results, and some also add a Received-SPF line:
Authentication-Results: mx.example.net;
spf=softfail (domain of example.com does not designate 192.0.2.25 as permitted sender) smtp.mailfrom=example.com
Received-SPF: Softfail (domain of example.com does not designate 192.0.2.25 as permitted sender) client-ip=192.0.2.25;
The exact wording varies by receiver. The domain checked is the envelope sender (smtp.mailfrom, the Return-Path), not the From address. The Email Header Analyzer shows the result for any message.
How receivers treat them
RFC 7208 lets receivers reject on fail, and some do, at SMTP time. A softfail is normally accepted and counted against the message by the spam filter. In practice the large mailbox providers rely on DMARC for the decision, and DMARC treats both the same way: anything other than an SPF pass is simply not an SPF pass. So once a domain has an enforced DMARC policy, the choice between ~all and -all matters much less than it used to.
Which one to use
- Domains that send no mail at all:
v=spf1 -all. No server is allowed. - Domains with DMARC at quarantine or reject: either works. Many admins use
~allso that a receiver which rejects on SPF fail alone doesn't drop forwarded mail that DKIM would have rescued under DMARC. - Domains without DMARC enforcement:
-allgives receivers a clearer signal, but only once you are sure the record lists every sender.
Whichever you choose, the real work is making the record complete and getting DKIM in place.
Fixing spf=softfail or spf=fail
The sending IP isn't covered by your record. Find which service sent the message, then add its mechanism:
v=spf1 include:_spf.google.com include:spf.esp.example.net ip4:203.0.113.10 ~all
Add only what the provider documents, and watch the lookup count: each include costs at least one of the 10 allowed DNS lookups (too many DNS lookups). If the service uses its own return-path domain, your SPF record isn't involved at all, and you need DKIM for DMARC to pass.
Forwarded mail always fails SPF at the final destination, because the forwarder's IP isn't yours. That is expected; DKIM covers it.
Related
- spf=none: no SPF record was found.
- SPF multiple records: why two records cause a permerror.
- dmarc=fail: what happens next when SPF and DKIM don't align.
- SPF record: the full record syntax.
Check your record and its lookup count with the SPF Checker.