The qualifier on the final all mechanism is the default result for any sending IP that did not match anything earlier in your record. It is the only part of an SPF record that expresses intent rather than fact, and it is where most of the argument about SPF lives.
What does each qualifier mean?
| Term | SPF result | What you are telling receivers | Typical receiver behavior |
|---|---|---|---|
-all | fail | This IP is not authorized to send as my domain. | Reject at SMTP, or accept and file as spam. RFC 7208 permits either. |
~all | softfail | Probably not authorized, but I am not certain yet. | Accept the message, record the softfail, weight it in filtering. |
?all | neutral | I am making no assertion about this IP. | Treated the same as having no SPF policy at all. |
+all | pass | Every IP on the internet is authorized to send as my domain. | SPF passes for anyone, including spoofers. |
Note that RFC 7208 does not require receivers to reject on fail. It says a fail result means the client is not authorized and the receiver may reject; a softfail message should be accepted but may be subjected to closer scrutiny. In practice large mailbox providers rarely reject on SPF fail alone anymore — they feed the result into a broader decision. Small self-hosted MTAs and appliances, on the other hand, often still reject outright on -all, which is exactly where hardfail bites you.
Why is +all dangerous?
+all makes SPF pass for every sender on the internet. That is worse than publishing no SPF record at all, because a domain with no SPF record produces a none result that receivers treat with suspicion, while +all produces an affirmative pass that some filters read as a positive signal.
It gets worse if you also publish DMARC. DMARC passes when the message has an aligned SPF pass or an aligned DKIM pass. With +all, anyone who puts your domain in both the MAIL FROM and the From: header gets an aligned SPF pass, and therefore a DMARC pass, from any IP they like. Your DMARC policy becomes a rubber stamp on other people's phishing. If you find +all in a record, it is almost always a copy-paste accident or an "it was blocking our mail so we fixed it" incident — remove it the same day.
+mx, +a, or any mechanism prefixed with + on ranges you do not control. + is the default qualifier, so include: already means +include: — the danger is specifically in applying it to all.# Find the qualifier on any domain's record
dig +short TXT example.com | grep spf1
# Real examples you can check right now
dig +short TXT google.com | grep spf1
# "v=spf1 include:_spf.google.com ~all"
dig +short TXT spf.protection.outlook.com
# "v=spf1 ip4:40.92.0.0/15 ... ip6:2a01:111:f400::/48 ... -all"What breaks under -all that survives under ~all?
SPF authenticates the SMTP envelope sender against the connecting IP. Anything that relays your mail from an IP you did not authorize produces a fail, and hardfail is where that becomes visible as a bounce rather than a filtering nudge.
- Plain forwarding. A user auto-forwards from their work address to a personal mailbox. The forwarding server relays your message from its own IP with your MAIL FROM intact, and SPF fails at the final destination. SRS rewriting fixes this, but only if the forwarder implements it.
- Mailing lists. Many lists rewrite the envelope sender (which fixes SPF) but modify the body or subject (which breaks DKIM). Some do neither.
- Vendors you forgot. Invoicing systems, backup monitoring, an appliance sending alerts from the office IP, a legacy application server relaying through a shell account. These are invisible until they bounce.
- Marketing platforms using your domain in the Return-Path without having been added to the record — common right after a platform migration.
- Multi-region ESP sending. A vendor that adds an EU or APAC range you never included in a flattened record.
Under ~all these all still deliver, usually to the inbox, and show up in your DMARC aggregate reports as SPF-failing sources. Under -all some receivers will bounce them. That difference — visibility versus breakage — is the entire argument for starting at softfail.
How does DMARC change the calculation?
This is the part people get wrong. DMARC does not distinguish between SPF softfail and hardfail. For DMARC, the only thing that matters is whether SPF *passed* and whether the passing domain aligned with the From: header domain. fail, softfail, neutral, and none are all equally "not a pass". Your DMARC policy — p=none, p=quarantine, or p=reject — is what decides what happens to unauthenticated mail.
So once DMARC is enforcing, -all adds much less than people assume against mail that spoofs your From: header. What -all still does is cover the cases DMARC does not: mail that uses your domain in the envelope sender but someone else's domain in From:, receivers that check SPF but not DMARC, and reputation systems that weight an explicit fail more heavily than a softfail. That is a real but modest benefit, and it comes with the forwarding risk above.
| Situation | With ~all | With -all |
|---|---|---|
Spoofed From: at your domain, DMARC p=reject | Rejected by DMARC | Rejected by DMARC — same outcome |
| Forwarded legitimate mail | Delivered, softfail recorded | May be rejected by strict receivers |
| Envelope-only abuse of your domain | Weak signal | Explicit unauthorized signal |
| Receiver checks SPF but not DMARC | Accepted with a penalty | Likely rejected |
| Forgotten legitimate sender | Delivers; visible in DMARC reports | Bounces; you find out from an angry user |
What should you publish?
A staged rollout, in the same spirit as the DMARC policy rollout. Do not skip straight to -all on a domain whose sending inventory you cannot list from memory.
- Publish
~allwith a complete-as-you-know-it list of senders, and publish DMARC withp=noneand anrua=address at the same time. Build it with the SPF generator and the DMARC generator. - Collect aggregate reports for at least two weeks, and longer if you have monthly or quarterly batch runs. Every SPF-failing source in those reports is either something to add to the record or something to shut down.
- Add the legitimate sources, keeping the total DNS-querying mechanism count at or below ten — see SPF PermError: too many DNS lookups if you run out of room.
- Tighten DMARC to
p=quarantine, thenp=reject, watching reports at each step. Do this before touching the SPF qualifier — DMARC is where the enforcement value is. - Once reports show a clean inventory and DMARC is enforcing, switch
~allto-allif you want the extra signal. Keep watching reports for a couple of weeks afterwards.
v=spf1 -all plus a DMARC record with p=reject. There is nothing legitimate to break, and an unused domain is a favourite for spoofing. Do the same on parked subdomains.How do you confirm what receivers actually saw?
Send a test message to an external mailbox and read the Authentication-Results header on the received copy. You are looking for the SPF result and the domain it was checked against:
Authentication-Results: mx.example.net;
spf=pass (sender IP is 209.85.220.41)
smtp.mailfrom=example.com;
dkim=pass header.d=example.com;
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.comA softfail or fail here names the IP that was rejected, which is the fastest way to identify a forgotten sender. Paste the full headers into the email header analyzer for a breakdown, and use the deliverability test to check SPF, DKIM, DMARC, MX, and PTR together before you tighten anything.