If a DMARC report or a header check says spf=permerror or "too many DNS lookups", your SPF record is being ignored by some receivers, and mail that relied on it may fail authentication. The cause is a hard limit in the SPF specification that stacked include: entries exceed very easily. This guide shows you how to count lookups exactly, decide what to cut, and choose between pruning, subdomain splitting and flattening.
The rule, precisely
RFC 7208 limits SPF evaluation to 10 DNS-querying mechanisms and modifiers per check. Going over does not produce a soft warning; the result is permerror, and the receiver treats SPF as having failed to evaluate. What happens next depends on the receiver and on your DMARC policy, but you should assume that mail may be rejected or marked as suspicious.
What counts
These terms each cost one lookup when evaluated:
include:a(with or without a domain)mxptr(also discouraged by the RFC; avoid it)exists:- the
redirect=modifier
What does not count
ip4:andip6:, which are literal addresses and need no queryallv=spf1itself- the
exp=modifier, which is only used after a failure to fetch an explanation string
The detail that surprises people: nesting
The limit applies to the whole evaluation tree, not to your record alone. If you write include:_spf.provider.example, that is one lookup, but the provider's record might itself contain four more include: terms and several a or mx terms. All of those count against your total of 10.
Two further wrinkles:
- An
mxmechanism counts as one lookup toward the ten, but it also triggers address queries for each MX host. The specification separately caps those at 10 MX names per mechanism, and exceeding that is a permerror too. Somxis not free if you have many mail hosts. Check the result with a tool rather than by eye. - A mechanism that resolves to nothing is a "void lookup".
The void lookup limit
RFC 7208 also says that evaluating more than two lookups that return no data (an NXDOMAIN or an empty answer) should cause a permerror. So a record containing include: entries for services you cancelled, whose records no longer exist, can break SPF even if you are far below ten. Stale entries are doubly harmful: they spend your budget and can trip the void limit.
How to count lookups
Manual count
Take your record and walk it recursively.
dig TXT example.com +short | grep spf1
# "v=spf1 include:_spf.workspace.example include:spf.transactional.example include:spf.crm.example mx a -all"
Then expand each include:
dig TXT _spf.workspace.example +short
dig TXT spf.transactional.example +short
dig TXT spf.crm.example +short
Keep a tally: each include, a, mx, exists, ptr and redirect you meet, at any depth, adds one.
A worked example, with documentation names:
example.com v=spf1 include:_spf.workspace.example include:spf.transactional.example mx a -all
_spf.workspace.example v=spf1 include:_netblocks1.workspace.example include:_netblocks2.workspace.example ~all
_netblocks1.workspace.example v=spf1 ip4:198.51.100.0/24 ip4:203.0.113.0/24 ~all
_netblocks2.workspace.example v=spf1 ip6:2001:db8::/32 ~all
spf.transactional.example v=spf1 ip4:192.0.2.0/25 include:relay.transactional.example ~all
relay.transactional.example v=spf1 ip4:192.0.2.128/25 -all
The tally:
| Term | Count |
|---|---|
include:_spf.workspace.example | 1 |
include:_netblocks1.workspace.example (nested) | 2 |
include:_netblocks2.workspace.example (nested) | 3 |
include:spf.transactional.example | 4 |
include:relay.transactional.example (nested) | 5 |
mx | 6 |
a | 7 |
Seven out of ten, so one more provider with a similar structure would push it over. The ip4 and ip6 terms cost nothing.
Using a tool
The Email DNS Checker evaluates your SPF record and reports the lookup count, flagging void lookups and multiple SPF records. Cross-check by querying the individual includes with the DNS चेकर. Receivers may count slightly differently around edge cases, so leave headroom rather than sitting at exactly ten.
Fix it, in order of preference
1. Remove what you no longer use
This is the cheapest fix and often enough. Audit every include::
- Which services still send mail as your domain?
- Which were trials, former agencies, or retired tools?
Use DMARC aggregate reports (see the SPF, DKIM and DMARC guide) to see which senders are really active. Remove entries for services with no traffic, and confirm with the people who run them before deleting. This also removes void-lookup risk.
2. Replace a and mx with explicit addresses where stable
If your own mail server's address never changes, ip4:203.0.113.25 costs zero lookups, while mx costs at least one and more as your MX hosts multiply. Be careful: if the address changes and you forget to update SPF, mail will fail. Document the dependency.
Also drop a and mx if they are not needed. Many records include both out of habit. You only need mx if your inbound servers also send outbound mail, and a only if your web server sends mail.
3. Move senders to subdomains
Each domain and subdomain gets its own SPF record with its own budget of ten. Marketing platforms and transactional services can send as news.example.com or mail.example.com, with their own SPF record and DKIM, instead of piling into the root.
example.com. IN TXT "v=spf1 include:_spf.workspace.example -all"
news.example.com. IN TXT "v=spf1 include:spf.newsletter.example -all"
app.example.com. IN TXT "v=spf1 include:spf.transactional.example -all"
Remember that DMARC alignment still has to work: using the subdomain in the From address (news@news.example.com) means relaxed alignment will accept it under the organisational domain. This is the cleanest long-term fix because it also isolates reputation between mail streams.
4. Use a redirect or a single provider where possible
If a whole domain sends only through one provider, v=spf1 redirect=_spf.provider.example is one lookup and delegates the entire policy. Note that redirect= is ignored if the record also contains an all mechanism, so use one or the other.
5. Flatten, with open eyes
Flattening replaces include: terms with the ip4:/ip6: ranges they currently resolve to, taking the lookups to zero. It works, but carries real costs:
- Providers change their IP ranges. A flattened record is a photograph; the next time the provider adds a server, your copy is out of date and legitimate mail starts failing.
- Record size: a long list of addresses can exceed the 255-character limit of a single TXT string (you must split it into multiple quoted strings inside one record) and approach the 512-byte UDP response size that older resolvers expect. Very large records push responses into TCP or truncate, and some DNS hosts impose their own limits.
- Manual maintenance does not scale. If you flatten, automate it: a scheduled job or a managed flattening service that re-resolves includes and republishes when ranges change, with alerting if that job fails.
Flatten only the senders whose ranges are stable, and keep include: for the ones that change often. A hybrid is perfectly acceptable.
Step-by-step procedure
- Capture the current record and save the output.
- Run the lookup counter in the Email DNS Checker to see your total and any void lookups.
- List every sender and check each against recent DMARC reports. Mark which are active.
- Delete dead includes and re-test.
- Replace
a/mxwithip4/ip6where addresses are stable. - If still near the limit, move bulk or transactional senders to subdomains, giving each a record and DKIM.
- Consider flattening only what remains if it is stable, with automation.
- Publish a single record. Never leave two SPF TXT records. Edit the existing one.
- Re-test: send mail through each remaining sender to the ईमेल डिलीवरेबिलिटी टेस्ट and confirm
spf=pass. - Watch DMARC reports for a week or two for failures you missed.
You can draft a clean record with the SPF & DMARC Generator, but confirm the lookup count yourself afterwards because generators cannot know what third-party includes will expand to in future.
Mistakes that keep the problem alive
- Adding an
include:every time a tool asks, without removing old ones. - Leaving
ptrin the record from legacy templates. It is slow, unreliable and counts toward the limit. - Counting only top-level terms and ignoring nested includes.
- Publishing a second SPF record "just for the new tool". Multiple SPF records are a permerror in themselves.
- Treating
~allversus-allas a lookup issue. It is not related; the lookup limit is hit before the ending matters. - Forgetting that the
redirect=target's lookups count too.
अगले कदम
- Recount lookups after every change with the Email DNS Checker.
- Build or compare records with the SPF & DMARC Generator.
- Read the full authentication picture in SPF, DKIM and DMARC: a complete guide.
- If mail still fails despite valid SPF, check your sending IP with the Blacklist Checker and the blacklist removal guide.
सामान्य प्रश्न
What happens when SPF exceeds 10 lookups?
The evaluation returns permerror. Receivers differ in how they treat it, but SPF cannot be relied upon to pass, and DMARC will then depend entirely on DKIM alignment. Some mail may be rejected or filtered.
Do ip4 and ip6 mechanisms count toward the limit?
No. Neither do all nor the v=spf1 marker. Only terms that require DNS queries, namely include, a, mx, ptr, exists and redirect, are counted.
Do nested includes count?
Yes. The limit applies to every DNS-querying term encountered while evaluating the full chain, including terms inside the records your includes point to. A single include: can cost several lookups.
Is SPF flattening a good idea?
It can be, for small stable sets of addresses, but a static flattened record goes stale when providers change ranges. If you flatten, automate regeneration and alert on failure, or prefer moving senders to subdomains.
What is the void lookup limit?
RFC 7208 says that more than two lookups returning no data (NXDOMAIN or an empty answer) should produce a permerror. Stale include: entries for services that no longer publish SPF are the usual cause.
Get notified when this guide updates
Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.
यह पेज सामान्य जानकारी है, जिसे हमारी संपादकीय टीम ने लिखा है और दस्तावेज़ीकरण बदलने पर अपडेट किया जाता है। सर्वर और प्रदाता अलग-अलग होते हैं, इसलिए बदलाव पहले सुरक्षित तरीके से जाँचें। देखें: संपादकीय नीति और अस्वीकरण.