EmailAudit.io
All articles
Email Authentication9 min read·EmailAudit.io Security Team

SPF Hard Fail vs Soft Fail

SPF -all vs ~all: what hard fail and soft fail do, how DMARC changes the decision, and which to publish. Includes a decision guide and rollout steps.

The short answer: -all (hard fail) says mail from unlisted servers is not authorised; ~all (soft fail) says it is probably not authorised, so accept it but treat it with suspicion. If your sender list is complete, use -all. If you enforce DMARC with p=quarantine or p=reject, the difference matters far less, and ~all is a common, defensible choice. Never use +all.

The last term in an SPF record, the all mechanism with its qualifier, is the part most people copy from a template without thinking about it. It is also the part where well-meaning caution (~all, "just in case") collides with the idea that stricter is always better (-all).

This guide explains what each qualifier means in the specification, how real receivers behave, how DMARC changes the picture, and gives a decision guide you can apply to your own domain. For the full syntax of everything that comes before all, see the SPF record syntax guide.


The Four Qualifiers

Every SPF mechanism can carry a qualifier prefix. For all there are four, defined in RFC 7208:

Record ending Qualifier SPF result What the RFC says receivers should do
-all Fail fail May reject at SMTP time (RFC 7208, section 8.4)
~all SoftFail softfail Accept, but mark the message (section 8.5)
?all Neutral neutral Treat as if no assertion was made
+all Pass pass Everyone is authorised

If a record has no all and no redirect=, the default result when nothing matches is neutral. A missing all therefore behaves like ?all.

Anything written after all is ignored, because evaluation stops there. A record such as v=spf1 -all include:_spf.google.com never reaches the include.


What -all Does in Practice

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

When the connecting IP matches nothing in the record, the result is fail. The RFC allows the receiver to reject the message during the SMTP conversation. What actually happens is up to the receiver's local policy:

  • Some mail servers reject outright with a 550 response citing SPF.
  • Many modern receivers do not reject on SPF alone. They record the result and feed it into spam scoring or DMARC evaluation.

A header from a message that failed against -all might read:

Authentication-Results: mx.example.net;
  spf=fail (example.net: domain of bounce@yourdomain.com does not designate
  198.51.100.77 as permitted sender) smtp.mailfrom=bounce@yourdomain.com

-all only affects mail from servers you have not listed. If your sender list is complete, nothing legitimate is hit. If it is incomplete, -all is what makes the omission visible, which is useful during testing but painful in production.


What ~all Does in Practice

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

The result is softfail: "we think this is not authorised, but we are not asserting it". Receivers typically deliver the message and give it a worse spam score. Many vendor setup guides show ~all in their examples, which is one reason it is so common.

The common misconception is that ~all is "safe" and -all is "risky". The risk lies in an incomplete record, not in the qualifier. A forgotten sender fails under either one; under ~all it just fails more quietly.

There is one legitimate reason to prefer softfail permanently: forwarding. When someone forwards your message from their own server, the forwarding server's IP is not in your record, so SPF fails or softfails even though the message is genuine. A strict -all makes those messages look worse to receivers that weigh SPF. (Proper handling of forwarding is what ARC and DKIM are for.)


Why +all and ?all Are Wrong for Production

+all authorises the entire internet:

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

Every server passes SPF for your domain, which is worse than having no record, because it advertises that you have put a policy in place and that policy allows everyone. If you find this in your DNS, change it now. Scanners flag it, and so do receivers.

?all and the missing-all case say nothing about unlisted senders. They are only reasonable for a domain that is being tested or a domain that is not sending mail at all, and for a non-sending domain the right record is stronger:

v=spf1 -all

How DMARC Changes the Decision

SPF on its own is a verdict about the connecting IP. DMARC adds a second question: does the domain SPF validated (the envelope sender, or Return-Path) match the domain in the visible From header? That match is called alignment.

Under DMARC, a message passes if either SPF or DKIM both passes and aligns. Your published DMARC policy (p=none, p=quarantine or p=reject) then tells the receiver what to do with a message that fails both. (See DMARC policy levels.)

Two things follow:

  1. Once a receiver evaluates DMARC, the SPF qualifier is largely superseded by the DMARC policy. RFC 7489 itself advises receivers that apply DMARC to rely on the DMARC policy rather than rejecting solely on an SPF -all, so that a domain owner's DMARC decision is honoured. Microsoft also documents that for DMARC purposes it does not distinguish between SPF hard fail and soft fail. Verify current behaviour with each receiver you care about.
  2. A -all record does not protect you the way p=reject does. A spoofer who fails SPF may still be delivered by a receiver that treats -all as a spam signal only, while p=reject is a clear instruction from you.

