The SPF 10 DNS Lookup Limit, Explained Properly
Why RFC 7208 caps SPF at 10 DNS-querying mechanisms, exactly which parts of your record count toward that number, and what actually happens the moment you go over.
What the Limit Actually Protects Against
SPF was designed at a time when mail servers already had plenty of reasons to be cautious about how much work an inbound message could trigger before it was even accepted. Every SPF check requires the receiving server to go out, query DNS, interpret what comes back, and sometimes query DNS again based on that answer. Without a ceiling, a malicious or simply badly configured domain could publish an SPF record that forces every mail server on the internet receiving its mail to perform dozens or hundreds of recursive DNS lookups on every single message β a cheap, repeatable way to waste other people's infrastructure. RFC 7208 closes that door with a flat, non-negotiable number: 10 DNS-querying mechanisms per SPF check, no exceptions.
It's worth being precise about what "10" actually refers to, because this is where most people misjudge their own record. It isn't 10 characters, 10 IP ranges, or 10 lines in the TXT record. It's 10 mechanisms that individually trigger a DNS lookup during evaluation, counted as the validator walks through your record and any records it points to, recursively, left to right, until it either finishes evaluating or hits the ceiling.
Counting a Real Record by Hand
Take a fairly ordinary small-business SPF record: v=spf1 include:_spf.google.com include:sendgrid.net include:spf.protection.outlook.com a mx ~all. On the surface that's four countable mechanisms β two includes, an a, and an mx β which looks comfortably under 10. But each include doesn't just cost 1; it costs 1 plus whatever the target domain's own record costs when evaluated. Google's _spf.google.com alone typically resolves through several nested includes internally, and Microsoft's Outlook include does the same. By the time recursive evaluation finishes, that four-mechanism-looking record can easily land at 9 or 10 real lookups, sometimes more depending on what those vendors currently publish.
This is exactly why manually eyeballing a record's top-level mechanism count is unreliable. The only trustworthy way to know your real number is to trace every include recursively, the same way a validating mail server would, which is precisely what a proper SPF checking tool does automatically.
What Happens the Moment You Cross 10
SPF evaluation is not tolerant of exceeding the limit in any partial or graceful way. The moment the evaluator would need to perform an 11th DNS-querying mechanism, RFC 7208 mandates the result is permerror, full stop β not a fallback to neutral, not "best effort" against the first 10. A permerror tells the receiving mail server that your domain's SPF record is, from a technical standpoint, broken, and RFC 7208 explicitly notes that receivers may choose to reject mail on a permerror rather than accept it, exactly the outcome a properly configured SPF record was supposed to prevent.
In practice this means a record that worked fine for months can start silently failing the moment a single vendor's include grows by one more nested lookup on their end β something entirely outside your control, and something that won't show up until deliverability quietly drops and someone finally goes and reads the aggregate DMARC reports.
Why 10 and Not Some Other Number
People sometimes assume the number 10 was picked to be generous, room for a handful of vendors plus your own infrastructure. In reality it reads more like a compromise between two competing pressures the working group had to balance. Set the ceiling too low and legitimate organizations with several genuinely necessary mail-sending vendors would be structurally unable to publish a compliant record without resorting to workarounds. Set it too high and the protection against amplification β a small SPF check triggering a large amount of downstream DNS work β becomes meaningless. Ten sits at a point where a well-run small-to-mid-size organization can usually fit their real needs in, while a record trying to authorize dozens of loosely-tracked senders gets pushed toward consolidation, which is arguably a healthier outcome for the sender's own security posture anyway. A domain with an SPF record that would need 30 or 40 lookups to fully express probably has a sprawling, poorly audited set of authorized senders regardless of what SPF's limit says.
How the Evaluator Walks Through Your Record
It helps to actually picture the evaluation order, because it explains some behavior that otherwise looks confusing. SPF evaluation is strictly left to right through the mechanisms in your top-level record. When it hits an include, it doesn't finish reading your record first and then go check the include afterward β it pauses right there, fetches the target record, and recursively evaluates that record's mechanisms in the same left-to-right order, including any nested includes inside it, before returning to continue with whatever comes after your original include mechanism. This is why the running lookup count is a depth-first tally, not a breadth-first one: a single include with three levels of nesting inside it is fully resolved, lookups and all, before the evaluator ever looks at your record's second mechanism.
This also explains why placement matters for efficiency even though it doesn't change correctness. If your highest-volume vendor's include sits last in the record, and every one of your other mechanisms needs to be checked and fail to match before reaching it, then the "average case" lookup cost for your actual mail traffic is higher than the record's theoretical maximum would suggest, since most real checks are walking past several non-matching mechanisms first.
How Different Receivers Actually Handle the Ceiling in Practice
RFC 7208 mandates the permerror result when the ceiling is exceeded, but it deliberately leaves what happens next up to local policy at the receiving server. In practice, the large mailbox providers you're most likely to care about tend to treat a permerror as a meaningfully negative signal, often folding it into broader reputation and filtering decisions rather than issuing a hard, deterministic bounce every time. Smaller or more strictly RFC-compliant mail systems are more likely to reject outright on a permerror. This variance means the practical consequences of exceeding the limit aren't perfectly uniform across the mail ecosystem, but it also means you can't rely on "well, my mail to Provider X still seemed to go through" as evidence a permerror isn't actually happening β different providers make different choices about how visibly they penalize it, and a record that's technically broken today may just not have produced an obviously broken outcome at whichever provider you happened to test against.
Void Lookups Deserve Their Own Careful Walkthrough
The void lookup sub-limit is easy to skim past as a footnote to the main 10-lookup ceiling, but it operates on genuinely different logic and deserves to be understood on its own terms. A void lookup isn't about how many mechanisms you have; it's specifically about how many of your countable lookups come back with nothing at all β either an NXDOMAIN response (the queried name doesn't exist in DNS) or a response with zero answer records for the query type SPF needs. RFC 7208 caps this at 2 for the entirety of a single SPF evaluation, counted across every level of nesting, independent of the main 10-lookup tally. A record could theoretically have only 4 total lookups, comfortably under the main ceiling, and still permerror if 2 of those 4 happen to resolve to nothing.
The rationale mirrors the main limit's amplification concern but targets a slightly different abuse pattern: a record engineered to reference a long chain of intentionally non-existent domains forces a validating resolver to spend time on failed lookups specifically, which behave differently in terms of caching and resolver load than successful ones. Capping void lookups at 2 closes that variant of the same underlying concern.
How to Actually Check Your Void Lookup Count
Unlike the main lookup count, which you can reason about by simply tallying mechanism types, checking for void lookups requires actually resolving each countable mechanism and inspecting whether the response came back empty. This is not something you can determine by reading the record's text alone β two records with identical syntax could have completely different void-lookup outcomes depending on whether their referenced domains currently resolve. A proper validator performs this resolution automatically and reports it as a distinct figure alongside the main lookup count, which is the only reliable way to know your actual exposure without manually querying every single include, a, mx, ptr, and exists target by hand and checking each response individually.
What a Full Recursive Trace Output Actually Looks Like
It's worth seeing what a genuinely complete recursive trace looks like, rather than just describing the process abstractly, since this is exactly the kind of output a proper validation tool should surface. For a record like v=spf1 include:_spf.google.com include:sendgrid.net ~all, a full trace would report something structured roughly like: top-level record, 2 include mechanisms found. Resolving include:_spf.google.com β found 3 nested includes, 0 direct ip4/ip6 β recursing. Resolving each of those 3 β 2 return only ip4/ip6 ranges (0 further lookups each), 1 returns 1 more nested include β recursing further β that final layer returns only ip4/ip6 ranges. Running total from the Google chain: 5 lookups (1 initial + 3 second-level + 1 third-level). Resolving include:sendgrid.net β found 0 nested includes, direct ip4/ip6 ranges only β 1 lookup. Grand total: 6 lookups, comfortably under the 10-lookup ceiling, with 4 lookups of headroom remaining. This level of explicit, layer-by-layer accounting is what separates a genuinely trustworthy validation result from a superficial one that only reports the final number without showing its work.
Why the Lookup Limit Sits at the SPF Layer and Not at the DNS Layer
It's worth clarifying a distinction that occasionally causes confusion: the 10-lookup ceiling is not a DNS protocol limit at all β DNS itself places no restriction on how many queries a client can issue for a single evaluation task, and there's no DNS-level mechanism that would refuse a domain's eleventh lookup. The limit is entirely an SPF specification-level rule, enforced by whatever SPF evaluation logic is running (inside a mail server's own code, a library, or a validation tool), not by the DNS resolver or DNS servers being queried. This matters practically because it means the limit is only as reliable as the correctness of whatever specific software is doing the enforcing. A poorly implemented SPF library that doesn't correctly track and cap the running lookup count during recursive evaluation could, in principle, exceed the specified ceiling without DNS itself doing anything to stop it, which is exactly why RFC 7208 places the burden of correct enforcement squarely on implementations, and why using well-established, widely-deployed SPF libraries (rather than a custom, less-tested implementation) matters for getting this specific behavior right in production mail systems.
The Relationship Between Lookup Count and DNS Query Timeout Behavior
A related, less commonly discussed consideration: each individual DNS lookup within an SPF evaluation carries its own timeout behavior, and a record with many lookups β even one that stays technically under the 10-lookup ceiling β accumulates more total time spent waiting on DNS responses than a leaner record does. Most of the time this accumulated latency is negligible, measured in milliseconds per lookup under normal DNS conditions. But under degraded network conditions, a slow or partially unresponsive DNS server on the vendor's end, or unusual resolver load on the receiving mail server's side, a record with several includes chained together can produce noticeably slower overall SPF evaluation than a lean record would, in the worst case risking a timeout on the SPF check itself before all lookups complete. This is a secondary, performance-oriented reason (distinct from the hard permerror risk) to keep a record's lookup count comfortably below the ceiling rather than treating "under 10" as the only threshold worth caring about.
ToolsNovaHub guides are researched against primary sources (RFCs, vendor docs) and kept up to date as standards change. Spotted an error? Let us know.
π Related Tools & Guides Comparison
| Resource | Type | Link |
|---|---|---|
| SPF Lookup | Tool | Open Tool β |
| SPF Include Mechanism | Guide | Read Guide β |
| SPF Flattening | Guide | Read Guide β |
| SPF PermError Fix | Guide | Read Guide β |
| SPF Record Optimization | Guide | Read Guide β |