SPF Qualifiers Explained: The Four RFC 7208 Section 4.6.2 Qualifiers (+ Pass, - Fail, ~ SoftFail, ? Neutral) with a Receiver-Side Interpretation Matrix
A focused per-qualifier dimensional analysis of the four SPF qualifiers defined by RFC 7208 section 4.6.2: + (Pass, the default qualifier producing spf=pass when a sender matches), - (Fail, producing spf=fail with optional SMTP rejection per §4.7), ~ (SoftFail, producing spf=softfail as a weak unauthorised signal), and ? (Neutral, producing spf=neutral equivalent to no SPF record). Each qualifier is presented with the canonical Definition / Syntax / Receiver behaviour / When to use / When NOT to use / Common pitfalls structure, plus a side-by-side comparison table, a receiver-side interpretation matrix showing how Gmail / Microsoft 365 / Yahoo / Apple iCloud actually treat each result code, four worked deployment examples covering production / deployment monitoring / null-sender / vendor deprecation scenarios, and the seven most common qualifier-choice mistakes. For operators answering "should I use -all or ~all", "is +all dangerous", "what does spf=softfail mean", or "how do I migrate from ~all to -all safely" — every situation where the SPF qualifier choice matters.
This reference is provided in English. SPF is specified in an English-language RFC (RFC 7208 section 4.6.2) and the canonical qualifier vocabulary (Pass, Fail, SoftFail, Neutral) does not translate. We keep the body in the source language so technical terms remain consistent with the specification.
TL;DR
The four SPF qualifiers (RFC 7208 section 4.6.2) determine the receivers result code when a mechanism matches. Each qualifier is a single-character prefix on a mechanism token:
+(Pass) — default qualifier when none is specified. Producesspf=pass. Receiver treats the sender as authorised.-(Fail) — strong unauthorised signal. Producesspf=fail. Receiver may reject, discard, or quarantine per RFC 7208 §4.7. Use-allin production for any domain with a complete sender inventory.~(SoftFail) — weak unauthorised signal. Producesspf=softfail. Receiver should not reject solely on SoftFail. Use~allonly during initial deployment as a monitoring-mode placeholder.?(Neutral) — no definitive statement. Producesspf=neutral, treated equivalent to no SPF record. Rarely the right choice; avoid?allin production.
The qualifier almost always attaches to the
terminal all mechanism — and
-all is the canonical production
answer. The default Pass qualifier (implicit when
no prefix is written) is what makes
ip4:198.51.100.42 identical to
+ip4:198.51.100.42. The
Domain Security
Checker surfaces your records terminal qualifier
and flags suboptimal choices like +all
(authorises everything) or ?all (no
enforcement value).
1. What SPF qualifiers are and where they appear
A qualifier in an SPF record is a single-character prefix that determines the result code the receiver returns when a sender matches the qualified mechanism. The four qualifiers defined in RFC 7208 section 4.6.2 are:
+→ Pass (the default; producesspf=pass)-→ Fail (producesspf=fail)~→ SoftFail (producesspf=softfail)?→ Neutral (producesspf=neutral)
The qualifier attaches to any mechanism token —
ip4, ip6, a,
mx, ptr,
include, exists, or
all. In practice the qualifier other
than + is overwhelmingly used on the
terminal all mechanism to express
"what should the receiver do with anything not
matched by an earlier mechanism." Per-mechanism
qualifiers other than + are rare but
legal: -include:ex-vendor.example is
valid SPF that says "treat any match in the
ex-vendors include subtree as Fail."
Why qualifiers matter: the qualifier
is the policy signal SPF gives to the receiver. A
sender that produces spf=fail tells the
receiver "I know this is unauthorised — act on it."
A sender that produces spf=softfail
tells the receiver "I think this is unauthorised but
do not act on this alone." A sender that produces
spf=neutral tells the receiver "I have
no opinion." DMARC consumes these results when
determining alignment, so the qualifier choice
indirectly affects DMARC enforcement.
Scope note: this page covers the
four qualifiers in depth. The mechanism vocabulary
(a, mx, include,
ip4, ip6, ptr,
exists, all) and the
modifiers (redirect=, exp=)
are covered in the comprehensive
SPF
mechanisms explained reference.
2. The four qualifiers at a glance
Side-by-side comparison of the four SPF qualifiers (RFC 7208 section 4.6.2). The result code is what the receiver returns in the Authentication-Results header when a sender matches the qualified mechanism.
| Qualifier | Result code | Default? | Receiver action (typical) | Canonical use case |
|---|---|---|---|---|
+ |
Pass (spf=pass) |
Yes (default when no qualifier specified) | Treat sender as authorised; deliver normally | Implicit on every listed mechanism; +all almost always a misconfiguration |
- |
Fail (spf=fail) |
No | May reject at SMTP, discard, or quarantine per RFC 7208 §4.7 | -all in production for any domain with complete sender inventory |
~ |
SoftFail (spf=softfail) |
No | Record result; typically do NOT reject; weight other signals (DKIM, reputation, DMARC) | ~all during initial 30-90 day SPF deployment monitoring |
? |
Neutral (spf=neutral) |
No | Treat equivalent to no SPF record; rarely actionable on its own | Rare; avoid ?all in favour of -all with explicit sender inventory |
3. The + (Pass) qualifier
(RFC 7208 §4.6.2)
Definition: The plus qualifier
(+) marks a mechanism as producing the
Pass result code when the sender matches. Pass means
the receiver should treat the sender as authorised
by the domains SPF policy. Pass is the
default qualifier when no prefix is
specified on a mechanism.
Syntax:
+<mechanism> or simply
<mechanism> with no prefix (the
two forms are byte-equivalent at the receiver). So
+ip4:198.51.100.42 and
ip4:198.51.100.42 produce identical
behaviour; +include:_spf.google.com
and include:_spf.google.com are
identical. The terminal +all is
legitimately distinct (and almost always a
misconfiguration — see below).
Receiver behaviour: A sender that
matches a +-qualified mechanism causes
the receiver to record
Received-SPF: pass and
spf=pass in the Authentication-Results
header (RFC 8601). The receiver treats the SPF check
as successful. For DMARC purposes, Pass also enables
the SPF half of DMARC alignment (the SPF-authenticated
MAIL FROM domain is checked for alignment with the
From: header domain per RFC 7489).
When to use: The implicit Pass
qualifier applies to every explicitly listed
mechanism in your SPF record —
ip4:198.51.100.42,
include:spf.protection.outlook.com,
a:mail.example.com,
mx. You do not need to write the
+ prefix; the default is Pass. The
explicit + prefix is useful only when
you want to be unambiguous in documentation or when
a tool auto-generates SPF records and wants
explicit qualifiers throughout.
When NOT to use: Do NOT use
+all at the end of an SPF record — it
authorises EVERY IP address on the internet to send
mail as your domain. This is the most-warned-against
SPF anti-pattern: it defeats SPF entirely, provides
zero protection against spoofing, and effectively
declares your domain open for impersonation. Always
terminate the record with -all (strict
enforcement, recommended) or ~all
(monitoring mode, during deployment).
Common pitfalls: (1) Copy-pasting
+all from an outdated tutorial — replace
with -all immediately. (2) Treating
the explicit + prefix as somehow
different from the implicit default — they are
byte-equivalent at the receiver. (3) Writing
+ip4:0.0.0.0/0 "to authorise everything"
— equivalent to +all and equally
catastrophic. (4) Confusing per-mechanism
+ (harmless explicit-default) with
terminal +all (catastrophic open-relay
semantic).
4. The - (Fail) qualifier
(RFC 7208 §4.6.2)
Definition: The minus qualifier
(-) marks a mechanism as producing the
Fail result code when the sender matches. Fail
means the receiver should treat the sender as
explicitly unauthorised by the domains SPF policy.
RFC 7208 section 4.7 allows the receiver to reject
at SMTP, discard, or quarantine, though the standard
does not mandate any specific action.
Syntax:
-<mechanism>. The two canonical
usages: (a) -all at the end of the
record (Fail anything not previously matched), and
(b) per-mechanism -include:ex-vendor.example
or -ip4:<range> to revoke a
specific senders authorisation while keeping the
rest of the record permissive.
Receiver behaviour: A sender that
matches a --qualified mechanism causes
the receiver to record
Received-SPF: fail and
spf=fail in the Authentication-Results
header. Per RFC 7208 §4.7, the receiver MAY reject
the SMTP transaction with a 550 5.7.1 response, MAY
quarantine to a spam folder, or MAY deliver with
the Fail result recorded for downstream filtering.
Major receivers (Gmail, Microsoft 365, Yahoo, Apple
iCloud) typically combine spf=fail with DMARC
enforcement: if DMARC is p=reject and SPF fails,
the message is rejected; if DMARC is p=none and
SPF fails, the message is usually delivered with
spf=fail recorded.
When to use: Use -all
in production for any domain with a complete sender
inventory. This is the canonical production answer
and the recommended end-state of every SPF
deployment. Also use per-mechanism -
for: (a) revoking an ex-vendors authorisation while
keeping their include subtree visible
(-include:ex-vendor.example), (b)
explicitly blocking a known-bad IP range while
permitting the rest of a CIDR
(-ip4:198.51.100.42 ip4:198.51.100.0/24
— note first-match-wins means the more specific
Fail wins).
When NOT to use: Do NOT use
-all until you have confirmed every
legitimate sender is listed in the record — switching
to -all with a missing sender will
cause that senders mail to be rejected. Do NOT use
-all if you have not enabled DMARC
aggregate reporting (rua=) to surface unexpected
rejections. Do NOT use -all on a domain
whose sender inventory is volatile (frequent
vendor adds/removes) — stay on ~all
until inventory stabilises.
Common pitfalls: (1) Flipping to
-all before completing sender discovery
— breaks legitimate mail. (2) Combining -all
with an incomplete include tree (the include resolves
but lacks the actual sending IPs — every message
Fails). (3) Forgetting that -all only
affects senders NOT matched by an earlier mechanism;
a stale +include:ex-vendor.example
still authorises that vendors infrastructure
regardless of the terminal -all. (4)
Expecting -all alone to enforce
rejection without DMARC — many receivers tolerate
spf=fail unless DMARC also says reject. (5)
Writing --all (typo) — the second
minus is parsed as part of a malformed mechanism
and the record is invalid.
5. The ~ (SoftFail)
qualifier (RFC 7208 §4.6.2)
Definition: The tilde qualifier
(~) marks a mechanism as producing the
SoftFail result code when the sender matches.
SoftFail means "the domain believes the sender is
probably unauthorised but is not willing to make a
strong policy statement." RFC 7208 section 4.6.2
explicitly defines SoftFail as a weaker signal than
Fail; receivers should record the result but not
reject solely on this signal.
Syntax:
~<mechanism>. The overwhelmingly
common usage is ~all at the end of an
SPF record. Per-mechanism SoftFail
(~include:soon-to-be-removed.example or
~ip4:<deprecating-range>) is rare
but legal — useful as a transition state when
deprecating a sender without immediate hard-fail.
Receiver behaviour: A sender that
matches a ~-qualified mechanism causes
the receiver to record
Received-SPF: softfail and
spf=softfail in the Authentication-Results
header. Most receivers (Gmail, Microsoft 365,
Yahoo) treat SoftFail as a non-pass signal but do
not reject solely on this result. The practical
delivery effect is typically: the message is
delivered (often to the inbox if other signals are
good) with spf=softfail recorded. DMARC counts
SoftFail as a non-pass for the SPF half of
alignment, so DMARC enforcement may still fire if
DMARC is at quarantine or reject.
When to use: Use ~all
during the initial 30-90 day SPF deployment window
when you are still discovering legitimate senders.
The SoftFail signal lets DMARC aggregate reports
surface unexpected senders without breaking their
delivery while you complete the inventory. Once 30
consecutive days show zero unexplained SoftFails
for legitimate sources, flip to -all
for production enforcement. Per-mechanism
~ is useful during a sender deprecation:
flag the soon-to-be-removed mechanism with
~ for two weeks, monitor for any
remaining legitimate traffic, then remove.
When NOT to use: Do NOT use
~all indefinitely in production — it
provides weak enforcement and signals to spoofers
that your domain is not seriously protected. Do NOT
use ~all as a permanent fixture on a
domain at DMARC p=reject — the combination is
incoherent (DMARC reject says "reject the message"
but SPF SoftFail says "do not reject solely on
this"; you want SPF Fail + DMARC reject for
consistent semantics). Do NOT use ~all
if your domain sends no mail (use
v=spf1 -all instead, the null-sender
canonical form).
Common pitfalls: (1) Leaving
~all in place indefinitely after
initial deployment — the canonical SPF deployment
ramp is ~all → -all over 30-90 days. (2) Expecting
SoftFail to cause rejection at SMTP — most receivers
deliver SoftFailed mail. (3) Pairing
~all with DMARC p=reject — incoherent
policy signal; pair -all with DMARC
p=reject instead. (4) Using ~all on a
domain whose sender inventory is supposedly
complete — flip to -all and let
aggregate reports flag any missed senders. (5)
Misreading the tilde as a no-op — SoftFail does
affect DMARC alignment computation even if it
does not affect SMTP-time delivery.
6. The ? (Neutral)
qualifier (RFC 7208 §4.6.2)
Definition: The question-mark
qualifier (?) marks a mechanism as
producing the Neutral result code when the sender
matches. Neutral means "the domain has explicitly
declined to make a statement about this sender."
RFC 7208 section 4.6.2 defines Neutral as equivalent
to "no SPF record found" for the matching senders —
the receiver should treat it the same as if SPF
were not deployed at all.
Syntax:
?<mechanism>. The overwhelmingly
rare canonical form is ?all at the end
of an SPF record. Per-mechanism Neutral
(?include:unverified.example) exists
in the spec but has essentially no production use
case — most operators reach for SoftFail or Fail
instead.
Receiver behaviour: A sender that
matches a ?-qualified mechanism causes
the receiver to record
Received-SPF: neutral and
spf=neutral in the Authentication-Results
header. The receiver treats the result as equivalent
to no SPF record — the message is delivered, but
SPF provides no positive or negative signal. DMARC
counts Neutral as a non-pass for SPF alignment, so
the DMARC verdict depends entirely on DKIM (which
must pass and align for the message to pass DMARC).
When to use: Almost never. The
canonical use case sometimes cited is a parent
domain whose subdomains have their own SPF records
and the parent itself sends no mail — but even
there, the more correct answer is
v=spf1 -all (explicit "no senders
authorised, reject any direct send from the parent
domain"). The Neutral qualifier exists in the spec
for completeness and to give operators a way to
publish a record that intentionally provides no
enforcement signal — but in practice this is rarely
the right answer.
When NOT to use: Do NOT use
?all as a "weak default" — if you want
weak enforcement, use ~all instead
(SoftFail at least signals non-pass; Neutral
signals nothing). Do NOT use ?all on
a domain that sends mail — it tells receivers
nothing about your sending posture and weakens
DMARC alignment. Do NOT use ?all as a
placeholder during SPF deployment — use
~all with DMARC rua reporting instead.
Common pitfalls: (1) Treating
?all as equivalent to "I have not
decided yet" — receivers cannot distinguish
intentional Neutral from accidental Neutral, and
you get zero protective value either way. (2)
Confusing ?all with "the safe choice"
— it is strictly weaker than ~all
which is strictly weaker than -all;
moving down the ladder removes protection. (3)
Inheriting ?all from a copy-pasted
template and never revisiting — audit your SPF
records quarterly and replace any ?all
with -all (or ~all if
still in deployment monitoring). (4) Using
?all on a null-sender parking domain
— use v=spf1 -all for the canonical
"this domain does not send mail" semantic.
7. Receiver-side interpretation matrix
How major receivers actually treat each SPF result code in 2026, based on observable Authentication-Results headers, public documentation, and DMARC enforcement behaviour. Specific SMTP-time rejection behaviour depends on per-tenant policy and may vary.
| Receiver | + (Pass) | - (Fail) | ~ (SoftFail) | ? (Neutral) |
|---|---|---|---|---|
| Gmail / Google Workspace | spf=pass; DMARC alignment proceeds | spf=fail; DMARC reject fires if p=reject; otherwise delivered with spf=fail recorded | spf=softfail; usually delivered; non-pass for DMARC | spf=neutral; delivered; non-pass for DMARC; relies on DKIM |
| Microsoft 365 / Outlook.com | spf=pass; Defender chain proceeds | spf=fail; reject at SMTP if DMARC p=reject; otherwise to Junk/Quarantine | spf=softfail; usually delivered; SCL bump possible | spf=neutral; treated as no SPF; DKIM/DMARC determine |
| Yahoo Mail / AOL | spf=pass; DMARC alignment proceeds | spf=fail; reject if DMARC p=reject; otherwise spam folder | spf=softfail; usually delivered; reputation-weighted | spf=neutral; treated as no SPF |
| Apple iCloud Mail | spf=pass; alignment proceeds | spf=fail; combine with DMARC for final disposition | spf=softfail; usually delivered | spf=neutral; non-pass for DMARC |
Key takeaways:
- Fail (
-) is necessary but not sufficient for rejection. Most receivers only reject spf=fail when DMARC is also at p=quarantine or p=reject. SPF Fail alone usually results in delivery-to-spam, not rejection. - SoftFail (
~) is almost always delivered. The qualifier signals "probably not legitimate" but receivers do not act on it alone. SoftFail mainly affects DMARC alignment (counts as non-pass) and downstream reputation scoring. - Neutral (
?) provides no protective value. Receivers treat it equivalent to no SPF record; the only way to pass DMARC for a Neutral-qualified sender is via DKIM. - Pass (
+) enables DMARC alignment. Without Pass on the connecting senders mechanism, DMARC must rely on DKIM to pass — a single point of failure if DKIM also fails (e.g. message forwarded and body modified).
8. Four worked deployment examples
8.1 Production: complete inventory with hard fail
Scenario: a company has audited every legitimate sender (Microsoft 365 for corporate mail, SendGrid for transactional, on-prem MTA at 198.51.100.42 for monitoring alerts) and is ready for strict enforcement.
example.com. IN TXT "v=spf1 ip4:198.51.100.42 include:spf.protection.outlook.com include:sendgrid.net -all"
Rationale: -all declares Fail for any
sender not matched above. The complete sender
inventory protects legitimate mail; spoofing
attempts return spf=fail and (paired with DMARC
p=reject) are rejected. This is the canonical
production end-state for any DMARC-enforcement-bound
domain.
8.2 Deployment monitoring: ~all with DMARC rua
Scenario: a company is rolling out SPF for the first time. They have published an initial sender list but want 60 days of aggregate reports to surface any missed senders before switching to strict enforcement.
example.com. IN TXT "v=spf1 ip4:198.51.100.42 include:spf.protection.outlook.com include:sendgrid.net ~all"
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"
Rationale: ~all returns SoftFail for
unmatched senders — they are still delivered (so
legitimate-but-missed mail does not break) but the
SoftFail result is logged in the receivers
Authentication-Results header and surfaces in the
DMARC aggregate reports. After 60 days of clean
reports (no SoftFail for legitimate sources), flip
~all to -all and DMARC
p=none to p=quarantine.
8.3 Null-sender domain (no mail expected)
Scenario: a parked domain or apex-only domain that sends no mail (e.g. example-brand.com whose only use is the marketing website — no transactional mail, no corporate mail, no automation alerts).
example-brand.com. IN TXT "v=spf1 -all"
Rationale: -all with no preceding
mechanisms declares "no IP is authorised to send
mail as this domain." Any spoofing attempt returns
spf=fail. Pair with DMARC p=reject
for explicit rejection. Do NOT use
v=spf1 ?all (Neutral, no enforcement)
or v=spf1 ~all (SoftFail, weak
enforcement) for a null-sender domain — the
canonical answer is v=spf1 -all.
8.4 Vendor deprecation: per-mechanism SoftFail
Scenario: a company is migrating off SendGrid to Mailgun. They want SendGrid traffic to start SoftFailing immediately to surface any forgotten integrations, while keeping Mailgun fully authorised.
example.com. IN TXT "v=spf1 ip4:198.51.100.42 include:spf.protection.outlook.com include:mailgun.org ~include:sendgrid.net -all"
Rationale: the per-mechanism
~include:sendgrid.net returns SoftFail
for any sender that matches the SendGrid include
subtree — the message is still delivered but the
spf=softfail result surfaces in DMARC aggregate
reports. After two weeks of clean reports (no
legitimate SendGrid traffic remaining), remove the
~include:sendgrid.net entirely; the
terminal -all then Fails any remaining
SendGrid traffic.
9. The seven most common qualifier-choice mistakes
-
Using
+allin production. Authorises every IP on the internet to send mail as your domain; defeats SPF entirely. Almost always a copy-paste error from an outdated tutorial. Fix: replace with-all(recommended) or~allif still in deployment monitoring. -
Leaving
~allindefinitely after initial deployment. SoftFail is a deployment-monitoring state, not a production end-state. Spoofers learn that your domain is not under strict enforcement. Fix: after 30-90 days of clean aggregate reports, flip~allto-all. -
Using
?allfor "soft enforcement". Neutral provides ZERO protective signal — receivers treat it equivalent to no SPF record. Strictly weaker than~allfor the same scenario. Fix: replace with~all(during deployment) or-all(in production). -
Omitting the terminal qualifier
entirely. A record like
v=spf1 ip4:198.51.100.42with no terminalallclause has an implicit Neutral terminal per RFC 7208 — provides zero enforcement for unmatched senders. Fix: always end the record with an explicit qualified all token (-all,~all, or rarely?all). -
Pairing
~allwith DMARC p=reject. Incoherent policy: SPF says "do not reject solely on this" but DMARC says "reject the message." The DMARC reject still fires (DMARC is the controlling policy) but the qualifier mismatch suggests confused operator intent. Fix: use-allwhen DMARC is at quarantine or reject; reserve~allfor DMARC p=none. -
Flipping to
-allbefore completing sender inventory. Switching to hard fail with a missing legitimate sender causes that senders mail to be rejected — a production outage for the missed sender. Fix: stay on~alluntil 30 consecutive days of aggregate reports show no unexplained SoftFails for legitimate sources, THEN flip. -
Writing per-mechanism
-on an include you do not control. A record like-include:partner.exampleattempts to revoke a partners include — but the partner can change their record at any time and the revoke may need re-targeting. Fix: simply remove theinclude:partner.exampleentirely; the terminal-allthen Fails any partner-originated traffic by default.
10. FAQ
- What is the difference between SPF -all and ~all?
- The minus-all (-all, Fail) qualifier tells the receiver that any sender not explicitly authorised in the SPF record should be treated as Fail — receivers may reject, discard, or quarantine the message per RFC 7208 section 4.7 guidance. The tilde-all (~all, SoftFail) qualifier tells the receiver that any unauthorised sender should be treated as SoftFail — the message is probably not legitimate, but receivers should not reject solely on this result. The practical difference: -all delivers strong enforcement (receivers act on the fail signal), ~all delivers monitoring-mode behaviour (the result is recorded but typically not acted upon at SMTP time). Use -all in production for any domain with a complete sender inventory. Use ~all only during initial deployment when you are still discovering legitimate senders and want to avoid blocking them by accident. Migrating from ~all to -all is the canonical SPF enforcement-ramp playbook.
- What does +all mean in an SPF record?
- The plus-all (+all, Pass) qualifier authorises EVERY IP address on the internet to send mail as the domain — it makes SPF unconditionally pass for any sender. This is almost always a misconfiguration: it defeats SPF entirely (every spam, phishing, and impersonation message gains SPF pass) and provides zero protection. The plus qualifier (+) is the default qualifier when none is specified, so +ip4:198.51.100.42 is identical to ip4:198.51.100.42. But +all means "authorise everything" which is never the operator intent. If you find +all in an SPF record, replace it with -all (strict enforcement, recommended) or ~all (soft enforcement, monitoring mode). Some sources confuse +all with the more reasonable +ip4:... or +include:... forms — only +all is dangerous; the plus prefix on a specific mechanism is just an explicit version of the default Pass qualifier.
- When should I use SPF ?all instead of -all or ~all?
- Almost never. The question-mark-all (?all, Neutral) qualifier makes no statement about senders not explicitly listed — the receiver treats the result as equivalent to no SPF record at all. This is sometimes recommended for a parent domain whose subdomains have their own SPF records and the parent itself sends no mail — but even there, the more correct answer is a v=spf1 -all record (explicit "no senders authorised"). The ?all qualifier is rarely the right choice because (1) it provides no protective signal, (2) it tells receivers nothing about your sending posture, and (3) it makes DMARC alignment harder to reason about. Use -all for production enforcement, ~all only during initial deployment monitoring, and ?all essentially never. The fourth qualifier (?) exists in the spec for completeness but has no canonical production use case.
- What is SPF SoftFail and how do receivers treat it?
- SPF SoftFail (~, tilde) is the result code receivers return when a sender matches a mechanism prefixed with ~ — typically ~all at the end of an SPF record. RFC 7208 section 4.6.2 defines SoftFail as "the domain believes the host is not authorised but is not willing to make a strong policy statement." Most receivers treat SoftFail as a soft signal: Gmail and Microsoft 365 record spf=softfail in the Authentication-Results header but typically do not reject or move to spam based on SoftFail alone (DMARC, content filtering, and reputation drive the final disposition). The practical effect: a SoftFailed message is usually delivered, but the result counters DMARC pass if DMARC is also failing (DMARC requires either SPF or DKIM to pass and align; SoftFail counts as a non-pass for DMARC purposes). Use ~all only during pre-enforcement monitoring; switch to -all once you have confirmed the legitimate sender inventory is complete.
- Does the default SPF qualifier matter if I do not write it?
- The default qualifier for ANY SPF mechanism with no explicit prefix is Pass (+). So v=spf1 ip4:198.51.100.42 include:_spf.google.com -all is exactly equivalent to v=spf1 +ip4:198.51.100.42 +include:_spf.google.com -all. The default Pass means a match on that mechanism produces spf=pass. The default does not extend to the terminal all mechanism: v=spf1 ip4:198.51.100.42 (with NO all clause) is a record that produces Pass for the listed IP and Neutral for everything else (per RFC 7208 the implicit terminal is Neutral, not Pass). Best practice is to ALWAYS terminate the record with an explicit qualified all clause (-all, ~all, or rarely ?all) so the records intent is unambiguous to the receiver.
- Can I use SPF qualifiers on specific mechanisms instead of just all?
- Yes. Any mechanism token in an SPF record can carry an explicit qualifier prefix (+, -, ~, or ?). So -include:ex-vendor.example is a valid mechanism that says "if the sender matches this include, treat the match as Fail" — useful for selectively flagging a sender that should never legitimately send mail as your domain. Similarly ~ip4:198.51.100.0/24 says "if the sender is in this range, treat it as SoftFail." In practice, per-mechanism qualifiers other than + are rare: most operators rely on the default Pass for explicitly listed mechanisms and use the qualifier only on the terminal all token. The two notable exceptions: (1) a -include:vendor.example to revoke authorisation for a known-bad provider whose include subtree might still authorise their IPs, and (2) ~ip4:... during traffic-shifting to mark IPs as soon-to-be-removed without immediate hard-fail. The DMARC Analyzer Domain Security Checker surfaces per-mechanism qualifier choices in its SPF analysis.
- Is SPF -all required for DMARC enforcement?
- No, SPF -all is not technically required for DMARC enforcement — DMARC operates on the aligned authentication result (either SPF or DKIM passing and aligning), not on the SPF qualifier specifically. However, -all is STRONGLY recommended for any domain at DMARC p=quarantine or p=reject. The reason: DMARC enforcement only takes effect when authentication fails or fails to align. If your SPF record is ~all (SoftFail), a spoofed message from an unauthorised IP returns spf=softfail (counted as non-pass for DMARC) — and DMARC reject still fires. The qualifier matters for non-DMARC-aware receivers and for SPF-only enforcement at the SMTP layer. Modern best practice is -all + DMARC p=reject — they reinforce each other and provide both pre-DMARC-evaluation (SPF rejection at SMTP) and post-DMARC-evaluation (DMARC reject) defence layers. Always pair -all with a complete sender inventory; -all with a missing legitimate sender breaks delivery.
- Why do receivers sometimes ignore SPF Fail and deliver the message anyway?
- Receivers may deliver an spf=fail message for several reasons that all stem from RFC 7208 section 4.7 explicitly NOT mandating rejection. The RFC says "the receiver MAY take Local Policy action on a Fail result" but does not require rejection. Common reasons receivers deliver despite Fail: (1) the receiver weights other signals (DKIM pass, sender reputation, content filtering, DMARC p=none) more heavily than raw SPF, (2) the message was forwarded and the receiver detects the forwarder pattern, (3) the receiver runs ARC-validation and trusts an upstream ARC chain, (4) the receiver applies different policies to different mailbox tenants (an enterprise customer with strict policy may reject; a consumer mailbox may deliver to spam folder), (5) DMARC is at p=none which overrides SPF Fail with a "monitor only" disposition. The qualifier (-all) is necessary but not sufficient for actual rejection — pair with DMARC p=reject for predictable behaviour.
- How do I migrate from SPF ~all to -all safely?
- The canonical SPF enforcement-ramp playbook: (1) Deploy v=spf1 ... ~all in production for 30-90 days with DMARC rua reporting enabled. (2) Review aggregate reports daily to identify any legitimate sender that returns spf=softfail — add it to the SPF record via include, ip4, or a as appropriate. (3) Verify the cumulative DNS-lookup cost stays under 10 (RFC 7208 section 4.6.4) as you add senders. (4) Once 30 consecutive days show ZERO unexplained softfails for legitimate sources, flip ~all to -all. (5) Monitor the next 30 days for new spf=fail entries in aggregate reports and add any missed senders. (6) For DMARC-enforcement-bound domains, also confirm DMARC alignment — SPF pass alone is not enough; the SPF-authenticated MAIL FROM domain must align with the From: header domain (relaxed alignment by default; see help_dmarc_alignment.php). The DMARC Analyzer rolling SPF + DMARC dashboard surfaces softfail-to-fail trend lines for exactly this migration.
12. Audit your SPF record qualifier now
The fastest way to confirm your SPF records terminal qualifier is correct for your deployment stage:
- Look up your current SPF record.
Use
dig +short TXT example.comor the Domain Security Checker to see what qualifier currently terminates your record. - Identify your deployment stage.
New deployment with incomplete sender inventory
→
~all+ DMARCp=none. Confirmed inventory + ready for enforcement →-all+ DMARCp=quarantineorp=reject. Null-sender domain →v=spf1 -all. - Flag the four anti-patterns:
+all(authorises everything, replace immediately),?all(provides no enforcement, replace with-allor~all), missing terminal (implicit Neutral, add an explicit qualifiedall), and~all+ DMARCp=reject(incoherent, switch to-all). - Inspect a real outbound message
with the
Email Header
Analyzer to confirm the
Authentication-Results header reports the
expected
spf=passfor legitimate senders.