DMARC Engine
Home/Blog/SPF ~all vs -all vs ?all
Blog

SPF ~all vs -all vs ?all

Soft fail, hard fail, neutral and pass-all: what each SPF qualifier on the all mechanism actually instructs receivers to do, how DMARC changes the picture, and which one to publish at each stage of your rollout.

16 May 2026 · 11 min read

SPF ~all vs -all vs ?all

SPF ~all vs -all vs ?all: which qualifier should you use?

Every SPF record ends with an all mechanism, and the single character in front of it is one of the most consequential decisions in your whole email-authentication setup. That character tells receiving mail servers what to do with a message that arrives from an IP address your SPF record does not list. Get it right and unauthorised senders are visibly rejected or quarantined. Get it wrong and you either leave the door open to spoofers or, worse, you can break a future DMARC rollout in ways that are surprisingly hard to diagnose.

The four qualifiers are + (pass), - (fail, usually called hard fail), ~ (softfail) and ? (neutral). In an SPF record they appear as +all, -all, ~all and ?all. The names sound interchangeable to anyone who has not lived with them, but they mean genuinely different things, and the differences matter a great deal once you put DMARC in front of them.

This article explains exactly what each qualifier instructs a receiver to do, how that instruction changes once DMARC is involved, and which one you should actually publish. We will work through concrete record examples, the common mistakes, and a clear recommendation for the steady state. If you want to see what your own domain publishes right now while you read, the free SPF checker will show you the parsed record and flag the qualifier you are using.

What the all mechanism actually does

SPF, the Sender Policy Framework, is a list of who is allowed to send mail using your domain in the envelope. A receiving server takes the envelope sender (the MAIL FROM address, also called the return-path), looks up the SPF record for that domain, and checks whether the connecting IP address is authorised by one of the mechanisms in the record.

SPF evaluates mechanisms from left to right and stops at the first match. A typical record looks like this:

v=spf1 include:_spf.google.com include:sendgrid.net ip4:198.51.100.7 -all

If the connecting IP is inside Google's published ranges, the include:_spf.google.com mechanism matches and evaluation stops with a pass. If it is one of SendGrid's, the second include matches. If it is literally 198.51.100.7, the ip4 mechanism matches. The all mechanism at the end is a catch-all: it matches every IP address that did not match anything earlier. So all is what decides the result for every sender you have not explicitly authorised.

The qualifier in front of all sets that result. -all means "everything else fails". ~all means "everything else softfails". ?all means "everything else is neutral". +all means "everything else passes", which is almost never what anyone wants.

That last point is worth stressing before we go further: the qualifier on all does not change what happens to your legitimate senders, because they match an earlier mechanism and never reach all. It only governs the verdict for senders that fall through, which in practice means spoofers, misconfigured services, and any legitimate sender you forgot to add.

-all: hard fail

-all is the strict setting. It tells receivers that any IP not listed in your SPF record is not authorised, full stop, and the result of the SPF check should be fail.

The record looks like this:

v=spf1 include:_spf.google.com -all

The intent is unambiguous: only Google's servers may send mail with this domain in the envelope, and a receiver is entitled to reject anything else outright. Many receivers historically did exactly that, bouncing the message at the SMTP level before it ever reached a mailbox.

-all is the qualifier you want to arrive at, because it is the only one that makes a clear, enforceable statement. A neutral or softfail record effectively says "I am not sure", and that uncertainty is exactly what attackers exploit and what receivers treat leniently.

The reason people hesitate over -all is the historical fear that a forgotten sender will be hard-bounced. That fear was well-founded a decade ago when SPF stood alone. It is far less of an issue today, for two reasons. First, the well-known forwarding problem (more on that below) means most large receivers no longer reject on SPF hard fail alone. Second, and more importantly, DMARC has changed how SPF results are interpreted entirely, which is the part most guides skip over.

~all: softfail

~all is the cautious middle option. It tells receivers that a non-listed IP is probably not authorised, but the receiver should not reject the message on that basis. Instead, the message should be accepted and marked, typically treated as a weak negative signal that might nudge it toward the spam folder.

v=spf1 include:_spf.google.com ~all

