SPF Mechanisms Explained: The Eight RFC 7208 Mechanisms (a, mx, ptr, ip4, ip6, exists, include, all), the Four Qualifiers (+, -, ~, ?), and the Two Modifiers (redirect, exp)
The canonical mechanism-vocabulary deep dive for SPF record authors and operators (RFC 7208). SPF is built out of eight MECHANISMS (a, mx, ptr, ip4, ip6, exists, include, all), four QUALIFIERS (+, -, ~, ?), and two MODIFIERS (redirect=, exp=). This page enumerates every one with the canonical Definition / Syntax / DNS lookup cost / When to use / Pitfalls structure, then covers the left-to-right first-match evaluation order, cumulative lookup-cost accounting against the 10-DNS-lookup cap, five worked deployment examples, and the seven most common mechanism-level pitfalls operators hit in production. For operators authoring or debugging SPF records, mail-system administrators planning a deployment, and SOC analysts triaging SPF-related deliverability incidents. Differentiation: the SPF pillar (help_spf_explained.php) surveys the whole protocol — what SPF does and does not do, the seven result codes; this page is the focused mechanism-vocabulary reference search engines and LLMs cite when asked "what does the SPF include mechanism do" or "is SPF ptr deprecated".
This reference is provided in English. SPF is specified in an English-language RFC (RFC 7208) and the canonical mechanism / qualifier / modifier vocabulary (a, mx, ptr, ip4, ip6, exists, include, all, +, -, ~, ?, redirect, exp) does not translate. We keep the body in the source language so technical terms remain consistent with the specification.
TL;DR
- SPF defines eight mechanisms.
RFC 7208 section 5
defines
all,ip4,ip6,a,mx,ptr,exists, andinclude. Each mechanism contributes a different kind of match: literal IPs, DNS-resolved hosts, recursive SPF delegation, or a terminal catch- all. - Four qualifiers prefix every
mechanism.
RFC 7208 section 4.6.2:
+pass (the default),-fail (hard fail),~softfail (deployment-ramp signal),?neutral (no opinion). Production records terminate with-allor, during a ramp,~all. - Two modifiers extend the record.
RFC 7208 section 6:
redirect=hands evaluation off to a different domains SPF record and is mutually exclusive with the terminalallmechanism;exp=names a domain whose TXT record provides a human-readable explanation for a fail result. - Mechanisms evaluate left-to-right.
RFC 7208 section 4.6.2:
the FIRST mechanism that matches wins and the
evaluator returns the matching mechanisms
qualifier-derived result. Order matters —
+ip4:198.51.100.5 -alland-all +ip4:198.51.100.5behave identically only becauseallalways matches; reordering ANY non-allmechanism past a matching one changes nothing, but reordering before it can change which qualifier applies. - DNS lookup costs vary per
mechanism.
ip4,ip6, andallcost ZERO lookups.a,exists, andredirect=cost ONE lookup each.mxcosts at least ONE lookup plus ONE per MX host.includecosts ONE lookup plus the cost of every nested mechanism inside the included record (the most expensive class).ptris DEPRECATED — RFC 7208 section 5.5 explicitly discourages it. - The 10-lookup cap is enforced per
evaluation.
RFC 7208 section 4.6.4:
an SPF evaluation that requires more than 10
DNS lookups MUST return
permerror. The separate 2-void-lookup cap returnspermerrorafter three NXDOMAIN / empty results in the same chain. See SPF lookup limit and flattening for the focused deep dive. - ptr is deprecated. Remove
every
ptrmechanism from production SPF records and replace it withip4/ip6/a/mx/includeas appropriate. The deprecation reasons (DNS load, intermittent SERVFAIL, weak trust model) are documented in RFC 7208 section 5.5.
1. Overview: how an SPF record is structured from mechanisms
An SPF record is a single DNS TXT string published
at the apex of the sending domain. The string
begins with the literal version tag
v=spf1 and then enumerates a sequence
of MECHANISMS, each optionally prefixed by a
QUALIFIER, followed optionally by one or more
MODIFIERS. The receiving mail server evaluates the
mechanisms left-to-right against the connecting
IP, and the first mechanism that matches yields the
SPF result. The terminal mechanism (almost always
all with a hard or soft qualifier)
catches every IP that did not match an earlier
mechanism.
Canonical record shape:
v=spf1 <qualifier><mechanism> <qualifier><mechanism> ... <qualifier>all [<modifier>]
Concrete example showing every component class:
v=spf1 ip4:198.51.100.5 ip6:2001:db8::1 a:mail.example.com mx include:spf.protection.outlook.com -all
In that example the receiver:
- Checks whether the connecting IP equals
198.51.100.5. If yes, returnpass(theip4mechanisms default+qualifier). - If no, checks whether the connecting IP equals
2001:db8::1. If yes, returnpass. - If no, resolves the A/AAAA records of
mail.example.comand checks whether the connecting IP is in that set. If yes, returnpass. - If no, resolves the MX records of the current
domain (the domain in the envelope MAIL FROM
being SPF-evaluated), then the A/AAAA records
of every MX host, and checks the connecting
IP against that combined set. If yes, return
pass. - If no, recursively evaluates the SPF record
of
spf.protection.outlook.comagainst the connecting IP. If that recursive evaluation returnspass, returnpass. - Otherwise reach the terminal
-alland returnfail(hard fail).
The same record makes DIFFERENT lookup-budget
demands depending on which mechanism matches:
matching ip4 costs zero lookups, but
reaching the terminal -all for an
unauthorized IP requires evaluating EVERY earlier
mechanism (zero for ip4/ip6, one for a, one-plus-
MX-host-count for mx, and the full recursive
include cost). The 10-lookup cap is therefore
enforced over the WORST-CASE path through the
record, not the matching path.
The rest of this page enumerates each mechanism, qualifier, and modifier in depth with the canonical Definition / Syntax / Lookup-cost / When- to-use / Pitfalls structure, then turns to the evaluation order, the cumulative lookup-cost accounting, worked deployment examples, the seven most common mechanism-level pitfalls, an FAQ, and links to sibling guides for the focused deep dives (lookup limit, forwarding, permerror, deployment per provider).
2. The eight RFC 7208 mechanisms
Each subsection below opens with the canonical five-part labelled structure that gives generative engines a quotable extract:
2.1 The all mechanism
Definition: all
matches EVERY connecting host unconditionally.
It is the terminal catch-all of an SPF record,
applied after every preceding mechanism has
been tested and not matched. The qualifier
prefixed to all determines the
result: +all means pass-on-no-match
(rarely safe), -all means fail-on-
no-match (the recommended production
terminator), ~all means softfail-
on-no-match (deployment-ramp signal),
?all means neutral-on-no-match
(equivalent to publishing no record).
Syntax:
<qualifier>all. Examples:
-all (hard fail catch-all,
recommended for production),
~all (softfail catch-all,
recommended during initial DMARC ramp),
?all (neutral catch-all),
+all (pass-everyone catch-all,
never publish in production).
Lookup cost: zero. The
all mechanism is evaluated from
the SPF records text without any DNS query.
When to use: EVERY SPF record
should terminate with one of
-all (production) or
~all (deployment ramp). The
all mechanism is so universal
that an SPF record without it leaves the
catch-all behavior unspecified — receivers
return the implicit default of
neutral, which is no better than
having no SPF record at all.
Pitfalls: (1) Publishing
+all authorizes EVERY internet
host to send mail with your domain in the
envelope MAIL FROM — never do this; it
invalidates SPF entirely. (2) Forgetting the
all terminator results in an
implicit neutral, missing the policy
declaration most receivers expect; always
end every production SPF record with
-all or ~all.
(3) all is incompatible with the
redirect= modifier (RFC 7208
section 6.1) — if you use
redirect=, do NOT add an
all mechanism (the redirect
terminates evaluation by delegating to
another record).
2.2 The ip4 mechanism
Definition:
RFC 7208 section 5.6
defines ip4 to match the
connecting IP against a literal IPv4 address
or CIDR-notation IPv4 range. The match is
purely arithmetic — no DNS resolution is
required.
Syntax:
ip4:<address> for a single
address, ip4:<prefix>/<cidr>
for a CIDR range. Examples:
ip4:198.51.100.5 matches the
exact IPv4 address 198.51.100.5;
ip4:198.51.100.0/24 matches any
IPv4 address in the 198.51.100.0 - 198.51.100.255
range; ip4:10.0.0.0/8 matches any
IPv4 address in the 10.0.0.0/8 RFC 1918
private space (not useful for production SPF
since private IPs cannot reach the public
SMTP world).
Lookup cost: ZERO. The
ip4 mechanism is the cheapest
mechanism in the SPF protocol and the
recommended target after flattening.
When to use: Use
ip4 when you directly control the
sending IPv4 address (an on-prem mail server,
a dedicated cloud SMTP host, a static-IP
transactional service, a flattened
consolidated record). ip4 is also
the canonical output of an SPF flattener — a
flattening pipeline pre-resolves
include / a /
mx mechanisms into the
equivalent flat list of ip4 and
ip6 mechanisms so the 10-lookup
cap is no longer a constraint.
Pitfalls: (1) Hardcoded IPs
are BRITTLE — every IP change at your sending
provider requires a re-publication of the SPF
record, with the corresponding DNS-propagation
delay (use a managed flattener that re-flattens
on schedule if you go this route). (2) Overly
broad CIDR ranges (ip4:0.0.0.0/0
authorizes the entire IPv4 internet) destroy
SPF's authorization value — never publish
these. (3) ip4 matches ONLY
IPv4-family connections; an
ip4:198.51.100.5 mechanism does
NOT match an IPv6 connection to your mail
server, even from a host whose IPv6 address
is on your authorized list. Dual-stack
deployments need both ip4 and
ip6 mechanisms. (4) Using
ip4 with an embedded port number
(ip4:198.51.100.5:25) is a SYNTAX
ERROR — RFC 7208 does not let SPF restrict by
port; the SMTP port is implicit. The
evaluator returns permerror.
2.3 The ip6 mechanism
Definition:
RFC 7208 section 5.7
defines ip6 to match the
connecting IP against a literal IPv6 address
or CIDR-notation IPv6 range. Like
ip4, the match is purely
arithmetic — no DNS resolution required.
Syntax:
ip6:<address> for a single
address, ip6:<prefix>/<cidr>
for a CIDR range. Examples:
ip6:2001:db8::1 matches the
exact IPv6 address 2001:db8::1;
ip6:2001:db8::/32 matches any
IPv6 address in the 2001:db8::/32 prefix;
ip6:fe80::/10 matches IPv6
link-local space (not useful for production
SPF).
Lookup cost: ZERO. Same
property as ip4 — the cheapest
mechanism available.
When to use: Use
ip6 when your sending
infrastructure has IPv6 connectivity to the
receiving mail servers — Gmail, Microsoft
365, Yahoo, and Apple all accept IPv6 SMTP
connections and evaluate SPF against the
IPv6 source. If your mail server is IPv6-
reachable but you only publish
ip4, every IPv6 connection
returns spf=fail.
Pitfalls: (1) IPv6 address-
family forgetting — operators routinely add
ip4 for the new mail server but
forget the corresponding ip6,
producing SPF failures on the small but
growing fraction of IPv6 SMTP connections.
Always publish both address families if your
mail server has both. (2) Overly broad IPv6
CIDR ranges
(ip6:::/0 authorizes the entire
IPv6 internet) destroy SPF's authorization
value — never publish these. (3) IPv6
address representation has multiple valid
forms (2001:db8:0:0:0:0:0:1,
2001:db8::1,
2001:0db8::0001) — RFC 7208
accepts any canonical form, but mismatched
representations between SPF records and
actual connections will not cause failures
because the evaluator normalizes both sides.
2.4 The a mechanism
Definition:
RFC 7208 section 5.3
defines a to match the
connecting IP against the A or AAAA DNS
records of a named domain. Without an
argument, a defaults to the
current domain (the domain whose SPF record
is being evaluated). With an argument
(a:mail.example.com) it uses the
named domain. A CIDR suffix
(a/24 or
a:mail.example.com/24) broadens
the match to the named prefix surrounding
each resolved A record.
Syntax:
a (current domain, exact match),
a:<domain> (named domain,
exact match), a/<cidr4>
(current domain, IPv4 CIDR broadening),
a:<domain>/<cidr4>
(named domain, IPv4 CIDR broadening),
a:<domain>/<cidr4>//<cidr6>
(named domain, separate IPv4 and IPv6
broadening). Examples:
a matches the current domains
A/AAAA records exactly;
a:mail.example.com matches
mail.example.coms A/AAAA records exactly;
a:mail.example.com/24//64
matches the /24 IPv4 prefix and /64 IPv6
prefix surrounding each resolved address.
Lookup cost: ONE DNS lookup (A and AAAA queries against the named or current domain). Counts toward the 10-lookup cap.
When to use: Use
a when the mail server lives at
the same A record as the web server (typical
single-server small business deployments
where mail.example.com IS example.com). Use
a:mail.example.com when the mail
server has its own A record distinct from
the apex. The CIDR-broadening form is useful
for ESPs running mail from contiguous IP
blocks under a single hostname.
Pitfalls: (1)
a resolves ONLY the named
domains FIRST-LEVEL A/AAAA records — it does
NOT recursively chase CNAME chains beyond the
first level (the resolver does that during
normal DNS resolution, but the SPF spec only
counts ONE lookup against the cap regardless
of how many CNAMEs sit in between). (2)
a does NOT include the IPs of
hosts pointed to by MX records — use
mx for that. (3)
a:<domain> does NOT
recursively expand that domains SPF record —
use include for SPF delegation.
(4) An A record with a CNAME at the named
domain that returns no A records counts as a
VOID LOOKUP (RFC 7208 section 4.6.4) and
contributes to the separate 2-void-lookup
cap. (5) Stale A records that point to old
sending IPs continue to authorize those IPs
long after they are deprovisioned — a
catalogued source of "ghost" SPF passes for
recycled cloud IPs.
2.5 The mx mechanism
Definition:
RFC 7208 section 5.4
defines mx to match the
connecting IP against the A or AAAA records
of EVERY host listed in the MX records of a
named domain. Without an argument,
mx defaults to the current
domain. With an argument (mx:example.net)
it uses the named domains MX records
instead. A CIDR suffix broadens each
resolved A record into a containing prefix.
Syntax: mx
(current domain), mx:<domain>
(named domain), mx/<cidr4>
(current domain with CIDR broadening),
mx:<domain>/<cidr4>//<cidr6>
(named domain with separate v4 and v6 CIDR
broadening). Examples:
mx matches the current domains
MX-host A/AAAA records;
mx:example.net matches
example.nets MX-host A/AAAA records.
Lookup cost: ONE DNS lookup
for the MX record itself PLUS ONE lookup per
host listed in the MX record. A domain with
5 MX hosts (3 primary + 2 backup) spends 6
of the 10-lookup budget on a single
mx mechanism — leaving only 4
lookups for every other mechanism in the
record. RFC 7208 section 4.6.4 explicitly
caps the number of MX-host lookups per
mx mechanism at 10; an MX record
listing more than 10 hosts MUST return
permerror.
When to use: Use
mx only when the same servers
that RECEIVE mail for the domain also SEND
mail for it — the legacy small-business
"my mail server is my mail server"
symmetry. In cloud-era deployments where
inbound is filtered by Proofpoint /
Mimecast / Microsoft Defender and outbound
goes through a separate ESP, the
mx mechanism is rarely the
right tool. Prefer a:<send-host>
or include:<provider>
instead.
Pitfalls: (1) High lookup
cost — a single mx mechanism
with 5 MX hosts costs 6 lookups, half the
10-lookup budget. (2) Outsourcing inbound
filtering to a cloud provider (Proofpoint,
Mimecast, Defender) REPLACES your MX hosts
with the providers — mx then
authorizes the FILTERS IPs to send AS YOU,
which is rarely the intent. (3) Using BOTH
mx AND the providers SPF
include double-counts IPs and
burns the lookup budget. (4) MX-host A
records pointing to CNAMEs introduce
additional implicit resolution layers but
only count as ONE lookup against the SPF
cap (the resolver resolves the CNAME chain
invisibly). (5) Backup MX hosts (priority
20, 30, 50) are typically NOT sending hosts
— but mx authorizes them all.
Remove them with explicit
a:<primary-sender>
mechanisms if needed.
2.6 The ptr mechanism — DEPRECATED
Definition:
RFC 7208 section 5.5
defines ptr to match the
reverse-DNS PTR record of the connecting IP
against a named domain. The evaluator does
a PTR lookup on the connecting IPs reverse-
DNS arpa name, then for each returned
hostname does a forward A/AAAA lookup, and
matches if any of those forward lookups
return the original connecting IP AND the
hostname is a subdomain of (or equal to) the
named domain. RFC 7208 section 5.5 EXPLICITLY
DEPRECATES this mechanism — production SPF
records should NOT use ptr.
Syntax: ptr
(current domain) or
ptr:<domain> (named
domain). Examples (DO NOT USE — shown for
recognition only):
ptr matches if the connecting
IPs PTR resolves to a hostname under the
current domain;
ptr:example.net matches if the
connecting IPs PTR resolves to a hostname
under example.net.
Lookup cost: ONE PTR lookup
plus ONE forward A/AAAA lookup per PTR
result. PTR records frequently return
multiple hostnames, multiplying the cost
unpredictably. ptr is among the
most DNS-expensive mechanisms in the protocol.
When to use: NEVER in
production. RFC 7208 section 5.5 quotes:
"Use of this mechanism is discouraged because
it is slow, it is not as reliable as other
mechanisms in cases of DNS errors, and it
places a large burden on the .arpa name
servers." If you find ptr in an
existing record, replace it with explicit
ip4 / ip6 /
a / mx /
include mechanisms targeting the
actual sending hosts.
Pitfalls: (1) Three
deprecation reasons documented in
RFC 7208 section 5.5: performance (multiple
PTR + forward lookups per evaluation),
reliability (in-addr.arpa nameservers
frequently SERVFAIL or return stale data,
producing transient SPF temperrors), and
trust model (relying on the IP holders DNS
for authorization shifts trust to an
infrastructure boundary SPF was not designed
to enforce). (2) Many receivers refuse to
evaluate ptr at all and treat
any record containing it as effectively
broken (some explicitly return
permerror). (3) Major mailbox
providers (Gmail, Microsoft 365) document
that ptr-based authorization
should not be relied upon and the
evaluation behavior is undefined.
2.7 The exists mechanism
Definition:
RFC 7208 section 5.7
(the same section as ip6 — note
the spec numbering quirk; exists
is in section 5.7 alongside ip6
but treated as a separate mechanism) defines
exists to match if a named
domain has ANY A record. The evaluator does
a single A query against the named domain;
if the query returns any A record (the
result is non-empty), the mechanism matches.
The actual A record contents are NOT compared
against the connecting IP — only the
existence of the A record is what is being
tested.
Syntax:
exists:<domain>. The
named domain is typically constructed
DYNAMICALLY at evaluation time using SPF
macros (RFC 7208 section 7), which substitute
the connecting IP, the sender, the helo
domain, and other SMTP context into the
domain string. Example:
exists:%{ir}.%{l}.%{d}.spf.example.com
expands to (for a connection from
198.51.100.5 to mail.example.com with
MAIL FROM: alice@example.com):
exists:5.100.51.198.alice.example.com.spf.example.com.
The domain owner publishes A records at the
composed name to dynamically authorize the
connection.
Lookup cost: ONE DNS lookup. Counts toward the 10-lookup cap.
When to use: Use
exists for dynamic per-sender or
per-IP authorization driven by an external
database — a common pattern is a custom DNS
zone where the domain owner stamps A records
at composed names whenever a new sender or
IP is authorized, and revokes them by removing
the A record. The SPF record stays unchanged
while authorization decisions move to the
external DNS zone. exists is
also used for COUNTERMEASURES against SPF
evaluation amplification attacks (where a
single SPF evaluation triggers many DNS
queries) — by returning predictable A records
only for known-good combinations.
Pitfalls: (1) Most operators
do not need exists — the dynamic
authorization patterns it enables are
specialized and most production deployments
are better served by static
ip4 / ip6 /
include mechanisms. (2) Macros
in exists targets can construct
VERY long DNS names that some resolvers
truncate — RFC 7208 section 7.1 limits
composed names to 253 octets but the
composition path is delicate. (3) An
exists mechanism with a macro
that resolves to NXDOMAIN counts as a VOID
LOOKUP — three voids return
permerror. Dynamic
exists deployments need to
publish a default A record at the
unauthorized name to avoid void-lookup
accumulation.
2.8 The include mechanism
Definition:
RFC 7208 section 5.2
defines include to recursively
evaluate the SPF record of a named domain
against the connecting IP, and match if and
only if the included evaluation returns
pass. Effectively
include:<domain> means
"authorize whatever <domain>s SPF record
authorizes". Operators use
include to delegate SPF
authorization to a third-party sender
(Microsoft 365, Google Workspace, an ESP, a
transactional service) without having to
enumerate the providers IP ranges by hand
and re-publish whenever the provider
changes them.
Syntax:
include:<domain>.
Examples: include:spf.protection.outlook.com
delegates to Microsoft 365 / Exchange Online;
include:_spf.google.com delegates
to Google Workspace / Gmail;
include:sendgrid.net delegates to
SendGrid; include:mailgun.org
delegates to Mailgun;
include:amazonses.com delegates
to Amazon SES.
Lookup cost: ONE DNS lookup
for the included records SPF TXT query PLUS
the recursive cost of every mechanism inside
the included record. include is
the MOST EXPENSIVE mechanism class because
the included record can itself contain
include mechanisms producing a
chain. Each nested include adds the cost of
ALL its mechanisms to the parent evaluation.
A typical Microsoft 365 include
(spf.protection.outlook.com)
flattens to one lookup at the top level (the
included record is published as a flat
ip4 / ip6 list). A
typical Google Workspace include
(_spf.google.com) is a NESTED
include chain (the included record contains
include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com)
consuming FOUR lookups out of the box (the
include itself plus three nested includes).
When to use: Use
include for every third-party
sender whose IP space you do not directly
control — ESPs, transactional services,
mailbox providers, marketing platforms,
helpdesk systems, CRM webhooks. The
include mechanism is the
canonical SPF delegation primitive.
Pitfalls: (1)
include is the #1 cause of
10-lookup-cap overruns — multiple providers
with deep nested chains routinely push
enterprise SPF records past the cap. See
SPF
lookup limit and flattening for the
focused deep dive. (2) include
requires the included record to PUBLISH
v=spf1 — including a record
that returns "none" (no SPF record published
at the included domain) returns
permerror, not
none. (3) include
is sometimes confused with
redirect= — the difference is
that include returns
pass when the included
evaluation passes and continues evaluation
otherwise, while redirect=
REPLACES the current evaluation with the
redirected one (RFC 7208 section 6.1).
include is the correct delegation
primitive for adding a sender;
redirect= is for handing off the
entire record. (4) include with
a malformed argument (typo, leading
whitespace, non-existent domain) returns
permerror — every published
include must be tested before
publication.
3. The four RFC 7208 qualifiers
RFC 7208 section 4.6.2 defines four qualifiers that prefix every mechanism and determine the result returned when that mechanism matches. Each subsection uses the canonical Definition / Syntax / Use-case / Pitfalls structure.
3.1 The + qualifier (pass — default)
Definition: the
+ qualifier means PASS — the
mechanism matching means the connecting host
IS authorized to send mail with this domain
in the envelope MAIL FROM. + is
the DEFAULT qualifier — if no qualifier is
prefixed to a mechanism, the evaluator
applies + implicitly.
Syntax: +<mechanism>
or equivalently <mechanism>
(the + is implicit). Examples:
+ip4:198.51.100.5 (explicit
pass), ip4:198.51.100.5
(implicit pass — same meaning),
+include:spf.protection.outlook.com
(explicit pass on Microsoft 365 inclusion),
include:spf.protection.outlook.com
(implicit pass — same meaning).
Use-case: the default for
every authorization mechanism in an SPF
record. + is so universal that
most published SPF records omit it
entirely and rely on the implicit default;
the only place + ever needs to
be explicit is for documentation clarity in
a record full of mixed qualifiers.
Pitfalls: (1) Publishing
+all authorizes EVERY internet
host to send mail with your domain — this
is the single most damaging SPF mistake;
it effectively disables SPF and tells
receivers your domain has no authorization
policy. Never publish +all in
production. (2) + on a
misconfigured mechanism (typo in
include: argument, wrong CIDR
range) still applies if the mechanism
matches the connecting IP — verify
mechanism arguments before publication.
3.2 The - qualifier (fail — hard fail)
Definition: the
- qualifier means FAIL (hard
fail) — the mechanism matching means the
connecting host is NOT authorized and the
receiver SHOULD reject the message. Hard
fail is the strongest SPF signal — most
receivers reject or quarantine the message
outright on - match.
Syntax:
-<mechanism>. Examples:
-all (the canonical production
terminator — reject every host not
explicitly authorized);
-ip4:198.51.100.0/24 (reject
every host in 198.51.100.0/24 — useful for
blocking a known-bad block that earlier
mechanisms would otherwise authorize);
-include:spf.expired-vendor.com
(reject every host the expired vendor
authorizes — defense-in-depth against an
expired include that should not have any
authorized hosts left).
Use-case: the recommended
terminator for every production SPF record.
-all declares to receivers that
any host not authorized by an earlier
mechanism is NOT authorized to send mail
with this domain — receivers should reject.
Most production records terminate with
-all.
Pitfalls: (1) -
before mechanism arguments not equal to
all is rare in practice — most
operators do not need explicit
- on non-terminal mechanisms.
(2) Switching from ~all to
-all too aggressively can break
forwarded mail (SPF fails on every
forwarded hop and -all
receivers may reject) — graduate from
~all to -all only
after DMARC aggregate reports confirm no
legitimate traffic depends on SPF passing.
DKIM coverage closes most of the forwarded-
mail concerns. (3) - qualified
IPs in the middle of a record can interact
with later + mechanisms in
ways operators do not expect — evaluation
is left-to-right, so the FIRST match wins;
-ip4:198.51.100.5 +ip4:198.51.100.0/24
rejects 198.51.100.5 specifically while
authorizing the rest of the /24.
3.3 The ~ qualifier (softfail)
Definition: the
~ qualifier means SOFTFAIL —
the mechanism matching means the connecting
host is PROBABLY not authorized but the
receiver SHOULD treat the result as a soft
signal rather than an outright rejection.
RFC 7208 section 8.5 explicitly says
"SoftFail messages typically would be
accepted but tagged" — Gmail typically
spam-folders softfailed mail; Microsoft 365
applies a higher spam score; Yahoo treats
it as a moderate negative signal.
Syntax:
~<mechanism>. Most
commonly used as ~all
(softfail-on-no-match terminator).
Use-case: the DEFAULT
terminator during the initial deployment of
a new SPF record or during a major change
(new sender added, IP range change, ESP
migration). ~all tells
receivers "I am still verifying my SPF
coverage is complete — treat unauthorized
traffic as a soft signal rather than
rejecting it outright". After the
deployment is stable and DMARC aggregate
reports confirm no legitimate sender is
failing SPF, graduate to -all.
Pitfalls: (1) Leaving
~all in production indefinitely
is a common mistake — operators publish the
soft terminator during the deployment ramp
and forget to harden to -all.
The result: receivers continue treating SPF
failures softly even when the record is
complete. Set a deadline for the
~all → -all
transition (typically 60-90 days after
DMARC p=none aggregate reports confirm full
coverage). (2) Some receivers (notably
legacy on-prem deployments) treat
~ identically to
? (neutral) — the softfail
signal is not universally honored. (3)
~all on a record with broad
+ip4 mechanisms means
"everything I have not explicitly listed
is suspect" — useful as a deployment ramp
but not as a permanent posture.
3.4 The ? qualifier (neutral)
Definition: the
? qualifier means NEUTRAL —
the mechanism matching means the domain
owner has NO opinion on whether this host
is authorized. The receivers SPF result
becomes neutral, which is the
same as the result returned when the
domain has no SPF record at all.
?all is therefore equivalent
to publishing no SPF record at all from a
protocol perspective.
Syntax:
?<mechanism>. Examples:
?all (neutral catch-all —
effectively no SPF policy),
?include:partner.example
(neutral on partner authorization — the
partner is neither authorized nor
unauthorized; receiver decides).
Use-case: Almost never in
production. The narrow legitimate uses are
(1) domains in active migration where the
domain owner does not yet have a policy
opinion, or (2) the rare case of an
inclusion the operator wants neither to
authorize nor explicitly forbid. Most
operators should pick +,
-, or ~ instead.
Pitfalls: (1) Publishing
?all tells receivers your
domain has no policy opinion — which is
IDENTICAL to publishing no record at all,
and worse than ~all for
deployment ramps. (2) Receivers treat
neutral and none
identically — there is no actionable
difference. (3) ? on the
terminal is a "I do not care" declaration —
if you do not care, do not publish an SPF
record at all; publishing ?all
gives receivers no useful signal.
4. The two RFC 7208 modifiers
RFC 7208 section 6
defines two MODIFIERS that extend the SPF record
beyond the basic mechanism list. Modifiers
differ from mechanisms in that they (a) do not
have a qualifier prefix, and (b) take the form
<name>=<value> rather
than <name>:<value>.
4.1 The redirect= modifier
Definition:
RFC 7208 section 6.1
defines redirect=<domain>
as a delegation modifier that REPLACES the
current SPF evaluation with the evaluation
of the named domains SPF record. The
evaluators result becomes the redirected
records result (pass, fail, softfail,
neutral, none, temperror, permerror).
Syntax:
redirect=<domain>.
Example:
v=spf1 redirect=_spf.example.com
delegates the entire SPF evaluation of the
current domain to _spf.example.coms SPF
record.
Lookup cost: ONE DNS lookup
for the redirected domains SPF record plus
the cost of every mechanism inside it.
Equivalent to a single top-level
include mechanism.
When to use: when an
organization manages SPF policy for many
domains centrally and wants every domains
SPF record to point to a single canonical
source. redirect= is the
cleaner pattern than embedding the same
include chain in every domains record.
Pitfalls: (1)
redirect= is MUTUALLY EXCLUSIVE
with the all mechanism — if
you use redirect=, you MUST
NOT include any all mechanism
in the same record (the redirected record
provides the terminal). (2)
redirect= is ignored if any
mechanism in the current record matches —
only one of the mechanisms or the redirect
executes, not both. (3)
redirect= to a domain without
a v=spf1 record returns
permerror. (4) Chained
redirects (one redirect-only record
pointing to another) work but multiply the
lookup budget — the cumulative cost is the
sum of every redirected records mechanism
costs.
4.2 The exp= modifier
Definition:
RFC 7208 section 6.2
defines exp=<domain> as
an EXPLANATION modifier that names a domain
whose TXT record provides a human-readable
message the receiver can include in a
bounce or fail-time diagnostic when SPF
returns fail. The explanation text supports
macro substitution like
exists targets do.
Syntax:
exp=<domain>. Example:
v=spf1 ip4:198.51.100.5 -all exp=spf-explain.example.com
with
spf-explain.example.com IN TXT "SPF check failed for %{i}; contact postmaster@%{d} for help."
returns a fail with the explanatory message
substituted at fail-evaluation time.
Lookup cost: ONE DNS lookup
ONLY when the receiver generates a fail-
explanation message. The
exp= lookup does NOT count
toward the standard 10-lookup evaluation
budget — it is evaluated only after the
main result is known and only if the
receiver opts to fetch it. Most receivers
do not fetch the explanation by default.
When to use: rarely.
exp= is useful when the domain
owner wants to surface a custom diagnostic
message in NDRs for SPF failures (e.g.,
"your mail server is not on our authorized
SPF list — contact postmaster@example.com").
Most receivers ignore exp= and
return their own diagnostic messages.
Pitfalls: (1) Receiver
support for exp= is
INCONSISTENT — many do not fetch the
explanation, so the modifier may have no
observable effect. (2) The
exp= target TXT record must
exist or the receiver MAY surface a generic
message; ensure the explanation TXT record
is published before publishing the
modifier. (3) Macros in the explanation TXT
produce LOG OUTPUT visible to attackers —
do not leak sensitive internal information
(do not include internal IPs, server names,
ticket IDs in the explanation).
5. Mechanism evaluation order: left-to-right, first-match-wins
RFC 7208 section 4.6.2 specifies that mechanisms are evaluated LEFT-TO- RIGHT in the order they appear in the SPF record. The FIRST mechanism that matches the connecting IP wins and the evaluator returns the matching mechanisms qualifier-derived result. Later mechanisms are NOT evaluated.
Concrete consequence: in a record like
v=spf1 -ip4:198.51.100.5 +ip4:198.51.100.0/24 -all,
a connection from 198.51.100.5 matches the
FIRST mechanism (-ip4:198.51.100.5)
and returns fail. The
+ip4:198.51.100.0/24 mechanism
later in the record would also match, but it
is NOT evaluated because the earlier
mechanism already won. This is the canonical
pattern for blocking a specific IP within an
otherwise-authorized prefix.
Reordering matters when overlapping
mechanisms have DIFFERENT qualifiers. If the
same record reordered the two ip4 mechanisms
as v=spf1 +ip4:198.51.100.0/24 -ip4:198.51.100.5 -all,
a connection from 198.51.100.5 matches the
BROADER +ip4:198.51.100.0/24
FIRST and returns pass — the
later more-specific -ip4:198.51.100.5
is never evaluated. The "specific overrides
general" rule from firewall configurations
does NOT apply to SPF; ordering does.
Practical guidance: put more-specific
mechanisms BEFORE more-general ones when the
qualifiers differ. Put the terminal
all mechanism LAST. Put zero-
lookup-cost ip4 and
ip6 mechanisms FIRST for
evaluation efficiency (the matching evaluator
returns immediately without resolving DNS for
the rest of the record). Note that the
10-lookup cap is enforced over the WORST-CASE
path through the record — an SPF evaluation
that matches on the very first mechanism
still has to be SYNTACTICALLY VALID across the
whole record (every mechanism in the record
is checked at publication time for compliance
with the lookup cap), but only the matching-
path lookups are actually executed at
evaluation time.
6. Cumulative lookup-cost accounting
RFC 7208 section 4.6.4 sets the SPF lookup budget at 10 DNS lookups per evaluation. Mechanisms and modifiers consume the budget at different rates, and operators must account for the WORST-CASE path (the unauthorized-IP terminal-fail evaluation that requires resolving every mechanism in the record).
Per-mechanism cost table:
| Mechanism / Modifier | Counts toward 10-lookup cap? | Cost per use |
|---|---|---|
ip4 |
No | 0 DNS lookups |
ip6 |
No | 0 DNS lookups |
all |
No | 0 DNS lookups |
a |
Yes | 1 DNS lookup (A/AAAA query) |
mx |
Yes | 1 + N DNS lookups (1 for MX, 1 per MX host, max 10) |
ptr (DEPRECATED) |
Yes | 1 PTR + 1 per PTR result (do not use) |
exists |
Yes | 1 DNS lookup (A query) |
include |
Yes | 1 + recursive cost of nested mechanisms |
redirect= |
Yes | 1 + recursive cost of redirected record |
exp= |
No (separate) | 1 DNS lookup ONLY when receiver fetches the explanation |
The separate 2-void-lookup cap (RFC 7208
section 4.6.4) tracks NXDOMAIN and empty results
independently. At most two mechanisms in the
entire chain (including nested includes and
redirects) may return a void result; the third
void returns permerror regardless
of whether the main lookup budget has been
exhausted. Operators using exists
with macros must publish a default A record at
the unauthorized name to avoid void-lookup
accumulation. See
SPF lookup
limit and flattening for the focused deep
dive on both caps and the four canonical
remediation paths (flattening, sender
consolidation, subdomain delegation, DKIM-first
alignment).
7. Worked deployment examples
Five concrete deployment patterns showing how the mechanisms compose. Each example states the sending estate, lists the SPF record, and walks the lookup-cost accounting.
Example 1: single on-prem mail server
Sending estate: one on-prem mail server at
198.51.100.5 handling all
outbound mail. No third-party providers. No
IPv6.
example.com. IN TXT "v=spf1 ip4:198.51.100.5 -all"
Lookup-cost accounting: ip4 costs
zero lookups; all costs zero
lookups. Total: 0 lookups. The record is
well under the 10-lookup cap.
Example 2: Microsoft 365 / Exchange Online tenant
Sending estate: Microsoft 365 Exchange Online handling all outbound mail. No on-prem relay. No third-party services.
example.com. IN TXT "v=spf1 include:spf.protection.outlook.com -all"
Lookup-cost accounting:
include:spf.protection.outlook.com
costs 1 lookup (Microsoft publishes the
record as a flat ip4 /
ip6 list — no nested includes).
Total: 1 lookup. Well under the cap. See
SPF
for Microsoft 365 for the provider deep
dive.
Example 3: Google Workspace tenant
Sending estate: Google Workspace / Gmail handling all outbound mail. No third-party services.
example.com. IN TXT "v=spf1 include:_spf.google.com -all"
Lookup-cost accounting:
include:_spf.google.com costs
1 lookup at the top level plus 3 NESTED
lookups (the included record contains
include:_netblocks.google.com
include:_netblocks2.google.com
include:_netblocks3.google.com). Total:
4 lookups. Well under the cap but burning
almost half the budget. See
SPF
for Google Workspace for the provider deep
dive.
Example 4: hybrid Microsoft 365 + transactional ESP
Sending estate: Microsoft 365 for end-user mail plus SendGrid for transactional and Mailgun for marketing.
example.com. IN TXT "v=spf1 include:spf.protection.outlook.com include:sendgrid.net include:mailgun.org -all"
Lookup-cost accounting: M365 include 1, SendGrid include 1, Mailgun include 1, plus any nested lookups each provider has in their record (1-2 nested lookups each is typical). Total: 3-7 lookups depending on each providers chain depth at evaluation time. Stays under the cap but the budget is filling up — adding more providers would push past 10.
Example 5: parked domain that sends no mail
Sending estate: a parked / inactive / acquired domain that should send no mail at all.
parked-example.com. IN TXT "v=spf1 -all"
Lookup-cost accounting: zero lookups. The
record declares "no host is authorized to send
mail with parked-example.com in the envelope
MAIL FROM". Pair with
v=DMARC1; p=reject; at
_dmarc.parked-example.com for the
strongest no-send posture. Every parked or
inactive domain owned by your organization
should have this pair published — see
DMARC
multi-domain strategy for the portfolio-
operator playbook.
8. The seven most common mechanism-level pitfalls
Across thousands of SPF records analyzed in DMARC aggregate-report data, the same seven mechanism-level mistakes recur. Each pitfall states the mistake, its operational symptom, and the fix.
- Publishing
+allas the terminator. Symptom: any host on the internet can pass SPF for your domain. Fix: never publish+all; use-all(production) or~all(deployment ramp). - Forgetting the
allterminator entirely. Symptom: receivers return the implicitneutralfor any non-matching host, which is no better than no record at all. Fix: always end every production record with-allor~all. - Using deprecated
ptr. Symptom: intermittenttemperrorfrom in-addr.arpa SERVFAIL, slow evaluations, some receivers refuse to honor the record. Fix: remove everyptrmechanism and replace with explicitip4/ip6/a/include. - Exceeding the 10-lookup cap.
Symptom: every evaluation returns
permerror, DMARC downgrades to fail, "SPF stopped working overnight" after adding a vendor. Fix: count lookups per the table in §6, flatten or consolidate senders or move to DKIM-first alignment. See SPF lookup limit and flattening. - Mixing
mxwith providerinclude:. Symptom: same providers IPs counted twice, lookup budget burned faster than expected, backup-MX servers (which never send) get accidentally authorized. Fix: pick ONE path — eitherincludefor cloud-provider deployments OR explicita/mxfor on- prem-managed mail flow. - Missing IPv6 address-family
coverage. Symptom: SPF passes
from IPv4 connections but fails from IPv6
(Gmail and Microsoft 365 increasingly use
IPv6 for SMTP). Fix: every IPv4 sending
host with an IPv6 address must have its
IPv6 address listed in
ip6too — or rely on providerincludewhich already covers both families. - Mixing
redirect=withall. Symptom:permerrorfrom publishing both modifiers in the same record. Fix: choose ONE —redirect=for full delegation (noall) OR explicit mechanism list with terminal-all(noredirect=).
9. FAQ
- What are the eight SPF mechanisms?
- RFC 7208 section 5 defines eight mechanisms an SPF record can use to authorize sending hosts: (1) all — matches every host, used as the terminal mechanism with a hard or soft qualifier; (2) ip4 — matches a literal IPv4 address or CIDR range, costs zero DNS lookups; (3) ip6 — matches a literal IPv6 address or CIDR range, costs zero DNS lookups; (4) a — matches the A or AAAA records of a named domain (default: the current domain), costs one DNS lookup; (5) mx — matches the A or AAAA records of every host listed in the MX records of a named domain (default: the current domain), costs one DNS lookup for the MX record itself plus one lookup per MX host (capped at 10 total per mechanism per RFC 7208 section 4.6.4); (6) ptr — matches the reverse-DNS PTR of the connecting IP and checks whether the resulting hostname matches the named domain, costs one PTR lookup plus one forward lookup per result and is explicitly DEPRECATED by RFC 7208 section 5.5; (7) exists — matches if a named domain has any A record (used for SPF macros and dynamic authorization), costs one DNS lookup; (8) include — recursively evaluates the SPF record of a named domain and matches if the included record passes, costs one DNS lookup for the includes own record plus the lookups of every mechanism inside it (the most expensive mechanism class and the #1 cause of 10-lookup-cap overruns).
- What are the four SPF qualifiers and what do they mean?
- RFC 7208 section 4.6.2 defines four qualifiers that prefix every mechanism and tell the receiver what result to apply when the mechanism matches: (1) + (pass, the default — the mechanism matching means the host IS authorized to send mail with this domain in the envelope MAIL FROM); (2) - (fail, hard fail — the mechanism matching means the host is NOT authorized and the receiver SHOULD reject the message); (3) ~ (softfail — the mechanism matching means the host is probably not authorized but the receiver SHOULD treat the result as a soft signal rather than an outright rejection, useful during a deployment ramp); (4) ? (neutral — the mechanism matching means the domain owner has no opinion on whether this host is authorized, equivalent to omitting the host from the record). Qualifiers prefix mechanisms with no space: -all means "fail if no earlier mechanism matched", +ip4:198.51.100.5 means "pass if the connecting IP is 198.51.100.5", ~include:_spf.example.net means "softfail if the included record matches". Most production SPF records terminate with -all (hard fail catch-all) or ~all (soft fail catch-all during deployment).
- What does the SPF include mechanism do?
- The SPF include mechanism (RFC 7208 section 5.2) recursively evaluates the SPF record of a named domain against the connecting IP and matches if the included record returns a pass result. Operators use include to delegate SPF authorization to a third-party sender (an ESP, a mailbox provider, a transactional email service) without having to enumerate that providers IP ranges by hand. Canonical example: v=spf1 include:spf.protection.outlook.com -all delegates authorization to Microsoft 365 by including the spf.protection.outlook.com SPF record, which Microsoft maintains as a flat list of Exchange Online sending IPs. include costs one DNS lookup for the includes own SPF record plus the lookups of every mechanism inside it — the included record is evaluated recursively and every nested include/a/mx/ptr/exists/redirect inside it counts toward the same 10-lookup cap. include is the #1 cause of 10-lookup-cap overruns because each include can pull in 1 to 5 nested lookups depending on the providers chain depth. If the included record returns permerror or temperror, RFC 7208 section 5.2 says the include mechanism returns the same error. include also requires the included record to publish v=spf1 — including a record that returns "none" (no SPF record published) returns permerror.
- How does the SPF a mechanism work?
- The SPF a mechanism (RFC 7208 section 5.3) matches if the connecting IP appears in the A or AAAA DNS records of a named domain. Without an argument, a defaults to the current domain — so a alone in v=spf1 a -all means "match if the connecting IP is one of the A/AAAA records of this domains apex". With an explicit argument (a:mail.example.com), it matches against that named domain instead. With a CIDR suffix (a/24 or a:mail.example.com/24), the match is broadened to the /24 prefix containing each resolved A record. a costs one DNS lookup against the 10-lookup cap. Operators use a when the mail server lives at the same IP as the web server (a means "include my main A record") — most useful for small single-server deployments. Pitfalls: a only resolves the named domains FIRST-LEVEL A records (it does not chase CNAMEs through to the final A — the resolver does that during normal DNS resolution); a does NOT include the IPs of hosts pointed to by MX records (use mx for that); a:mail.example.com does NOT recursively expand into another SPF record (use include for that).
- How does the SPF mx mechanism work?
- The SPF mx mechanism (RFC 7208 section 5.4) matches if the connecting IP appears in the A or AAAA DNS records of any host listed in the MX records of a named domain. Without an argument, mx defaults to the current domain. With an explicit argument (mx:example.net), it uses that named domains MX records instead. mx costs at least one DNS lookup for the MX record itself plus one lookup per MX host returned, capped at 10 per RFC 7208 section 4.6.4 (mechanisms that request more than 10 lookups MUST return permerror). Operators use mx when the same servers that receive mail for the domain also send mail for it — the legacy "my mail server is my mail server" symmetry. Pitfalls: (1) MX records typically list 2-5 hosts and mx counts EVERY one of them against the lookup cap — a small organization with 5 MX hosts spends 6 of the 10-lookup budget on the single mx mechanism, leaving only 4 lookups for everything else; (2) outsourcing inbound mail to a cloud filter (Proofpoint, Mimecast, Microsoft Defender for Office 365) replaces your MX hosts with the filter providers — mx then authorizes the FILTERS IPs to send AS YOU, which is rarely what you want; (3) using both mx and the providers SPF include can double-count IPs unnecessarily and burn the lookup budget.
- Why is the SPF ptr mechanism deprecated?
- RFC 7208 section 5.5 explicitly DEPRECATES the ptr mechanism. The mechanism matches if the reverse-DNS PTR record of the connecting IP resolves to a hostname under the named domain (and the forward A record of that hostname includes the connecting IP). Three reasons motivate the deprecation: (1) Performance and DNS load — every ptr evaluation requires a PTR lookup followed by a forward A lookup of every PTR result, which can produce dozens of DNS queries against the in-addr.arpa or ip6.arpa tree for a single SPF evaluation; (2) Reliability — many ASes do not publish accurate PTR records and DNS resolvers frequently return SERVFAIL or transient errors for in-addr.arpa lookups, producing intermittent temperror results; (3) Trust model — relying on reverse DNS for authorization places trust in the IP holders DNS infrastructure rather than the senders, which is not the same trust boundary SPF is designed to enforce. RFC 7208 section 5.5 explicitly says "Use of this mechanism is discouraged because it is slow, it is not as reliable as other mechanisms in cases of DNS errors, and it places a large burden on the .arpa name servers" and "If used, proper PTR records have to be in place for the domains MX hosts". Operators should remove every ptr mechanism from their SPF records and replace it with ip4 / ip6 / a / mx / include as appropriate.
- What does -all mean in SPF?
- The terminal mechanism -all in an SPF record (RFC 7208 section 5.1) means "no other mechanism in this record matched the connecting IP, therefore the result is fail (hard fail)". -all is the canonical SPF policy decision: the domain owner is asserting that hosts NOT explicitly authorized by earlier mechanisms are NOT authorized to send mail with this domain in the envelope MAIL FROM, and the receiver SHOULD reject the message. Receivers that honor SPF treat -all as the strongest negative signal — Gmail, Microsoft 365, Yahoo, and Apple all reject or quarantine -all failures by default. -all is the recommended termination for every production SPF record. Three softer alternatives exist: ~all (softfail — receiver SHOULD treat as a soft signal, useful during a deployment ramp), ?all (neutral — domain owner has no opinion, equivalent to no SPF record at all), and +all (pass — every host is authorized, equivalent to disabling SPF — never publish this in production). Note that DMARC alignment can pass via DKIM even when SPF returns fail, so -all does not on its own block forwarding-mangled SPF — that is what DMARC + DKIM are for. -all is a policy declaration, not an enforcement mechanism — DMARC provides the enforcement.
- What is the difference between SPF ip4 and ip6?
- SPF ip4 and ip6 are sibling mechanisms (RFC 7208 sections 5.6 and 5.7) that match the connecting IP against a literal IPv4 or IPv6 address or CIDR range respectively. Both cost ZERO DNS lookups — they are evaluated entirely from the SPF records own text, making them the cheapest mechanisms available. Syntax: ip4:198.51.100.5 matches the exact IPv4 address 198.51.100.5; ip4:198.51.100.0/24 matches any IPv4 address in the 198.51.100.0/24 prefix; ip6:2001:db8::1 matches the exact IPv6 address 2001:db8::1; ip6:2001:db8::/32 matches any IPv6 address in the 2001:db8::/32 prefix. Operators use ip4/ip6 when they directly control the sending IP space (an on-prem mail server, a dedicated cloud SMTP host, a static-IP transactional service). The "no DNS lookup" property makes ip4/ip6 the recommended SPF target after flattening — a flattened SPF record converts every include/a/mx into a flat list of ip4/ip6 mechanisms so the 10-lookup cap is no longer a constraint. Pitfalls: (1) literal IPs are brittle — every IP change requires re-publishing the SPF record (managed flatteners help here); (2) ip4 and ip6 are address-family specific — an ip4 mechanism does NOT match an IPv6 connection and vice versa, so dual-stack deployments need both; (3) overly broad CIDR ranges (ip4:0.0.0.0/0) authorize the entire internet — never publish this.
- How many DNS lookups does each SPF mechanism cost?
- RFC 7208 section 4.6.4 counts the DNS lookup cost of each mechanism toward the 10-lookup cap. The breakdown: (1) ip4 and ip6 cost ZERO lookups — they are evaluated from the SPF records text without DNS; (2) all costs zero lookups — it is the terminal catch-all; (3) a costs ONE lookup (the A/AAAA query for the named domain or current domain); (4) mx costs ONE lookup for the MX record itself plus ONE lookup per host listed in the MX record (a domain with 5 MX hosts spends 6 lookups on a single mx mechanism); (5) include costs ONE lookup for the included records SPF TXT plus the lookups of every mechanism inside the included record (recursively — include is the most expensive mechanism class); (6) exists costs ONE lookup; (7) ptr costs ONE PTR lookup plus ONE forward A lookup per result returned (ptr is also DEPRECATED by RFC 7208 section 5.5 — do not use); (8) the redirect= modifier (RFC 7208 section 6.1) costs ONE lookup (the redirected domains SPF record). The exp= modifier (RFC 7208 section 6.2) costs ONE lookup but ONLY when the receiver generates a fail explanation message — it does not count toward the standard evaluation budget. There is a SEPARATE 2-void-lookup cap (RFC 7208 section 4.6.4) — at most two mechanisms in the entire evaluation chain may return NXDOMAIN or empty result; the third void lookup returns permerror. See help_spf_lookup_limit.php for the full lookup-budget deep dive.
11. Verify your SPF mechanism record now
Once your SPF record uses the mechanism vocabulary correctly, verify it from three angles: live DNS lookup with the Domain Security Checker (parses your published record, flags 10-lookup overruns and deprecated mechanisms), live Authentication-Results inspection with the Email Header Analyzer (paste a header from a real delivery and see which SPF mechanism matched at the receiver), and ongoing DMARC aggregate- report monitoring through the platform dashboard (the aggregate reports surface sources passing and failing SPF over time, catching record drift and new senders before they cause deliverability incidents).
Check my SPF mechanism record Analyze an authentication-results header Sign up — Free plan