SPF ~all vs -all: Which Enforcement Rule Should You Use?

The short answer
Use ~all (softfail) while you are still finding every service that sends as your domain; unauthorized mail is accepted but marked. Switch to -all (hardfail), which tells receivers to reject unauthorized mail, once all senders are listed and DKIM and a DMARC policy are live. -all is the stronger end state.
SPF ~all vs -all: softfail marks unauthorized mail, hardfail rejects it. Start with ~all, switch to -all once every sender, DKIM and DMARC are in place.
On this page
- 01The short version
- 02~all vs -all at a glance
- 03All four qualifiers, in one place
- 04Where ~all (softfail) wins
- 05Where -all (hardfail) wins
- 06How to switch to -all without blackholing mail
- 07What each costs, and where to verify
- 08Who should use each
- 09?all, +all, and the option that actually matters
- 10Where AI Emaily fits
Your SPF record ends in one of two enforcement rules, and the choice between SPF ~all and -all decides what a receiver does with mail that claims to be your domain but is not on your authorized list. ~all is a softfail: the message is accepted but marked. -all is a hardfail: the message is treated as unauthorized and is usually rejected.
This is a decision, not a definition. The short answer sits below, and the sequencing that makes the stronger rule safe to turn on is the rest of the post.
SPF is defined in RFC 7208, and the qualifier on `all` is a specific part of that specification's mechanism syntax. When a receiving mail server evaluates your record, it works through each mechanism left to right — `ip4`, `ip6`, `include`, `a`, `mx`, and any others. Each mechanism is tested against the IP address that actually connected and delivered the message: the connecting MTA's IP, not any address written in the message headers. The first mechanism whose condition the connecting IP satisfies terminates evaluation immediately and returns that mechanism's result, combined with its qualifier. If no earlier mechanism matches, the `all` mechanism always matches because it carries no IP condition. The qualifier on `all` — whether ~ or - — is therefore the result returned for every sender not already covered by an explicit mechanism earlier in the record.
The short version#
Use ~all while you are still finding every service that sends mail as your domain. Softfail will not blackhole a legitimate sender you forgot to list — the mail still arrives, just flagged. That protects you from your own incomplete record.
Switch to -all once three things are true: every legitimate sender is in the record, DKIM is signing your mail, and a DMARC policy is published. At that point hardfail is the correct end state, and there is no good reason to stay on softfail.
The reason softfail was designed at all is that RFC 7208 section 8.5 explicitly anticipated incomplete records. The authors knew organizations would add mechanisms piecemeal and needed a way to say 'probably not authorized' without causing collateral damage to forgotten legitimate senders. Softfail is that middle ground: it carries enough information for a spam filter to score and route the message, without giving the receiving server a mandate to reject it outright. Hardfail removes that hedge — and can only be deployed responsibly once the record is complete enough that the hedge is no longer needed.
- Still building your sender list, no DKIM or DMARC yet: keep ~all.
- Every sender listed, DKIM signing, DMARC live and clean: move to -all.
- A parked domain that sends no mail at all: publish v=spf1 -all today.
- Never use +all (it authorizes the whole internet) or ?all in production (RFC 7208 says treat it exactly like no record).
~all vs -all at a glance#
The two rules differ only in what they instruct a receiver to do with unauthorized mail. Everything else about the record — the includes, the IP ranges, the DNS-lookup limit — is identical.
| Dimension | ~all (softfail) | -all (hardfail) |
|---|---|---|
| SPF result returned | softfail | fail |
| What receivers should do | Accept but mark — often Junk or quarantine | Treat as unauthorized; many reject, often with 550 5.7.1 |
| RFC 7208 guidance | SHOULD NOT reject on this result alone (section 8.5) | May reject; final disposition is the receiver's local policy (section 8.4) |
| Risk if a real sender is missing | Low — mail is still delivered, just flagged | High — legitimate mail can be rejected |
| Signal to receivers | Weaker, hedged | Stronger, unambiguous |
| Best stage | During rollout and discovery | End state, with DKIM and DMARC |
All four qualifiers, in one place#
The two you actually choose between are ~all and -all. The other two exist in the syntax but are traps in production. Here is the full set, straight from RFC 7208 section 4.6.2. Note that the qualifier is optional and defaults to +, so a mechanism written with no sign is a pass.
The qualifier character is optional, and when none is written the default is `+`, which means pass. This makes `include:_spf.google.com` and `+include:_spf.google.com` identical — both return a pass result if the sender's IP is listed inside Google's SPF record. It is also why `+all` is not just unusual but actively dangerous: it is shorthand for 'every IP on the internet passes SPF for my domain,' which means any sender can impersonate you without SPF ever raising an objection. The absence of a qualifier is invisible in the record, so read the first character of each mechanism carefully when auditing an existing SPF entry.
Evaluation terminates on the first match. Any mechanism listed after `all` is unreachable — a receiver that has already matched on `all` stops processing and will never test a later mechanism. Some providers' setup guides still include mechanisms after `all` due to old documentation errors; those trailing mechanisms are silently ignored by every compliant resolver. The correct position for `all` is always last in the record, and if two `all` mechanisms appear the first one wins.

