Article

How to Fix SPF Too Many DNS Lookups (PermError)

SPF allows a maximum of 10 DNS-querying mechanisms; exceed it and receivers return a permerror that makes SPF fail. Fix it by removing unused includes, replacing includes with ip4/ip6 where addresses are stable, and consolidating or flattening the record.

By Paul Rudenko, Security ResearcherUpdated Jun 26, 20267 min read

Sender Policy Framework (SPF) is a small but strict protocol. One of its least-forgiving rules is a cap on how many DNS queries a single SPF evaluation may perform. Cross that line and receiving mail servers stop evaluating your record and return a permerror — a permanent error that, in practice, means SPF simply fails.

This guide explains the rule, shows you how to count your own lookups, and walks through the durable ways to bring a bloated record back under the limit.

For the site owner (plain English)

This means your SPF record — the DNS line that lists who may send email for your domain — has grown too big and now trips a hidden limit, which can quietly send your real mail to spam. It is worth fixing, though it is not a same-day emergency. The usual cause is simple: over the years you added a line for each new tool (a newsletter service, a CRM, a support desk) and the list eventually crossed a ten-lookup ceiling built into the standard. The fix is to trim that one TXT record: log in to your DNS provider, remove entries for tools you no longer use, and where possible replace a provider's include: with its fixed IP addresses, which do not count against the limit. It is editing a single record, not rebuilding your email.

What is the SPF 10-lookup limit?

SPF is defined by RFC 7208. Section 4.6.4 sets a hard ceiling: during a single check of your SPF policy, a receiver may perform at most ten DNS lookups for mechanisms and modifiers that require DNS resolution.

The intent is to protect mail servers from being used to amplify denial-of-service traffic — without a cap, a maliciously nested SPF record could trigger an unbounded cascade of queries. When the eleventh lookup is reached, the evaluation halts and the result is permerror.

The catch is that the limit counts lookups, not the number of characters or terms in your published record. The mechanisms that each consume one or more lookups are:

  • include — each include: term costs one lookup, plus every lookup performed by the included record (nesting is recursive).
  • a — resolving the A/AAAA records of a name costs one lookup.
  • mx — costs one lookup to fetch the MX records, and the subsequent A/AAAA resolution of each returned host can add more.
  • ptr — costs one lookup. It is also discouraged by RFC 7208 and should be avoided entirely.
  • exists — costs one lookup.
  • The redirect modifier — counts toward the limit as well.

Crucially, ip4: and ip6: mechanisms cost zero lookups, because the address is already in the record and no DNS query is needed to resolve it. The same is true for all. This is the lever that almost every fix relies on.

Why nesting is the usual culprit

A single include:_spf.google.com looks like one lookup, but Google's record itself contains further includes, each resolving to more. A record that publishes only three or four includes can quietly resolve to twelve or thirteen lookups once every nested level is followed. Because the bloat lives in records you do not control, the count can also drift over time as those providers restructure their own SPF.

What permerror does under DMARC

On its own, an SPF permerror means the SPF check yields no useful pass. Under DMARC, alignment depends on SPF (or DKIM) producing a pass that aligns with the visible From domain. If SPF permerrors and DKIM is absent or also fails, DMARC fails — and ap=reject or p=quarantine policy will then have your legitimate mail rejected or sent to spam. A lookup overflow is therefore not a cosmetic warning; it can silently break deliverability.

How do I count my own lookups?

Counting by hand means walking the record depth-first. Start at your published v=spf1 record, add one for each lookup-consuming mechanism, then recurse into every include and redirect and add their lookups too. Continue until you have expanded every branch.

v=spf1 include:_spf.google.com include:servers.mcsv.net include:sendgrid.net a:mail.example.com -all

In the example above you can already see four lookup-consuming terms at the top level (three includes plus one a). But each of those includes expands further — _spf.google.com alone typically adds three nested includes — so the true total is what matters, not the four terms you can see.

Rather than tracing this manually every time, use a checker. An SPF validation tool will expand the full tree, show the running count, and flag exactly which branch pushes you over ten. Our DMARC and email authentication checker does this expansion for you and reports the lookup total alongside any permerror risk.

How to fix it

There is no way to raise the limit — receivers enforce it, not you — so every fix reduces the number of lookups your record requires. Work through these in order; the early steps are the safest.

1. Remove dead includes

Most overflowing records carry includes for services that are no longer sending mail: a retired marketing platform, a help-desk tool you migrated away from, a one-off campaign vendor. Every stale include wastes at least one lookup, often several once nested. Audit each include against the systems that actually send as your domain today, and delete anything you cannot account for. This is the single highest-value step and carries almost no risk, because you are only removing authorization for senders that no longer exist.

2. Replace includes with ip4/ip6 for stable senders

If a sender publishes a small, stable set of sending IP addresses, you can list those addresses directly with ip4: / ip6: instead of including the provider's record. Because IP mechanisms cost zero lookups, this can reclaim several lookups at once.

# Before (1+ lookups, possibly nested):
include:mail.vendor.example

# After (0 lookups):
ip4:198.51.100.0/24 ip6:2001:db8:abcd::/48

