SPF looks simple — a TXT record listing authorized senders — until an organization accumulates enough third-party sending services that the record silently breaks in a way that's invisible until a specific message happens to trigger it. This article covers SPF's actual mechanics and the failure modes that come up in real assessments.
SPF mechanisms
An SPF record is built from mechanisms evaluated left to right, each one either matching the sending IP or not:
| Mechanism | Meaning |
|---|---|
ip4: / ip6: | A specific IP address or range is authorized |
a | Any IP address the domain's own A record resolves to is authorized |
mx | Any IP address listed in the domain's MX records is authorized |
include: | Delegates to another domain's SPF record — the mechanism responsible for most real-world complexity |
redirect= | Replaces the entire record's evaluation with another domain's SPF record |
all | Matches every remaining IP not matched above — always the last mechanism |
The qualifier on all is the whole point of the record
Every mechanism can be prefixed with a qualifier controlling what happens on a match. On all specifically, this qualifier is the record's actual enforcement decision:
-all(hard fail) — IPs not explicitly authorized should be rejected. This is the target state for a mature configuration.~all(soft fail) — unauthorized IPs are flagged but not necessarily rejected outright; treated as suspicious by receiving servers rather than blocked.+all(pass) — authorizes any server to send as the domain. This is a real, serious misconfiguration, not a relaxed setting — it defeats the purpose of having an SPF record at all. Any assessment finding+allshould treat it as a priority-one issue.?all(neutral) — explicitly states no policy; functionally similar to having no SPF record for enforcement purposes.
A record ending in +all is not a weaker version of SPF — it authorizes spoofing
+all tells receiving servers that literally any sending server is authorized. It is functionally equivalent to having no SPF protection, and worse than having none in the sense that it can create false confidence that the domain is protected.
Include chains and recursive dependencies
Most organizations don't send all their mail from infrastructure they control directly — they use Microsoft 365, a marketing platform, a support ticketing system, a CRM, each of which requires an include: mechanism pointing at that vendor's own SPF record. Each included record is evaluated by walking into it and evaluating its mechanisms, which may themselves include further records.
This is where the majority of real-world SPF problems originate: the record that looks like five or six lines in your DNS panel can represent a much deeper dependency tree once every include is actually walked.
The 10 DNS lookup limit
SPF's specification imposes a hard limit of 10 DNS lookups during evaluation (RFC 7208). Mechanisms that require a lookup include include, a, mx, redirect, exists, and ptr (the ptr mechanism is additionally deprecated and should not be used at all in new configurations). ip4/ip6/all do not count against the limit.
This limit is not a soft guideline — exceeding it causes SPF to fail with a permerror, which many receiving mail systems treat as equivalent to an outright SPF failure for the entire domain, not just a partial or degraded result. An organization can have an SPF record that is syntactically perfect, lists every legitimate sender correctly, and still fail SPF universally because the total lookup count across all nested includes exceeds 10.
The practical danger is that this failure mode is invisible until it happens: adding one more include: for a new SaaS tool can be the lookup that pushes a previously-working record over the limit, and the record will look completely normal on inspection — the problem only shows up in actual evaluation.
Multiple SPF records is also a real misconfiguration
A domain must have exactly one SPF record. If two TXT records both start with v=spf1 (often the result of a new tool's setup instructions telling someone to "add this SPF record" without checking whether one already exists), the result per RFC 7208 is a permanent error — not "the two records get combined" and not "the first one wins." Both are invalidated.
Practical troubleshooting checklist
- Confirm there is exactly one SPF record on the domain (search all TXT records, not just the one you expect).
- Walk the full include chain and count total lookups — don't estimate from the top-level record's visible line count alone.
- Confirm the
allqualifier matches your actual enforcement intent — flag+allimmediately as a priority finding. - Remove includes for services no longer in use — a common source of both wasted lookup budget and stale authorization.
- If approaching the lookup limit, consult your DNS/email provider about supported flattening or restructuring approaches rather than removing legitimate senders to save lookups.
Practical next steps
Run IT KORR's SPF/DKIM/DMARC Checker — it recursively walks your actual include chain and reports an estimated lookup count, rather than requiring manual counting. For how SPF fits with DKIM and DMARC as a complete system, see Email Authentication Architecture.