The practical result is that the strength of your all qualifier is a weak lever once DMARC is enforcing, and a stronger lever when DMARC is missing or at p=none, where SPF is the main signal you are giving. Setting DMARC up properly is worth more than debating -all versus ~all.

Your situation SPF all choice Why
No DMARC record -all once list is complete SPF is your only signal to receivers
DMARC p=none (monitoring) ~all while you discover senders, then -all Avoids hard-failing senders you haven't found yet
DMARC p=quarantine or p=reject Either; -all is conventional, ~all is acceptable DMARC does the enforcing
Domain that never sends mail -all with v=spf1 -all Nothing legitimate to protect
Heavy forwarding (alumni, mailing lists) ~all is reasonable Reduces forwarded-mail penalties

Reading the Result in a Real Header

When you test a change, look at the Authentication-Results header on the received copy. A message sent through an authorised provider under an enforcing record looks like this:

Authentication-Results: mx.example.net;
  spf=pass smtp.mailfrom=yourdomain.com;
  dkim=pass header.d=yourdomain.com;
  dmarc=pass (p=REJECT) header.from=yourdomain.com

Check three things: smtp.mailfrom shows which domain SPF actually validated, header.d shows which domain signed with DKIM, and header.from is the domain your recipient sees. If smtp.mailfrom is a vendor's domain, SPF can pass while still not aligning with your From address, which is why -all on your own record changes nothing for that vendor's mail.


A Decision Guide

Use -all when all of these are true:

  • Every legitimate sender is listed (check DMARC aggregate reports for 2-4 weeks first)
  • You have DKIM set up for every third-party sender, so mail still passes DMARC if SPF fails
  • You can tolerate a small risk of forwarded mail looking worse

Use ~all when any of these are true:

  • You are still in the discovery phase with DMARC at p=none
  • You have recently changed providers and want a safety net
  • You rely on SPF for mail that is routinely forwarded

Never use +all. Treat ?all and a missing all as unfinished work.


Moving From ~all to -all Safely

  1. Enable DMARC reporting with p=none and an rua address. The DMARC generator builds the record.
  2. Inventory your senders from the reports. Look for sources failing SPF that you recognise (a billing system, a forgotten CRM). Add them via the third-party senders guide.
  3. Check the lookup count. Adding senders can push you past the limit; see SPF too many DNS lookups.
  4. Confirm DKIM is signing for every sender with your domain.
  5. Change ~all to -all in the single SPF TXT record at the root of the domain.
  6. Watch the reports for a week or two for new SPF failures from legitimate sources.
  7. Raise DMARC towards quarantine and then reject when the reports are clean.

You can verify the published result at any point with the SPF checker, or regenerate a clean record with the SPF generator.


Common Mistakes

  • Two SPF records. Publishing a second TXT record starting v=spf1 makes the result permerror. Merge them into one.
  • Putting all in the middle. Everything after it is ignored.
  • Using -all before the sender list is complete. Legitimate mail from unlisted systems starts failing.
  • Treating SPF as sufficient. SPF does not survive forwarding and does not cover the visible From address on its own. Pair it with DKIM and DMARC.
  • Forgetting subdomains. Subdomains that send mail need their own SPF record, and non-sending subdomains benefit from v=spf1 -all.

Frequently Asked Questions

Is -all or ~all better?

For a domain with a complete sender list, -all is the stronger and more conventional statement. If DMARC is enforcing, either works in practice because the DMARC policy decides the outcome. The wrong choice is not between the two; it is publishing an incomplete record under either.

Will -all cause my emails to bounce?

Only mail sent from servers missing from your record. Send from a listed provider and SPF passes. Bounces on legitimate mail mean a sender is missing from the record or the lookup limit is exceeded.

Does Gmail treat ~all and -all differently?

Receivers weigh SPF results inside much larger spam models and do not publish the exact weights. Treat both as negative signals, and rely on DKIM and DMARC alignment, which are the parts you can fully control.

Should I use -all if I use DMARC p=reject?

It is conventional and does no harm provided your sender list is correct. The DMARC policy is the control that actually blocks spoofed mail, so do not delay enforcing DMARC while debating the qualifier.

What does SPF softfail mean in email headers?

spf=softfail means the sending IP was not in your record and the record ends with ~all. It is a warning, not a rejection. Look at the DKIM and DMARC results in the same header before drawing conclusions; the email header analyzer lays them out.


Next Step

Check which qualifier your domain publishes today with the SPF checker, or run a free email audit to see SPF, DKIM and DMARC together. If you want enforcement rolled out without breaking legitimate mail, the email security setup service handles it end to end.

Is your domain protected?

Run a free Full Audit — check SPF, DKIM, DMARC, blacklists, and MTA-STS in seconds. Get a branded PDF report delivered to your inbox. No account required.