SPF PermError: too many DNS lookups, and how to fix it
Why SPF stops at ten DNS lookups, what counts towards the limit, and five fixes in order of safety, from removing dead includes to flattening.
SPF has a hard limit, set by its standard (RFC 7208, section 4.6.4): evaluating a record may trigger at most ten DNS lookups. One more and the result is permerror, which receivers treat as a failure for every message, including the legitimate ones. Your record looks fine, each service’s documentation said to add its include:, and yet SPF is broken for everybody.
What counts
| Counts as a lookup | Does not count |
|---|---|
include: (and every lookup inside the included record) |
ip4: and ip6: |
a, mx |
all |
exists:, ptr |
exp= |
redirect= |
Includes nest: include:spf.protection.outlook.com costs one lookup, plus whatever that record includes. A typical small company with Microsoft 365, a newsletter tool, a CRM and a help desk reaches eleven or twelve without noticing. The SPF checker expands the whole tree and counts.
There is a second, smaller limit: two void lookups. An include: that points to a name that no longer exists counts as void; three of them also produce permerror.
Five fixes, safest first
1. Remove what no longer sends. The service you left two years ago, the old web host, the a and mx added “just in case”. Each removed include gives back its whole subtree. Your DMARC reports show which sources really send.
2. Remove includes that do nothing for DMARC. Many newsletter and CRM tools send with their own return-path domain, so SPF is checked against their domain, not yours. Their include: in your record is useless; what makes their mail pass DMARC is DKIM signed with your domain. Check each service’s domain-authentication page: if it never asked you to change the return path, its include can usually go.
3. Move bulk senders to a subdomain. Send newsletters from news.yourdomain.com, with its own SPF record. Each subdomain has its own ten-lookup budget, and your main domain keeps a short, readable record.
4. Replace a and mx with ip4:. If your own mail server has a fixed address, write it as ip4:203.0.113.10. Zero lookups.
5. Flatten, with care. Flattening replaces includes by the IP addresses they resolve to. It solves the count, but providers change their addresses without warning, and a flattened record then silently rejects their new servers. Only flatten records you can re-check automatically, and never flatten the large providers’ includes (Microsoft, Google) by hand.
After the fix
Check the record again: one record, a lookup count under ten with some margin, an ending of ~all or -all. Then confirm that DMARC still passes for each service in the following week’s reports, with the DMARC report reader. The SPF generator writes a clean record if you prefer to start over.