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.
Which Mechanisms Count, and Which Don't
| Mechanism | Counts Toward the 10? | Why |
|---|---|---|
include: | Yes — 1 per occurrence | Fetches another domain's TXT record and evaluates it recursively |
a | Yes — 1 per occurrence | Requires an A/AAAA lookup for the domain (or specified domain) |
mx | Yes — 1, plus 1 per returned MX host | First resolves MX records, then resolves each host's own address |
ptr | Yes — 1 per occurrence, deprecated | Requires a reverse DNS lookup, explicitly discouraged by RFC 7208 |
exists: | Yes — 1 per occurrence | Performs an A lookup purely to test existence, often used with macros |
ip4: / ip6: | No | Literal address ranges evaluated with no DNS query at all |
all | No | A fixed terminal match with no lookup required |
redirect= | Yes — 1, replaces the record entirely | Fetches and evaluates a different domain's record in place of the rest of the current one |
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.
The Void Lookup Limit Is a Separate Trap
Beyond the headline number of 10, RFC 7208 defines a second, stricter limit that catches people off guard even more often: no more than 2 of your lookups are allowed to come back completely empty — an NXDOMAIN or a query with zero answers. This exists specifically to stop a different kind of abuse: a record engineered to force the evaluator to repeatedly query domains that don't exist, wasting resolver time on failed lookups rather than useful ones. A record with a typo'd include domain, or one referencing a mail vendor's SPF hostname that was since retired, can trip this limit well before the main count of 10 becomes relevant.
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.
Realistic Ways to Fix a Record That's Over the Limit
| Fix | Effort | Trade-off |
|---|---|---|
| Remove unused vendor includes | Low | Fastest win; requires an honest audit of who actually sends mail on your behalf today |
Replace mx with explicit ip4/ip6 entries | Low–Medium | Removes a lookup but needs updating if your mail server IPs change |
| Flatten one or two heavy includes into static IPs | Medium | Cuts lookups sharply, but requires a process to re-sync IPs when the vendor changes theirs |
| Consolidate to fewer, better-chosen vendors | High | Best long-term fix, but requires actual operational or contractual changes |
Testing Before You Publish a Change
Any time you edit an SPF record specifically to address a lookup-count problem, verify the new count before treating the fix as done — not after DNS propagation completes and mail starts flowing again, but immediately, against the exact record text you're about to publish. A validator that recursively resolves every include the way a real receiving server would is the only reliable way to confirm you're safely under both the 10-lookup ceiling and the 2-void-lookup sub-limit at the same time, since fixing one without checking the other is a common half-fix.
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.
A Second Worked Example: Where the Count Sneaks Up
Take a record that looks deceptively safe: v=spf1 a mx include:_spf.google.com include:mailchimp.com include:eu.hs-send.com include:mktomail.com ~all. Counted naively at the top level, that's six mechanisms: a, mx, and four includes. Already close to the ceiling before any nesting is considered. Now expand each one. The a mechanism costs 1. The mx mechanism costs 1 plus one more for every MX host your domain publishes — two MX records means mx alone costs 3, not 1. Google's include typically resolves through two additional nested includes internally. Mailchimp's, HubSpot's regional sending domain, and Marketo's each carry their own internal structure too, some flatter than others. It's entirely plausible for this record, which looks like six lines, to resolve to 13 or more actual lookups once fully expanded — already a permerror, and one that would only be caught by actually tracing the whole tree rather than glancing at the record text.
Auditing on a Schedule, Not Just When Something Breaks
Because a large share of the lookup total lives inside domains you don't control, a record that passes today is not a guarantee it passes next month. Vendors restructure their SPF infrastructure more often than most domain owners expect — adding regional sending pools, splitting a single flat list into several nested includes for internal reasons, or migrating between infrastructure providers entirely. None of that requires you to touch your own DNS zone, and none of it produces a notification to you when it happens. The only way to catch a slow creep toward the ceiling before it becomes a live permerror is a periodic re-check, ideally automated, of the exact lookup total your record currently resolves to.
The Amplification Problem SPF Was Designed Around
To really understand why a hard ceiling was necessary rather than just a soft recommendation, it helps to think about the asymmetry involved. Publishing an SPF record costs the domain owner essentially nothing — a single DNS TXT entry, updated whenever needed. But every single piece of mail claiming to be from that domain, arriving at every mail server on the internet, triggers whatever DNS work that record demands. A domain that publishes a record requiring 50 recursive lookups isn't spending 50 lookups' worth of resources itself; it's forcing every receiving mail server, everywhere, to spend that much, on every message, indefinitely. That's a genuine amplification vector, structurally similar in spirit to other DNS-based amplification problems the internet has had to design around elsewhere. A flat, universal ceiling that every implementation enforces identically closes that door completely, rather than relying on individual receivers to each independently decide what a "reasonable" number of lookups looks like.
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.
Lookup Counting for MX Records With Many Hosts
The mx mechanism deserves a closer look because its lookup cost is the least intuitive of the countable mechanisms. Writing mx alone in a record doesn't cost a flat 1; RFC 7208 specifies that it costs 1 for the initial MX record lookup, plus one additional lookup for each of the resulting MX hostnames as their own A/AAAA records get resolved. A domain publishing three MX records, common for redundancy, means the mx mechanism alone consumes four lookups from your ten-lookup budget: one to fetch the MX list, three more to resolve each listed host. This is a specific, easy-to-miss detail, because a record's author often writes mx expecting it to behave like ip4 or a — a flat, predictable cost — when its actual cost scales directly with how many mail servers the domain happens to publish, information that isn't visible just by reading the SPF record text itself.
The Practical Difference Between a and mx in Terms of Lookup Risk
| Mechanism | Typical Lookup Cost | Risk Factor |
|---|---|---|
a | Flat 1, regardless of how many A/AAAA records the domain has | Low and predictable |
mx | 1 plus 1 per MX host, scales with your own mail redundancy setup | Moderate, worth checking directly against your actual MX record count |
a:otherdomain.com | Flat 1, resolves a specified domain instead of the current one | Low, but depends on a domain you may not control staying stable |
How the 10-Lookup Ceiling Interacts With DNSSEC-Signed Zones
For domains running DNSSEC, it's worth knowing that DNSSEC validation itself doesn't add to the SPF lookup count — the ceiling counts SPF-specific mechanism lookups as defined by RFC 7208, not the underlying DNSSEC chain-of-trust verification work a validating resolver might separately be doing to authenticate each response. The two systems operate independently: DNSSEC governs whether a receiving server can trust that the DNS answers it received weren't tampered with in transit, while the SPF lookup ceiling governs how many of those answers a single SPF evaluation is allowed to request in the first place. A domain can run a fully DNSSEC-signed zone and still exceed the SPF lookup ceiling in exactly the same way an unsigned zone would, and fixing one has no bearing on the other.
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.
Common, Entirely Accidental Sources of Void Lookups
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.
Historical Context: How the 10-Lookup Figure Was Chosen
Understanding a bit of the standards history behind SPF's lookup ceiling helps explain why it's treated as a hard, non-negotiable number rather than a soft guideline implementations are free to interpret differently. Earlier drafts of SPF's specification, before RFC 4408 and later RFC 7208 formalized the current rules, went through substantial community debate about exactly this kind of resource-bounding question, since SPF was one of the first widely deployed DNS-based email authentication mechanisms and the working group had limited prior art to draw on for how aggressively to bound recursive DNS work. The eventual consensus settled on a fixed number specifically because a fixed, universally enforced ceiling is far more useful for interoperability than a vague "reasonable amount" left to each implementation's own judgment — without a specific number, different mail servers could disagree about what's acceptable, producing exactly the kind of inconsistent, hard-to-diagnose behavior a protocol aiming for broad interoperability needs to avoid.
Comparing SPF's Approach to Other Email Authentication Protocols' Resource Bounds
| Protocol | Resource-Bounding Mechanism |
|---|---|
| SPF | Hard 10-lookup ceiling plus a separate 2-void-lookup sub-limit |
| DKIM | No equivalent DNS-lookup ceiling; a signature references exactly one selector, one lookup |
| DMARC | Relies on SPF and DKIM's own bounds; adds no independent DNS-lookup ceiling of its own |
This comparison highlights something worth understanding: SPF's lookup-recursion problem is fairly specific to its own mechanism design, where a single record can reference other records that reference still more records. DKIM's simpler, single-selector-per-signature lookup model doesn't have an equivalent recursive expansion problem, which is exactly why DKIM has no comparable ceiling to worry about — it's not that DKIM's designers considered and rejected a limit, but that DKIM's lookup structure never created the same category of risk SPF's recursive include mechanism does.
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.
What a Non-Compliant Implementation's Failure Looks Like in Practice
An SPF evaluator that fails to correctly enforce the lookup ceiling doesn't fail loudly or obviously — it simply continues evaluating past where a compliant implementation would have stopped and returned permerror, potentially completing an evaluation that a compliant, RFC-following implementation would have refused to complete. This creates a subtle interoperability problem: a domain's record might appear to work correctly when tested against one specific validation tool, while actually exceeding the ceiling and triggering a permerror at a different, correctly-compliant mail server elsewhere. This is a strong practical argument for testing SPF records against multiple independent, well-regarded validation sources rather than trusting a single tool's result as universally representative of how every receiving mail server will actually behave, since not every implementation in the wild necessarily enforces every rule with identical rigor.
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.
Related Reading in This Series
For a deeper look at how a single include mechanism resolves and what makes some vendors heavier than others, see SPF Include Mechanism. If you're specifically weighing whether to flatten your record into static IPs, read SPF Flattening. For the broader set of causes behind a permerror result beyond just the lookup count, see SPF PermError Fix. To check your current record's exact lookup count today, open SPF Lookup.
ToolsNovaHub tools are built and independently maintained with a focus on accurate, no-signup network and security utilities. 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 → |