SPF: too many DNS lookups
Past ten DNS lookups, SPF does not degrade. It returns permerror, and receivers treat that exactly like a domain with no SPF at all — while your record still reads perfectly fine.
Recognising the problem
This failure is unpleasant precisely because nothing looks broken. Your SPF record is syntactically valid. It lists the right servers. You can read it, and everything in it is correct.
What you see instead:
- Legitimate mail from one provider starts landing in spam, often just one provider, often after adding a new tool.
- DMARC aggregate reports show spf=permerror, or spf=none, for sources you know are yours.
- An online SPF checker reports "too many DNS lookups" or "permerror", while a plain syntax validator says the record is fine.
The two tools disagree because they answer different questions. A syntax validator asks whether the record is well-formed. Evaluating the lookup limit means actually resolving the record, recursively, the way a receiving server does.
One consequence worth stating plainly: if you have DMARC, permerror means the SPF half of your authentication is gone. Everything then rests on DKIM alone, and any source that does not sign will fail.
Why the limit exists
SPF is evaluated by the receiving server, at delivery time, for every message. Each include: it encounters means another DNS query, and those includes can nest.
Without a ceiling, a maliciously crafted record could make any receiver perform hundreds of lookups per message, turning every mail server on the internet into an amplifier pointed at whatever nameserver the attacker chose. The limit is a denial-of-service protection, not an arbitrary constraint, which is why no receiver will raise it for you.
RFC 7208 sets it at ten. It is a hard ceiling, applied to the fully expanded record, and exceeding it is a permanent error rather than a partial evaluation.
A second, less known limit sits alongside it: at most two void lookups, meaning queries that return no record at all. An include: pointing at a provider you stopped using, whose record has since been deleted, burns one of those two.
Counting your lookups
Only some mechanisms cost a lookup. This is the part that surprises people, and knowing it changes what you optimise.
- Costs one lookup each: include, a, mx, ptr, exists, and the redirect= modifier. Nested includes add their own.
- Costs nothing: ip4, ip6, and all. They resolve to literals, so the receiver queries nothing.
That asymmetry is the whole game. Every include: you can turn into ip4: is a lookup recovered.
What providers actually cost The published figure for a provider is rarely the real one, because their record includes others. Google Workspace is the classic example: include:_spf.google.com is one lookup on the surface, but it expands into three further netblock includes, so roughly four in total. Microsoft 365 is cheaper, generally one or two.
Add a marketing platform, a transactional sender and a ticketing tool, and you are past ten having added nothing unusual.
Doing the count Read your record first:
dig +short TXT example.com | grep spf1Then resolve each include: in turn and count what it contains. Doing this by hand once is worth the twenty minutes, because it shows you exactly where your budget goes rather than giving you a number. After that, use a checker that reports the expanded count.
Cutting without breaking anything
Work in this order. The early steps are free, and they often solve the problem on their own.
1. Remove what you no longer use This is almost always the biggest win, and it is the least risky. Organisations accumulate senders: a trial platform from two years ago, a newsletter tool replaced last spring, a CRM that was migrated. Each left its include: behind.
Cross-check every include: against your DMARC reports. A source that has sent nothing in months is a candidate for removal, and removing it costs nothing if you were right.
2. Prefer the narrowest include a provider documents Several providers publish both a broad record covering their whole platform and a narrower one for the specific service you use. The narrow one usually costs fewer lookups. Check their documentation rather than copying the value from a forum post.
3. Replace a and mx with explicit addresses If your mail servers have stable addresses, mx costs a lookup that ip4: does not. The trade-off is real: you now have to update the record when the address changes. Do it where the address genuinely never moves, not everywhere.
4. Drop ptr entirely The ptr mechanism is deprecated by the RFC, slow, and unreliable. If it is in your record, it should not be.
The fix nobody suggests: delegate to subdomains
The steps above buy you room. This one changes the shape of the problem, and it is the answer for an organisation that genuinely has many senders.
The ten-lookup limit applies per domain being evaluated. A subdomain is a different domain for this purpose, with its own budget.
So instead of one record carrying everything:
example.com "v=spf1 include:_spf.google.com include:marketing include:crm include:billing -all"send each family of mail from its own subdomain, each with its own record:
example.com "v=spf1 include:_spf.google.com -all"
news.example.com "v=spf1 include:marketing-provider.net -all"
billing.example.com "v=spf1 include:billing-provider.net -all"Your corporate mail keeps the apex and stays well under the limit. Each platform gets its own budget, and none can push the others over.
Three further benefits make this worth the migration effort:
- A deliverability problem on marketing mail stops contaminating the reputation of your invoices and your day-to-day correspondence.
- Your DMARC reports become readable, because each subdomain reports separately.
- Adding a platform next year no longer means re-auditing the whole record.
The cost is real: every sending platform has to be reconfigured to use the new From domain, and DKIM has to be set up for each subdomain. Plan it as a migration, not an afternoon. But it is the only fix that does not need redoing the next time someone signs up for a tool.
Flattening, and what it really costs
Flattening means resolving every include: yourself and writing the resulting IP ranges directly into your record. Lookups drop to zero, because ip4: costs nothing.
"v=spf1 ip4:35.190.247.0/24 ip4:64.233.160.0/19 ip4:66.102.0.0/20 ... -all"It works, and it is sometimes the only option left. Be clear about what you are taking on.
You have converted a record that your providers maintained into one that you maintain. When Google, Microsoft or your ESP changes their ranges, and they do, your record is silently wrong. Mail from an address they added last week fails your own SPF. Nothing warns you, and the symptom looks exactly like the problem you just fixed.
There is also a length ceiling to watch: a DNS TXT record is capped at 255 characters per string, and the practical limit for a whole SPF record is 512 bytes before responses start fragmenting. Flattened records approach it quickly.
So: flatten only if you cannot delegate, use a service that re-flattens automatically and alerts on change rather than a one-off manual expansion, and diary a quarterly review. A flattened record left alone for a year is a deliverability incident waiting for its moment.
Checking that it is actually fixed
Re-read the record, confirm the expanded count is at ten or below, then verify against reality rather than against a tool.
dig +short TXT example.com | grep spf1The check that matters is your DMARC aggregate reports. Give it a week: permerror should disappear, and every legitimate source should show spf=pass with alignment. A checker tells you the record is valid; the reports tell you what receivers actually did with your mail.
Then keep it from happening again. The mechanism that works is procedural, not technical: make SPF a step when a new sending platform is adopted. Every tool that sends on your behalf needs an entry, and every tool retired needs its entry removed. Most records go over the limit because the first half of that rule is followed and the second is not.
Frequently asked questions
What counts toward the ten SPF lookups?
The mechanisms include, a, mx, ptr and exists, plus the redirect= modifier, each cost one lookup, and nested includes add their own on top. The ip4, ip6 and all mechanisms cost nothing, because they resolve to literals and require no query. That asymmetry is what makes flattening work, and it means every include: converted to ip4: recovers a lookup.
What happens when the limit is exceeded?
The evaluation returns permerror, a permanent error, and receivers treat permerror much as they treat a domain with no SPF record at all. Nothing partial is salvaged. If you publish DMARC, the SPF half of your authentication is gone and everything rests on DKIM, so any source that does not sign will fail outright.
Should I flatten my SPF record?
Only if you cannot delegate to subdomains first. Flattening converts a record your providers maintained into one you maintain: when they change their IP ranges, and they do, your record is silently wrong and legitimate mail starts failing with no warning. If you do flatten, use a service that re-flattens automatically and alerts on change, and review it quarterly.
Does a subdomain get its own lookup budget?
Yes. The limit applies per domain being evaluated, and a subdomain counts as a different domain. Sending marketing mail from news.example.com with its own SPF record leaves your apex record short and safe. It also stops a deliverability problem on one channel from contaminating the others, and it makes DMARC reports far easier to read.
See where your own domain stands
A free, fully passive scan. Public data only, no intrusion, no account required.
Scan my domain