SPF PermError: Too Many DNS Lookups and How to Fix It

Your SPF record looks fine. It starts with v=spf1, lists every service that sends mail for you, and ends with -all. But an SPF checker reports "PermError: too many DNS lookups", an...

SPF PermError: Too Many DNS Lookups and How to Fix It
Advertisement

Your SPF record looks fine. It starts with v=spf1, lists every service that sends mail for you, and ends with -all. But an SPF checker reports "PermError: too many DNS lookups", and messages from your domain keep landing in spam. The cause is almost always the same: the record makes the receiving server do more than 10 DNS lookups, and SPF stops evaluating at that point.

This guide covers where the limit comes from, how to count lookups yourself (nested includes are where most people get it wrong), and how to get back under 10, starting with the safest fixes.

What the error looks like

In the headers of a message delivered to a large mailbox provider, the Authentication-Results line shows something like this:

Advertisement
Authentication-Results: mx.example.net;
       spf=permerror (sender SPF record for example.com: too many DNS lookups)
       smtp.mailfrom=newsletter@example.com

The wording in the parentheses depends on the receiver, but the important part is spf=permerror. Online checkers report the same thing more directly, with messages like "too many DNS lookups", "exceeded 10 lookup limit", or "PermError".

Why it matters

A PermError means the receiver couldn't evaluate your record at all. It is not a neutral or soft result. Most receivers treat it the same way they treat a failed SPF check, and some treat it as a sign of a broken setup. In practice that means more mail goes to spam, some of it gets rejected, and you lose an authentication signal you thought you had.

It also affects DMARC. DMARC passes only if SPF or DKIM passes and aligns with the domain in the From header. If SPF returns PermError, DMARC depends entirely on DKIM. When a sending service signs with its own domain instead of yours, or doesn't sign at all, DMARC fails, and if your policy is p=quarantine or p=reject, receivers act on that. You can see how your current policy is set up with the DMARC checker.

Why the 10-lookup limit exists

SPF is defined in RFC 7208. Section 4.6.4 says implementations MUST limit the number of DNS-querying terms to 10 during a single SPF evaluation. If that limit is exceeded, the result is permerror.

Advertisement

The reason is protection for receivers and for DNS itself. The sender controls the record, and every message checked can trigger a chain of queries. Without a cap, a sloppy or malicious record could make each incoming message fan out into dozens of lookups, which at a large provider's volume becomes a cheap way to overload DNS servers. The cap keeps evaluation cost small and predictable.

What counts and what doesn't

According to RFC 7208, these terms count toward the limit:

  • include: — counts as one, and everything inside the included record counts too
  • a and a:
  • mx and mx:
  • ptr (the RFC says this mechanism SHOULD NOT be published at all)
  • exists:
  • the redirect= modifier

These do not count, because they don't need DNS:

  • ip4:
  • ip6:
  • all

Two other rules from the same section are worth knowing. First, evaluating a single mx mechanism may not involve looking up more than 10 address records for the hosts it returns, and going over that also produces PermError. Second, the RFC says implementations SHOULD limit void lookups (queries that return no answer or NXDOMAIN) to two, and exceeding that is also a PermError. That second rule often catches records that still reference a decommissioned host or a provider you stopped using years ago.

Advertisement

How to count lookups: a worked example

This is the part that confuses people. The limit applies to the whole evaluation, not just your top-level record. Every include pulls in another SPF record, and whatever lookups that record contains are added to your total.

Here's a realistic-looking record for a company that uses a hosted mailbox suite, a CRM that sends notifications, and a newsletter platform. The provider domains below are placeholders, but the structure is typical:

example.com.  TXT  "v=spf1 a mx include:_spf.mailsuite.example include:spf.crm.example include:send.newsletter.example ip4:203.0.113.10 -all"

At the top level there are five DNS-querying terms: a, mx, and three includes. That looks fine. Now follow each include:

_spf.mailsuite.example     "v=spf1 include:_nb1.mailsuite.example include:_nb2.mailsuite.example include:_nb3.mailsuite.example ~all"
spf.crm.example            "v=spf1 include:spf1.crm.example include:spf2.crm.example ~all"
send.newsletter.example    "v=spf1 a include:relay.newsletter.example ~all"

Assume the deepest records (_nb1, spf1.crm, relay.newsletter, and so on) contain only ip4/ip6 ranges. The tally looks like this:

a                                  1
mx                                 1
include:_spf.mailsuite.example     1
  include:_nb1 / _nb2 / _nb3       3   (subtotal 4)
include:spf.crm.example            1
  include:spf1 / spf2              2   (subtotal 3)
include:send.newsletter.example    1
  a                                1
  include:relay.newsletter.example 1   (subtotal 3)
ip4:203.0.113.10                   0
-all                               0
-----------------------------------------
Total                             12   → PermError

A record with five visible lookups actually needs twelve. That's common: a single provider include can contain several more lookups, and providers change their records without notice, so a record at 9 last year can be at 11 today.

Counting by hand is tedious and error-prone. The SPF checker resolves every include recursively and shows the lookup count, so you can see which branch is using up your budget.

How to fix it, safest options first