Softfail exists precisely for the migration period. When you first publish SPF, you are rarely certain you have listed every sender. Newsletters, invoicing platforms, helpdesk software, CRM tools and the office printer all send mail, and it is easy to miss one. ~all lets you publish a record and start observing without the risk that a forgotten sender gets hard-bounced. A softfailing message still gets delivered; it just carries a faint mark against it.

The downside is that softfail, on its own, provides almost no protection against spoofing. A receiver that honours ~all literally will still deliver the forged message, perhaps with a slightly higher spam score. An attacker forging your domain does not much care whether their phishing email lands in the inbox or the spam folder of a target who is going to be fooled anyway. So ~all as a permanent setting is a half-measure: safe for you, but soft on the people abusing your domain.

?all: neutral

?all is the "no opinion" setting. It explicitly tells receivers that you make no assertion at all about whether a non-listed IP is authorised. The SPF result is neutral, which receivers are expected to treat exactly as if you had no SPF policy for those senders.

v=spf1 include:_spf.google.com ?all

In practice ?all is barely distinguishable from publishing no all mechanism, or from having no useful SPF policy at all. It offers no protection and sends no signal. The only legitimate use we see for it is a very early, very cautious testing phase, or an unusual delegation scenario where one record defers entirely to another. For almost everyone, ?all is a record that looks like it does something while doing nothing.

If your domain currently publishes ?all, treat that as a finding to fix, not a stable configuration. Run it through the SPF checker and you will see it parsed out plainly.

+all: pass everyone (do not do this)

+all tells receivers that every IP address on the internet is authorised to send mail as your domain. It is the SPF equivalent of leaving your front door wide open with a sign inviting people in.

v=spf1 include:_spf.google.com +all

There is essentially no legitimate reason to publish +all. It defeats the entire purpose of SPF, authorising the whole world to pass your check. When we see +all in the wild it is almost always a mistake: someone copied a record, or assumed + meant "include my real senders too". If you find +all on a domain, fix it immediately. It actively undermines any DMARC policy you layer on top, because SPF will now report pass for forged mail from arbitrary IPs.

The crucial part: how all interacts with DMARC

This is where most explanations stop too early, and where the right answer actually lives. The behaviour of ~all versus -all changes substantially once you publish a DMARC record, because DMARC overrides the receiver's freedom to act on the raw SPF result.

Without DMARC, the receiver decides for itself what to do with an SPF fail or softfail. With DMARC, the receiver's action is governed by your DMARC policy (p=none, p=quarantine or p=reject), not by the SPF qualifier. And DMARC does not even look at the raw SPF verdict in isolation. It cares about two things together: did SPF pass, and did it pass for a domain that aligns with the visible From address? That second requirement is alignment, which we cover in depth in DMARC alignment explained.

Here is the key consequence. Under DMARC, the distinction between SPF fail (-all) and SPF softfail (~all) very largely disappears. DMARC treats both as "SPF did not produce an aligned pass". A message that softfails and a message that hard-fails are, from DMARC's perspective, both simply messages without SPF authentication. What then determines the outcome is whether DKIM provides an aligned pass instead, and if neither does, your DMARC policy decides the fate of the message.

In other words: once DMARC is in place and enforcing, ~all and -all produce almost the same end result for spoofed mail, because DMARC, not SPF, is doing the enforcing. The forged message fails DMARC either way and is quarantined or rejected according to your p= value.

So why prefer -all at all under DMARC? Three reasons:

  1. Clarity of intent. -all states honestly that non-listed senders are unauthorised. ~all hedges. There is no reason to hedge once DMARC is your real enforcement layer.
  2. Defence in depth for receivers that weight SPF. Some receivers, and some non-DMARC processing paths, still factor the raw SPF result into spam scoring. A genuine fail is a stronger negative signal against a spoofer than a softfail.
  3. Cleaner reporting. Your DMARC aggregate reports, which you can read with the DMARC report analyzer, distinguish SPF pass from fail. A hard -all makes the data crisper about which sources are genuinely unauthorised.

The forwarding problem, and why DMARC fixes it

The original argument for ~all over -all was email forwarding. When someone forwards your message, say a user who set up a redirect from an old address, the forwarding server connects from an IP that is not in your SPF record. SPF then fails for the forwarded copy, even though the message is perfectly legitimate. With a strict -all and a receiver that rejects on SPF fail, that legitimate forwarded mail could be bounced.

