Learn · Fixing a record
SPF PermError: too many DNS lookups
Your SPF record is valid, your senders are all listed, and receivers are returning permerror anyway. The cause is a hard limit in the specification: evaluating an SPF record may cost at most ten DNS lookups, and yours costs more. This is worse than having no SPF record at all, because a permanent error makes receivers stop evaluating SPF entirely — including for the mail that would have passed.
Count where you stand first: the free SPF record checker resolves your record the way a receiver does and tells you the number, plus which includes are expensive.
Which mechanisms actually cost a lookup
This is where most manual counts go wrong. Only some mechanisms spend from the budget:
| Costs a lookup | Free |
|---|---|
include: | ip4: |
a and a: | ip6: |
mx and mx: | all |
exists: | v=spf1 |
redirect= | modifiers like exp= |
ptr (deprecated — remove it) |
Two things make the real number much larger than the record looks:
- The count is recursive. Every
include:you resolve may contain includes of its own, and all of them count against your ten.include:zoho.comspends five on its own.include:_spf.google.comspends four. Two providers and you are most of the way to the ceiling before adding anything of your own. - An
mxmechanism costs more than one. It resolves the MX records, then resolves each hostname it finds. A domain with five MX hosts spends six lookups on the single wordmx.
There is a second, less famous limit worth knowing: at most two "void" lookups — queries returning NXDOMAIN or no records. A stale include: for a service you stopped using is a void lookup, and three of them is also a permerror.
Fixing it, in the order worth trying
1. Delete what you no longer use
Start here, always. SPF records accumulate dead entries faster than anything else in DNS — the marketing platform you trialled for a quarter, the invoicing tool you migrated off, the CRM from two vendors ago. Each one still costs a lookup, and some now cost a void lookup as well.
Go through every include: and ask whether that service still sends as your domain. If you cannot answer confidently, your DMARC aggregate reports can: they name every source actually sending, so anything in your SPF record that never appears in a report is a candidate for deletion.
2. Replace stable includes with ip4
ip4: is free. If a service publishes a small, genuinely stable set of sending addresses, listing them directly costs nothing against the budget.
v=spf1 ip4:203.0.113.0/24 include:_spf.google.com -all
Use this for your own infrastructure — a static mail server, a VPS you control — where you will notice if the address changes. Do not use it for a large cloud sender: their ranges change without telling you, and a stale ip4: fails silently in the direction that breaks real mail.
3. Move bulk senders to a subdomain
This is the fix that actually scales, and the one most people reach last. Each domain gets its own ten-lookup budget, so sending marketing mail from news.yourdomain.com and transactional mail from mail.yourdomain.com gives each its own record and its own headroom:
yourdomain.com v=spf1 include:_spf.google.com -all
news.yourdomain.com v=spf1 include:sendgrid.net -all
It also isolates reputation — a bad marketing campaign no longer touches the domain your invoices come from — and it keeps DMARC working, because relaxed alignment (the default) accepts a subdomain of your organisational domain. Change the From address at the sending platform and you are done.
4. Flattening — and why to be careful
Flattening means resolving every include: yourself and replacing them with the resulting ip4: lists. It reliably gets you under ten, and it is what most "SPF flattening" services sell.
The cost is that you have taken on maintenance of somebody else's infrastructure list. When Google or Microsoft adds a sending range, your flattened record does not know, and mail from the new range fails SPF until someone notices. If you flatten, use a service that re-resolves and updates automatically, and never flatten by hand into a static record you will forget about. For most domains, options 1 to 3 are enough and carry no such debt.
What not to do
- Do not publish a second SPF record. Splitting the includes across two TXT records is the intuitive move and it is a permanent error of its own — receivers that find two records evaluate neither. One record per domain, always.
- Do not use
ptr. It is deprecated, slow, unreliable, and receivers are entitled to ignore it. Delete it if you find one. - Do not solve it with
+all. It ends the error by authorising the entire internet to send as you. Some guides genuinely suggest this.
After the fix
Re-check with the SPF record checker and confirm the count is at ten or below. Then remember what a permerror was costing you: for as long as it stood, SPF contributed nothing to DMARC for any message you sent, and every one of them was relying on DKIM alone to align. Confirm your DKIM is actually signing with the free DKIM checker, because a domain that just came out of permerror often finds it has been running on one leg for months.
The durable fix is watching the number rather than counting it once. SPF records grow — a provider adds an include on their side, someone in marketing signs up for a tool — and the eleventh lookup arrives without any change on your part. That is DNS drift, and it is why this error tends to appear on a domain nobody touched.
Free checks: SPF checker DMARC checker DKIM checker Spam checker