Work through these in order; the later ones involve trade-offs.

1. Remove includes you no longer use

This is the easiest fix and usually the most effective. Records collect includes over time: an old helpdesk tool, a marketing platform you trialed, a host you left. If a service no longer sends as your domain, remove its include.

2. Drop a, mx, and ptr if those hosts don't send mail

Many records include a and mx by default because a generator or hosting panel added them. a authorizes the IP your domain's A record points to (often your web server). mx authorizes your inbound mail servers. If your website doesn't send mail directly and your inbound MX hosts aren't the ones sending outbound mail (common with hosted mailbox suites), both are wasted lookups. Remove ptr regardless: RFC 7208 says it should not be published, and it's slow and unreliable.

3. Replace lookups with ip4/ip6 where ranges are stable

If a server you control sends from a fixed IP, list it with ip4: or ip6: instead of a:mail.example.com. That costs zero lookups. You can do the same for a provider that publishes official, documented sending ranges, but be careful: providers add and retire IPs, and if you hardcode their ranges you become responsible for tracking those changes. When in doubt, keep the provider's include and save your hardcoded IPs for infrastructure you own.

4. Move bulk or marketing mail to a subdomain

Each domain and subdomain has its own SPF record with its own 10-lookup budget. If your newsletter platform sends from news.example.com and your transactional service sends from mail.example.com, each subdomain only needs the includes for its own sender. Your root domain then only has to cover your mailbox provider. It also isolates reputation from marketing complaints. The SPF generator makes it quick to build a separate, clean record for each subdomain.

5. Lean on DKIM-aligned DMARC

Since DMARC passes when either SPF or DKIM passes and aligns, a service that signs with DKIM using your domain doesn't strictly need to be in your SPF record for DMARC to pass. Some third-party services also send with their own return-path domain, in which case SPF is checked against their domain, not yours, and adding their include to your record does nothing for alignment. Set up DKIM with your own domain for every service that supports it, and you may find some includes aren't helping at all. Don't drop SPF entirely, though: some receivers still evaluate it on its own, and forwarding can break DKIM in edge cases.

6. SPF flattening (understand the trade-offs)

"Flattening" means resolving all your includes into their underlying IP ranges and publishing those as ip4/ip6 entries. Flattening services automate this: they watch your providers' records and republish an updated result, often through an include they host.

The benefit is real: you can authorize many senders with very few lookups. The risks are also real:

  • Stale IPs. If a provider adds a new sending range and your flattened record isn't updated in time, mail from that range fails SPF. Manual flattening has no update mechanism at all.
  • Record size. Expanding many includes can produce a long record. Very large DNS responses can cause issues with some resolvers, so flattening tools often split the result across several records.
  • Dependency. With a hosted service, your mail authentication depends on that vendor staying online and keeping its data current.

Flattening is a reasonable choice when you truly need many senders on one domain and options 1–5 aren't enough. It shouldn't be the first thing you try.

Quick checklist

  1. Run your domain through an SPF checker and note the total lookup count, including nested includes.
  2. List every service that actually sends mail as your domain today.
  3. Remove includes for services that no longer send.
  4. Remove ptr, and remove a/mx if those hosts don't send outbound mail.
  5. Replace lookups for your own fixed-IP servers with ip4/ip6.
  6. Move bulk or marketing senders to subdomains with their own SPF records.
  7. Set up DKIM with your own domain for every service, and confirm your DMARC record.
  8. Make sure you have only one SPF record per domain, then re-check after DNS propagates.
  9. Re-check periodically, because providers change their includes.

FAQ

Does the 10-lookup limit include nested includes?

Yes. The limit covers the entire evaluation. Each include counts as one, and every DNS-querying term inside the included record (and inside anything it includes) counts too.

Do ip4, ip6, and all count toward the limit?

No. RFC 7208 lists only include, a, mx, ptr, exists, and the redirect modifier as counting terms. ip4, ip6, and all don't require DNS queries.

Can I publish two SPF records to split the lookups?

No. A domain must have only one SPF record. Publishing two causes a PermError of its own. If you need more room, use subdomains, since each one gets its own record and its own budget.

What is a void lookup?

A DNS query made during SPF evaluation that returns no records or NXDOMAIN, for example an include pointing to a domain that no longer has an SPF record. RFC 7208 recommends limiting these to two; going over produces PermError even if your total is under 10.

Is ~all safer than -all when I have this error?

No. The all qualifier only matters when evaluation finishes normally. A PermError happens before that, so switching between ~all and -all won't fix it. Reduce the lookup count instead.

Advertisement
spf permerror too many dns lookups batas 10 lookup spf include spf spf flattening rfc 7208 void lookup cara memperbaiki spf
Share this article
Back to Blog
🚀 Partner Recommendation

Need Premium Source Code & Business Apps?

Access Laravel applications, POS systems, School Management, Clinic Software, ERP solutions, and ready-to-use premium source code at GudangCode.

GudangCode
  • ✔ Premium Source Code
  • ✔ Ready-to-Use Systems
  • ✔ Lifetime Updates
  • ✔ Lifetime Membership
  • ✔ Daily App Updates
Join Membership →
Advertisement
Advertisement