Only do this for providers whose ranges genuinely do not change — your own outbound relay, a fixed transactional gateway, a colocated server. For large cloud senders whose ranges shift, keep the include (see the gotcha below).

3. Drop redundant a and mx mechanisms

Many records inherit an a or mx mechanism that was added "just in case." If your domain's A record or mail exchangers do not actually send outbound mail, those mechanisms are pure cost. Remove them. Where they are needed and the addresses are stable, replace them with explicit ip4:/ip6: entries to convert a lookup into a zero-cost term.

4. Consolidate or flatten the record

If you still exceed ten after pruning, consolidation is the next tool. Flattening means resolving every include down to the underlying IP addresses and publishing those addresses directly, so the receiver performs no nested lookups at all. Done well, a flattened record can sit comfortably at zero or one lookup regardless of how many providers you use.

The right way to flatten is with a maintained flattening service that re-resolves your providers' records on a schedule and updates the published IPs for you (often by hosting the record at a delegated subdomain you include or redirect to). That keeps the convenience of a flat record without the maintenance trap of a static snapshot. The caveat is real and is covered next.

Common gotcha: hand-flattening — pasting a provider's current IP list into your own record once — works the day you do it and then breaks silently. When that provider adds, retires, or reassigns a sending IP (which large senders do routinely, without notifying you), your static copy no longer matches reality and mail from the new addresses fails SPF with no error message to alert you. Either use a flattening service that re-resolves and updates automatically, or keep a normal include for any provider whose IP ranges are volatile.

How do I verify the fix?

After every change, confirm two things: that the published record parses as a single valid v=spf1 policy, and that its fully expanded lookup count is ten or fewer. DNS caching means an edit can take time to propagate, so re-check after the TTL has elapsed rather than immediately.

  • Run an SPF lookup-count check and confirm the total is ≤ 10 with no permerror.
  • Send a test message to an address that reports authentication results and confirm SPF shows pass for your sending IP.
  • Check your DMARC aggregate reports over the following days to confirm SPF is passing and aligned across all your real senders.

See your fully expanded SPF lookup count and permerror risk in seconds.

Check your SPF record

For the full picture of how SPF, DKIM, and DMARC fit together, read the email authentication guide. If your domain has accidentally published more than one SPF record — another common cause of permerror — see how to fix multiple SPF records. For step-by-step DNS entry, see setting up SPF, DKIM and DMARC on GoDaddy, and for the bigger picture read how to prevent email spoofing of your domain.

Frequently asked questions

What is the SPF 10-lookup limit?

RFC 7208 caps a single SPF evaluation at ten DNS-querying mechanisms. The mechanisms that count are include, a, mx, ptr, and exists, plus the redirect modifier — and the count is recursive, so every lookup performed by a nested include adds to your total. By contrast, ip4, ip6, and all cost zero lookups because no DNS query is needed to resolve them. The rule exists to stop SPF being used to amplify denial-of-service traffic. When a receiver reaches the eleventh lookup, it stops evaluating and returns permerror, which means SPF fails to produce a pass. The limit counts lookups, not the number of terms you can see in the record, so a short-looking record with a few nested includes can easily exceed ten.

How do I count my SPF lookups?

Expand your record depth-first. Begin at your published v=spf1 record, add one for each lookup-consuming mechanism (include, a, mx, ptr, exists) and for any redirect modifier, then recurse into every include and redirect and add their lookups too, continuing until every branch is fully expanded. Remember that ip4, ip6, and all add nothing. Because the bloat usually hides inside providers' nested records that you do not control, manual counting is error-prone and can drift as those providers change. The reliable approach is to run an SPF checker that expands the entire tree for you, shows a running total, and points to the exact branch that pushes you past ten. Our email authentication checker performs this expansion and reports both the lookup count and any permerror risk.

Is SPF flattening safe?

Flattening — resolving includes down to raw IP addresses and publishing them directly — is safe and effective only when something keeps those addresses current. A maintained flattening service re-resolves your providers' records on a schedule and updates the published IPs automatically, usually via a delegated subdomain you include or redirect to. That preserves a low lookup count without becoming stale. The unsafe version is hand-flattening: pasting a provider's current IP list into your record once. It works the day you do it, then breaks silently when that provider adds or reassigns a sending IP, because your static snapshot no longer matches reality and there is no error to warn you. For providers with volatile ranges, keep a normal include instead.

What happens when SPF returns permerror?

A permerror is a permanent error that means SPF could not be evaluated to a usable result, so it does not produce a pass. On its own that weakens authentication. Under DMARC the consequences are sharper: DMARC needs SPF or DKIM to pass and align with the From domain. If SPF permerrors and DKIM is missing or also fails, DMARC fails — and if your DMARC policy is p=quarantine or p=reject, legitimate mail can land in spam or be rejected outright. Because nothing visibly errors in your own systems, this often goes unnoticed until deliverability drops. That is why a lookup overflow should be treated as an urgent fix, and why you should confirm SPF passes and aligns in your DMARC aggregate reports after correcting it.

Related guides

See your whole external attack surface

One page is a start. The full external scan covers TLS, headers, DNS, exposed files, open services and known-exploited CVEs across your whole domain.

See the full scan →