| Qualifier | Name | SPF result | What it tells a receiver |
|---|---|---|---|
| -all | Fail (hardfail) | fail | Not authorized — reject or discard |
| ~all | Softfail | softfail | Probably not authorized — accept but mark |
| ?all | Neutral | neutral | No assertion — treat exactly like no SPF record |
| +all | Pass | pass | Authorizes every sender on the internet — never use |
Where ~all (softfail) wins#
Softfail wins whenever a wrong answer would reject real mail. Most organizations cannot list every sending source on day one — a marketing platform, the CRM, the help desk, invoicing software, an on-premises relay and a handful of SaaS tools all send as the domain, and some are easy to miss.
With ~all, a source you forgot still gets its mail delivered; the receiver marks it rather than dropping it. You learn about the gap from a DMARC report or a spam-folder complaint, not from a bounce and an angry customer. That makes softfail the safe default while you are still building the record.
What 'marked' means in practice depends on the receiving server's local policy, but the trace is always visible in the headers. A receiving MTA adds a `Received-SPF` header to every message it evaluates. For a softfail, that header reads something like: `Received-SPF: softfail (domain of yourdomain.com does not designate 203.0.113.42 as permitted sender) client-ip=203.0.113.42`. Most spam-filter pipelines treat softfail as a mild negative signal — adding points toward the spam threshold without triggering an outright block. A sender you forgot still delivers to Junk rather than disappearing into a permanent bounce, and the header gives you a precise record of which IP triggered the result. That diagnostic value disappears the moment you switch to hardfail prematurely and a legitimate source starts bouncing at SMTP.
- You have not yet inventoried every sender.
- DKIM and a DMARC policy are not in place yet.
- You run a large or federated org where sources are hard to enumerate.
- You are mid-migration between mail providers.
Where -all (hardfail) wins#
Hardfail wins once your record is complete. -all tells every receiver that anything not on your list is unauthorized, which is the strongest instruction SPF can give. Microsoft recommends -all for Microsoft 365 domains for exactly this reason, provided DKIM and DMARC are set up alongside it.
For a domain that sends no mail at all — a parked or brand-protection domain — v=spf1 -all is correct immediately, with no rollout, because there is no legitimate mail to protect. Microsoft documents this same value for parked domains.
When a receiver encounters a hardfail, many MTAs issue a 550 5.7.1 rejection at SMTP time, before the message body is even transmitted. The exact rejection text varies by provider: Gmail returns `550-5.7.26 This message does not have authentication information`, while Microsoft Defender's SPF enforcement returns `550 5.7.23`. RFC 7208 section 8.4 explicitly leaves final disposition to the receiver's local policy — the specification says receivers 'MAY' reject, not 'MUST.' Some large consumer mailboxes run their own sender-reputation classifiers and will accept a hardfail message, routing it based on IP history and engagement signals rather than the SPF result alone. The practical effect of -all is therefore not a guaranteed rejection at every provider, but the strongest signal SPF can send. Publishing it communicates unambiguously that you know exactly who sends as your domain and that everything else is unauthorized.
SPF checks the envelope, not the From you read
How to switch to -all without blackholing mail#
-all earns its scary reputation when people flip it before their record is complete and reject their own mail. The sequence below removes that risk. Do not skip to the last step.
The DMARC aggregate report is your readiness signal. Each report arrives as XML at the `rua` address in your DMARC record, typically within 24 hours of each reporting period from receivers like Google and Microsoft. Inside, each `<record>` element identifies a source IP or IP range, shows the domain checked, and includes a `<policy_evaluated>` block with three fields: `disposition`, `dkim`, and `spf`. Look for rows where `spf` shows `fail` and `disposition` shows `none` — those are real sources currently spared because your DMARC policy is in monitoring mode. Any legitimate sender in that group will face rejection once you harden to -all and raise the DMARC policy to quarantine or reject. A clean report — no real senders in the `spf fail` rows — means the record is ready to lock down.
- 1
Inventory every sender
List every service that sends as your domain — ESP, CRM, help desk, invoicing, an on-premises relay, each SaaS tool. Missing one is the whole risk.
- 2
Add them to the record
Put each source in your SPF record. Stay under 10 DNS lookups — `include:`, `a`, `mx`, `exists`, and `ptr` each cost one lookup, and every nested `include` inside a third-party record adds to your total. RFC 7208 section 4.6.4 defines the 10-lookup hard limit; exceeding it produces a `permerror` result that DMARC treats as an SPF failure. If you are near the limit, replace some `include:` mechanisms with explicit `ip4:` or `ip6:` ranges for senders whose IP ranges you can lock down. Move secondary senders — transactional mail, help-desk tools, invoicing software — onto sending subdomains so they carry their own SPF budget and do not spend your primary domain's 10-lookup allowance.
- 3
Turn on DKIM everywhere
Enable DKIM signing for every sending source so a message can still authenticate even when its SPF path does not match.
- 4
Publish DMARC at p=none
Start DMARC in monitoring mode and read the aggregate reports. Confirm every legitimate source passes SPF or DKIM with alignment.
- 5
Keep ~all until the reports are clean
Stay on softfail while any real sender still fails. The reports tell you when you have finished discovering, not a calendar.
- 6
Switch to -all, then tighten DMARC
Change the qualifier to -all, then raise the DMARC policy from none to quarantine to reject.
DMARC treats both as failures — with a catch
What each costs, and where to verify#
Neither qualifier costs anything. An SPF record is a single DNS TXT entry, and changing ~all to -all is a one-line edit at your DNS host. The real cost is a wrong choice: -all too early rejects real mail, while ~all forever leaves a weaker signal in place than your domain deserves.
Recommended values differ by provider, and they change, so verify against your sender's own current documentation before you publish. Microsoft recommends -all for Microsoft 365; some SaaS setup guides still print ~all in their examples. Treat any value you copy from a blog — including this one — as something to confirm on the vendor's live page.
Before publishing any change, test with a tool that actually resolves the full DNS chain rather than just parsing the record string. Running `dig TXT yourdomain.com` (or `nslookup -type=TXT yourdomain.com` on Windows) shows the raw record as resolvers see it. MXToolbox's SPF Lookup and Google Admin Toolbox's Check MX both follow the include chain and count lookups, catching a `permerror` before receivers do. After publishing, allow for TTL propagation — most DNS providers set TTLs between 300 and 3,600 seconds. Verify from a second resolver such as `dig TXT yourdomain.com @1.1.1.1` to confirm the change has propagated past your own resolver's cache. Do not assume a change is live because your local lookup returned the new value.
Who should use each#
| Choose | If you are… |
|---|---|
| ~all (softfail) | Still inventorying senders, or without DKIM and DMARC yet |
| ~all, then -all | Rolling out authentication and following the sequence above |
| -all (hardfail) | Confident every sender is listed, with DKIM and DMARC clean |
| -all immediately | A parked or non-sending domain — publish v=spf1 -all |
| Neither ?all nor +all | Anyone in production — these give no protection |
?all, +all, and the option that actually matters#
?all is the neutral qualifier. RFC 7208 section 8.2 says a neutral result must be treated exactly like the none result — that is, as if you published no SPF record at all, so ?all provides no protection. It exists for testing a brand-new record, not for production.
+all is worse. It authorizes every sender on the internet to use your domain, which effectively turns SPF off. There is no legitimate production use for it.
There is one additional edge case worth knowing: if a record has no `all` mechanism at all, RFC 7208 section 4.7 specifies that the implicit result is neutral — the same result `?all` returns explicitly. In that state, the domain is neither permitting nor denying any sender, and receivers must treat it exactly as if no SPF record were published. Some administrators testing a brand-new domain before adding their first mechanism omit `all` entirely rather than writing `?all`; both produce the same neutral outcome. Replace either form with `~all` as soon as any real mechanism is added, and do not leave neutral semantics on a production domain once mail is flowing.
The option that actually matters is not a fourth qualifier — it is DMARC. SPF's -all hardens the envelope, but the address a person reads is protected by DMARC alignment, not by the SPF qualifier alone. Get to -all, then publish and enforce a DMARC policy. Do not stop at the qualifier.
Never ship ?all or +all to production
Where AI Emaily fits#
To be clear about where we sit: AI Emaily is the AI email client we build, and it is not an SPF or DMARC tool. It does not publish your DNS records, choose your enforcement rule, or generate the aggregate reports that tell you when -all is safe. That work belongs to your DNS host and a dedicated DMARC reporting service. If you came here to configure your sending domain, finish the sequence above with those tools — this page solves that whether or not you ever sign up.
Where AI Emaily meets this topic is the receiving side. Its spam and phishing defense reads SPF, DKIM and DMARC results as signals when it decides what reaches your inbox and what gets held back. That is the flip side of the choice in this post: when a sender publishes -all alongside DKIM and a DMARC policy, every receiver — AI Emaily included — has a cleaner basis to trust that mail, and a cleaner basis to distrust a spoof that fails all three.
So the honest fit is narrow and real: we do not set your enforcement rule, but we act on everyone else's. We build AI Emaily. It runs on a 7-day free trial of its paid plans (Pro or Autopilot), with a card required and no charge if you cancel before day seven — there is no permanent free tier.
Frequently asked
See it in AI Emaily
Keep reading
Sources

Written by
Nafiul HasanNafiul Hasan is an entrepreneur and AI automation system builder with 10+ years of experience turning messy, manual workflows into reliable automated systems. He designs and ships AI enterprise solutions end-to-end — the agent logic, the data plumbing, and the product people actually use — and founded AI Emaily to give busy professionals their attention back. He writes here from the builder's seat: what works, what breaks, and how to put AI to work without giving up control.