Dr.Who
← blog

SPF ~all vs -all: use hardfail once you've listed every sender

· spf · dmarc · email · deliverability · dns

spfdmarcemaildeliverabilitydns

The all mechanism at the end of your SPF record sets the policy for any sender that didn't match an earlier rule. -all (hardfail) tells receivers to reject mail from servers not listed in your record; ~all (softfail) tells them to treat such mail as suspicious but usually accept it anyway. ?all is neutral (no opinion) and +all permits any server to send as you — effectively no protection. The right end state is -all, but only once you have enumerated every legitimate sending source; flip it too early and you start rejecting your own mail.

What each qualifier tells the receiver

The qualifier prefix on all is the catch-all verdict:

v=spf1 include:_spf.google.com -all   # hardfail: reject unlisted senders
v=spf1 include:_spf.google.com ~all   # softfail: accept but mark suspicious
v=spf1 include:_spf.google.com ?all   # neutral: no policy statement
v=spf1 include:_spf.google.com +all   # pass everything: do not use

A receiver evaluating an unlisted sender produces an SPF result accordingly: -all yields fail, ~all yields softfail, ?all yields neutral. With +all everyone passes, which defeats the purpose of publishing SPF at all.

When to use which

  • ~all (softfail) while you are still discovering senders. New domains, recent migrations, or any setup where you are not yet certain you've listed every marketing platform, ticketing system, CRM, and transactional provider should start here. Softfail rarely causes outright rejection, so a sender you forgot won't be silently dropped — it just gets flagged.
  • -all (hardfail) once your inventory is complete and verified. This is the protective end state: unlisted servers spoofing your domain get rejected. Reach it deliberately, after confirming nothing legitimate sends from outside the record.

The risk of -all too early is real: any legitimate sender missing from the record sends mail that receivers reject, and you may not notice until someone reports missing email. That's why softfail is the on-ramp, not the destination.

How this interacts with DMARC

SPF alone has a blind spot — it authenticates the envelope sender (the return-path), not the visible From: header a recipient reads. DMARC is what binds authentication back to the From: domain via alignment, and it gives you the safety net for tightening SPF. Deploy DMARC first, start at p=none so you receive aggregate reports, and read those reports to discover every server sending as you. Once the reports show only sources you recognize, you can confidently move SPF to -all and raise DMARC to enforcement.

spf=fail smtp.mailfrom=evil.example   # -all rejected the unlisted sender
dmarc=fail (p=reject) header.from=example.com

Note the SPF void lookup and 10-DNS-lookup limits still apply regardless of the qualifier: if your record exceeds 10 lookups it returns permerror and the all policy never gets evaluated. Keep the record lean and verify it resolves cleanly before relying on -all.

Check your SPF record →

Further reading