SPF ~all vs -all: Softfail or Hardfail in 2026?

Published November 2, 2026 · 6 min read · spFlat! Blog

Every SPF record ends with an all mechanism, and the character in front of it is probably the most debated character in email authentication. Should your record end in ~all (softfail) or -all (hardfail)?

The short answer for 2026: if your domain sends email and you run DMARC, use ~all. If your domain never sends email, use -all. The longer answer explains why the stricter looking option is not automatically the safer one, and why neither matters if your SPF record is broken.


The four qualifiers at a glance

EndingSPF resultWhat it saysTypical receiver behavior
+allpassEvery server on the internet may send as youAccepts everything. Never use this.
?allneutralNo statement about unlisted serversTreated much like having no SPF policy
~allsoftfailUnlisted servers are probably not authorizedAccepts the message, may add spam weight, lets DKIM and DMARC decide
-allfailUnlisted servers are not authorizedMay reject during the SMTP conversation

The qualifier only applies to mail from servers that did not match anything earlier in the record. Mail from your listed ip4:, ip6: and include: sources gets pass, no matter how the record ends.

What softfail and hardfail mean on paper

RFC 7208 defines fail as an explicit statement that the sending host is not authorized to use the domain. softfail is a weaker statement: the host is probably not authorized, but the domain owner does not want to make a strong claim. Neither result tells a receiver exactly what to do. That is left to local policy, and receivers differ.

Without DMARC, that difference matters, because the qualifier is the only policy signal you send. With DMARC, the picture changes completely.

Why DMARC makes the qualifier matter less

DMARC does not care how SPF failed. It asks one question about SPF: did it pass, with a domain aligned to the From: header? Softfail, fail and neutral are all simply "not a pass".

So with DMARC at p=reject:

  • ~all with DMARC p=reject: spoofed mail is rejected.
  • -all with DMARC p=reject: spoofed mail is rejected.

The protection against spoofing is the same. Enforcement lives in your DMARC policy, not in the last four characters of your SPF record. (New to alignment? Read SPF vs DKIM vs DMARC first.)

The real risk of -all: rejection before DMARC runs

Some receivers check SPF as soon as the sending server issues MAIL FROM, before the message itself has arrived. If your record says -all and the sending IP is not listed, they can reject right there. DKIM is never verified and DMARC never runs.

The DMARC specification warns about exactly this. RFC 7489 (section 10.1) points out that a -all can cause rejection early in handling, before any DMARC processing takes place.

That hurts in the situations where DMARC would have saved the message:

  • Forwarding. A recipient forwards your mail from an old address, or a mailing list relays it. The forwarding server is not in your SPF record, so SPF fails. DKIM would still have passed and aligned, but the message was already bounced.
  • A sender nobody told you about. Marketing starts using a new platform that signs with DKIM but is not in your SPF record yet. With ~all, DMARC passes on DKIM. With -all, some receivers bounce it.
  • Stale IP lists. A provider adds sending ranges and your hand-flattened record does not include them yet.

This is why M3AAWG (the Messaging, Malware and Mobile Anti-Abuse Working Group) recommends ~all for domains that send email in its Email Authentication Recommended Best Practices.

Which one should you use?

Your situationRecommended ending
Domain sends email, DMARC at p=quarantine or p=reject~all
Domain sends email, DMARC at p=none or not set up yet~all, and make DMARC enforcement your next step
Changing providers and not sure you know every sender~all until your DMARC reports are clean
Domain never sends email (parked, brand protection)v=spf1 -all

For a domain that never sends email, lock it down completely:

example.com.         TXT  "v=spf1 -all"
_dmarc.example.com.  TXT  "v=DMARC1; p=reject"
example.com.         MX   0 .

The last line is a null MX (RFC 7505): the domain does not accept mail either. Here -all has no downside, because there is no legitimate mail to lose.

The upgrade path is not from ~all to -all. It is ~all, plus aligned DKIM for every sender, plus DMARC at p=reject. That combination blocks spoofing and still lets forwarded, DKIM signed mail through.

Neither one helps if SPF is broken

All of this assumes SPF actually gets evaluated. If your record needs more than 10 DNS lookups, the check stops with a PermError before it ever reaches all. Your carefully chosen qualifier is never read, and for DMARC the result is simply that SPF did not pass.

The same goes for two SPF records on one domain, a syntax error, or too many void lookups. Before you debate ~all versus -all, make sure the record works:

With spFlat! your record becomes one short spFlat! include. spFlat! suggests ending it with ~all, in line with the advice above, and keeps the IP list behind that include current. The record itself lives in your own DNS, so for a domain where you deliberately want -all, you can still change the ending yourself. Because the IP list stays current, the stale list problem that makes -all risky on hand-flattened records also goes away.

Before you change the qualifier

  1. Check that your SPF record evaluates without errors and stays under 10 lookups.
  2. Confirm every sending service signs with DKIM, aligned to your domain.
  3. Read your DMARC aggregate reports for a few weeks and look for legitimate sources that fail SPF.
  4. Move DMARC to p=quarantine, then to p=reject.
  5. Only then decide on the qualifier. For most sending domains, ~all stays.

Summary

  • ~all for domains that send email, -all for domains that never do.
  • With DMARC enforced, softfail and hardfail give the same protection against spoofing.
  • -all can cause rejection before DKIM and DMARC run, which breaks forwarded mail.
  • A PermError makes the whole question irrelevant. Fix the record first.

Check your SPF record first

Free, no signup. See your evaluated DNS lookup count (including nested includes) and whether a PermError occurs right now.

Check Your SPF
Or start your free 14-day trial →

Frequently asked questions

Should I use ~all or -all in my SPF record?

For a domain that sends email and has DMARC, use ~all (softfail) and enforce through DMARC at p=quarantine or p=reject. For a domain that never sends email, use v=spf1 -all together with a DMARC p=reject record. This matches the M3AAWG Email Authentication Recommended Best Practices.

Is -all more secure than ~all?

Not when DMARC is enforced. DMARC treats softfail and fail the same way (both are simply not a pass), so ~all with DMARC p=reject blocks spoofed mail just as well as -all. The difference is that -all can make some receivers reject mail before DKIM and DMARC are evaluated, which can bounce legitimate forwarded mail.

Does DMARC treat SPF softfail and hardfail differently?

No. DMARC only checks whether SPF passed with a domain aligned to the From: header. Softfail, fail and neutral all count as SPF not passing, and your DMARC policy decides what happens next.

Does the all qualifier matter if my SPF record has a PermError?

No. A PermError, for example from exceeding the 10 DNS lookup limit, stops SPF evaluation before the all mechanism is reached. The qualifier is never applied and DMARC sees SPF as not passing. Fix the PermError first.