This is real, and it is why ~all felt safer for years. But notice what DMARC does here. DMARC will not reject a forwarded message if DKIM still verifies, because DKIM survives forwarding. The DKIM signature travels with the message body and headers, so a forwarded message that fails SPF can still produce an aligned DKIM pass and therefore pass DMARC. This is one of the main reasons DKIM matters so much, and why you should never rely on SPF alone. We go deeper on this in the DKIM product overview and the broader SPF product page.

The practical takeaway: if your mail is properly DKIM-signed and aligned, the forwarding scenario that made people fear -all is handled by DMARC-plus-DKIM, not by softening your SPF. That removes the last real objection to -all for most domains.

A safe migration path for the all qualifier

You do not have to jump straight to -all on day one. The sensible sequence mirrors the wider DMARC rollout, moving from observation to enforcement as your confidence grows. Here is the path we recommend:

  1. Publish SPF with ~all first. When you are still discovering your senders, softfail lets you list what you know without risking hard bounces for anything you missed. Use the SPF checker to confirm the record is valid and within the ten-lookup limit.
  2. Turn on DMARC at p=none with aggregate reporting. This costs nothing in deliverability and starts the flow of data showing every IP sending as your domain, both legitimate and not.
  3. Use the reports to complete your sender list. Read the aggregate data (the report analyzer makes the XML legible) and add any legitimate sources you find missing from SPF, ideally also getting them DKIM-signed.
  4. Once your senders are all accounted for, tighten SPF to -all. At this point a non-listed IP genuinely should fail, and you want it to.
  5. Advance DMARC to p=quarantine and then p=reject. With -all in place and DKIM aligned, your authentication story is complete and enforcing.

This is exactly the progression that takes a domain safely from no protection to full enforcement, and it is the spine of the DMARC service if you would rather not manage each step by hand.

Common mistakes with the all qualifier

A few recurring errors are worth calling out specifically:

  • Two all mechanisms in one record. Only the first one counts, because SPF stops at the first match. A record like v=spf1 ... ~all include:extra.net -all will never reach the second all, and the include after the first all is dead. Keep exactly one all, always at the very end.
  • Leaving ?all or no all in place long term. Neutral records provide no protection and confuse receivers and reporting alike. Decide on ~all for migration or -all for steady state.
  • Believing -all alone stops spoofing. It does not, without DMARC. SPF protects the envelope sender, not the visible From address that users actually see. Spoofers simply use a different envelope domain and a forged From. Only DMARC ties authentication back to the visible From. This is the single most common misunderstanding, and we unpack it in DMARC alignment explained.
  • Reaching the ten-lookup limit while chasing -all. Adding more include mechanisms to authorise every sender can push you past SPF's limit of ten DNS lookups, which causes a permerror and effectively breaks SPF. If you are bumping against that ceiling, read how SPF flattening works and consider the automated approach in the SPF product.
  • Softening SPF instead of fixing alignment. If forwarded or third-party mail is failing, the fix is aligned DKIM signing, not weakening all. Diagnose with the DKIM checker.

So which qualifier should you use?

The short, honest answer:

  • Use ~all while you are still discovering and listing your senders, and during the early p=none monitoring phase. It is the safe migration setting.
  • Use -all as your destination, once you are confident every legitimate sender is in your SPF record (and ideally DKIM-signed and aligned). Under DMARC, -all is the clear, correct steady state and carries essentially no extra risk of breaking legitimate mail, because DMARC and DKIM handle the edge cases.
  • Never use ?all as a long-term setting; it asserts nothing.
  • Never use +all; it authorises the entire internet to spoof you.

If there is one idea to carry away, it is that the all qualifier is not your enforcement mechanism once DMARC exists. SPF tells receivers who is allowed to send; DMARC, tied to the visible From through alignment, is what actually decides whether forged mail is rejected. Choose ~all to migrate safely, move to -all for the steady state, and let DMARC at p=reject do the real enforcing.

To see exactly what your domain publishes today, what the all qualifier is doing, and whether you are inside the lookup limit, run the free SPF checker or explore the full set of diagnostic tools. And if you would rather have the whole journey from ~all and p=none to -all and p=reject handled for you with no email outage, that is precisely what DMARC Engine's done-for-you service is built to do.

Share

See where your domain stands today

Run a free DMARC scan, then let us take you to enforced p=reject with no email outage.