SPF PermError: Too Many DNS Lookups (How to Fix)
Fix SPF PermError "too many DNS lookups": what counts toward the 10-lookup limit, how nested includes add up, and when to remove, split or flatten safely.
6 min read · Updated
SPF records grow one service at a time—an email provider, a CRM, a helpdesk, a newsletter tool—until one day mail starts failing SPF everywhere, with no change to the record that looks unusual. The cause is almost always the 10 DNS lookup limit.
What is the SPF 10 DNS lookup limit?
To stop SPF being used to make receiving servers send large numbers of DNS queries, RFC 7208 caps evaluation at 10 DNS lookups. Exceed it and the receiver stops with a permanent error (permerror). Under DMARC that counts as an SPF failure for every message, not just some.
These terms cost a lookup each:
include:,a,mx,ptr,exists:andredirect=
These are free: ip4:, ip6: and all.
The catch is that lookups inside included records count too. A single include: for a large provider can cost three or four lookups because their record includes others. A record with six includes can easily need twelve lookups.
There is a second, lesser-known limit: at most two "void" lookups—lookups that return no records, typically includes of services you no longer use whose records have been deleted.
Find out where the lookups go
The SPF, DKIM and DMARC checker follows every include and shows the tree with a lookup count per branch, so you can see which entries are expensive. You will often find:
- includes for services you stopped using years ago;
- the same provider included twice under different names;
aandmxmechanisms that duplicate what an include already covers;- a
ptrmechanism, which is deprecated and should go regardless.
Ways to get under the limit
1. Remove what you don't use
The safest fix. Check your DMARC aggregate reports to see which services actually send as your domain, and remove includes for the rest.
2. Replace a and mx with addresses
If your own mail server has a stable address, ip4:192.0.2.25 costs nothing, while mx costs a lookup. Only do this for addresses you control and that rarely change.
3. Move senders to subdomains
Marketing and transactional platforms can usually send from a subdomain such as news.example.com or billing.example.com. Each subdomain has its own SPF record with its own 10-lookup budget, and DMARC's relaxed alignment still accepts them for mail from example.com when the platform signs with DKIM.
4. Rely on DKIM for some services
DMARC passes if either SPF or DKIM is aligned. A service that signs with your domain's DKIM key doesn't strictly need to be in SPF. Removing it is reasonable once reports confirm its mail passes DKIM.
5. Flattening, with care
"Flattening" replaces includes with the IP ranges they currently resolve to. It works, but providers change their ranges without notice. A flattened record that isn't automatically refreshed will silently start failing. If you flatten, use a service that updates the record continuously.
Other permanent errors to rule out
- Two SPF records on the same name. Only one is allowed; merge them.
- An include that points at a name without an SPF record, often a typo or a provider that changed its include name.
- Syntax errors such as
ip4:with an invalid address or a misspelled mechanism.
Any of these fails SPF for every message, so they are worth checking after every edit.
Frequently asked questions
- What is the SPF 10 DNS lookup limit?
- RFC 7208 lets receivers perform at most 10 DNS lookups while evaluating an SPF record, including lookups inside included records. Going over causes a permanent error.
- Which SPF mechanisms count toward the lookup limit?
- include, a, mx, ptr, exists and redirect each cost a lookup. ip4, ip6 and all are free.
- Is SPF flattening safe?
- Only if the flattened record is refreshed automatically. Providers change their IP ranges without notice, and a static flattened record will silently start failing.
- What causes SPF PermError besides too many lookups?
- Two SPF records at the same name, an include pointing at a name with no SPF record, more than two void lookups, or syntax errors.