SPF ~all vs -all in one paragraph
In an SPF record, ~all (SoftFail) tells receiving mail servers that messages from any server not on your authorized list are suspicious but should usually still be delivered, while -all (HardFail) tells them those messages are unauthorized and may be rejected outright. Both use the same catch-all all mechanism; only the leading qualifier differs. The full set is + (Pass), - (Fail/HardFail), ~ (SoftFail), and ? (Neutral), all defined in RFC 7208. Use ~all while you are still discovering which services legitimately send as your domain; switch to -all once your record is complete and verified so that spoofed mail is actively refused. If you already publish DMARC at p=reject, the two qualifiers converge in practice — DMARC treats SoftFail and HardFail the same, so it, not the all tag, decides the final fate of forged mail.
That is the summary an AI Overview will hand you. What it can't show you is how the verdict flows through a real receiving server, why the choice is quietly overridden the moment DMARC enters the picture, and the specific migration path that gets you to -all without bouncing your own invoices. Those are below.
The four qualifiers, side by side
Every mechanism in an SPF record can carry a qualifier. Applied to the final all, they set the default verdict for every sender you did not explicitly authorize.
| Qualifier | Name | Record syntax | Receiver is told | Typical handling | Use it? |
|---|---|---|---|---|---|
+ | Pass | +all | Everyone is authorized | Accept all mail as legitimate | Never — defeats SPF entirely |
? | Neutral | ?all | No policy statement | Treat as if no SPF exists | Rarely — no anti-spoofing value |
~ | SoftFail | ~all | Probably unauthorized | Accept but mark, often spam/quarantine | During rollout and monitoring |
- | Fail (HardFail) | -all | Definitely unauthorized | Reject or discard | Steady state, once record is verified |
The mechanism list before all is evaluated left to right; the first match wins. all matches everything, so it must be last and it defines what happens to senders no earlier mechanism approved. A record like v=spf1 include:_spf.google.com ~all means "Google Workspace is authorized; treat anything else as SoftFail."
How the verdict actually flows
The qualifier is not an instruction the receiver must obey — it is a signal the receiver is free to weigh. RFC 7208 is deliberately soft here: it says a HardFail is a permissible basis for rejection, and a SoftFail should be accepted but "treated with suspicion." What a given provider does with that signal varies. The diagram below traces the same spoofed message through both policies.
The practical upshot: ~all leaves the decision to the receiver's spam engine, which means a determined spoof can still land in an inbox on a lenient provider. -all gives that same provider explicit permission to refuse the message during the SMTP conversation, before it is ever accepted.
The DMARC twist most guides miss
Here is the point that changes the whole calculus: once DMARC is in play, your all qualifier stops being the deciding factor. DMARC (RFC 7489) asks a single question of SPF — did the message pass SPF with an aligned domain? A SoftFail and a HardFail both answer "no." DMARC does not distinguish between them.
So if you publish p=reject, a spoofed message is refused because DMARC says to refuse it, whether your record ends in ~all or -all. The qualifier still matters for two audiences:
- Receivers that check SPF but not DMARC. These are increasingly rare among major providers but common in smaller or legacy mail systems. For them,
-allis the only signal telling them to reject. - Your own risk posture during rollout. Before DMARC reaches
p=reject, the SPF qualifier is doing real work on its own.
The clean sequence is: get SPF accurate with ~all → deploy DMARC monitoring → tighten DMARC to quarantine then reject → and along the way move SPF to -all as belt-and-suspenders.
When to use each — the decision table
| Situation | Recommended qualifier | Why |
|---|---|---|
| Brand-new SPF record, senders not fully inventoried | ~all | Avoids bouncing a service you forgot to list |
DMARC deployed at p=none (monitoring) | ~all | Collect reports first; don't reject yet |
| Record verified, DMARC at quarantine or reject | -all | Actively refuse spoofs; defense-in-depth |
| Parked domain that sends no mail | -all (with empty record v=spf1 -all) | Hard-block all mail; nothing legitimate exists |
| Domain still using forwarding without ARC/SRS | ~all with DMARC on DKIM | HardFail risks bouncing forwarded legitimate mail |
| Debugging a delivery problem | ?all temporarily | Removes SPF as a variable; revert immediately |
Migrating from ~all to -all without bouncing yourself
The only real danger in -all is rejecting your own mail from a source you forgot to authorize. A disciplined migration removes that risk entirely.
- Inventory every sender. Marketing platform, CRM, help desk, billing/invoicing, transactional API (SendGrid, SES, Postmark), and your primary mailbox provider all need to be in the record — directly or via
include:. - Publish
~alland turn on DMARC monitoring. Addv=DMARC1; p=none; rua=mailto:dmarc@yourdomain.comso you receive aggregate reports. - Read the reports for two to four weeks. Aggregate reports list every source sending as your domain and whether each passed SPF. Any legitimate source failing SPF is one you still need to add.
- Watch the 10-lookup limit. SPF permits at most 10 DNS lookups during evaluation; exceed it and the record returns a
permerror, which can invalidate authentication regardless of your qualifier. Flatten or consolidateinclude:chains if you are near the ceiling. - Flip to
-all. Once no legitimate source is failing, change the single character. No other part of the record needs to move.
You can generate and validate a syntactically correct record with our SPF record generator before you publish, then confirm the live record resolves and stays under the lookup limit.
The forwarding caveat
Traditional email forwarding breaks SPF for everyone, no matter the qualifier. When a message is forwarded, the forwarding server's IP relays it — and that IP is not in the original sender's SPF record, so SPF fails. Under -all, a strict receiver may reject perfectly legitimate forwarded mail. This is not a reason to avoid -all; it is the reason DMARC leans on DKIM alignment, which survives forwarding because the cryptographic signature travels with the message. Mailing lists and forwarders that need to preserve authentication use SRS (Sender Rewriting Scheme) or ARC (Authenticated Received Chain) to repair the chain. If your domain still relies heavily on forwarding without those mechanisms, keep ~all and let DKIM carry DMARC.
Bottom line
Use ~all while you are still learning what sends as your domain and while DMARC is in monitoring mode. Move to -all once your record is verified, complete, and under the DNS-lookup limit — it is the only qualifier that gives non-DMARC receivers explicit permission to reject spoofs. And remember that the moment you reach DMARC p=reject, the debate is largely settled for you: DMARC, not the tilde or the dash, is what actually stops the forgery. The all qualifier is your first line; DMARC is the wall behind it.