iPGaze

Guide

How to Fix SPF ‘Too Many DNS Lookups’ (PermError)

SPF allows only 10 DNS lookups before a PermError breaks authentication. Learn what counts, how to count yours, and how to fix and flatten a bloated record.

If a mail tester or a DMARC report tells you your SPF record produces a "PermError" or warns that you have "too many DNS lookups," your domain's SPF is effectively broken even though the record itself may look perfectly valid. This is one of the most common SPF problems, and it almost always creeps in over time as you add more sending services. The good news is that it is well understood, measurable, and fixable without guesswork.

This guide explains the rule behind the error, how to count the lookups your record really uses, where the bloat usually comes from, and the practical ways to bring your record back under the limit while keeping every legitimate sender authorized.

The 10-DNS-lookup limit and why it exists

Sender Policy Framework is defined in RFC 7208, which sets a hard ceiling of 10 DNS lookups when a receiving mail server evaluates your SPF record. The limit exists to protect receivers: SPF evaluation happens during the SMTP conversation, and without a cap a maliciously or accidentally complex record could force a receiver to perform an unbounded number of DNS queries per message, creating an amplification and denial-of-service risk. Ten was chosen as a reasonable balance between flexibility and safety.

Crucially, the count includes every mechanism that requires DNS resolution across the entire record, including everything pulled in through nested includes. The initial fetch of your own SPF TXT record does not count against the 10, but almost everything it references does.

What actually counts as a lookup

Six mechanisms trigger DNS lookups and count toward the limit: "include", "a", "mx", "ptr", "exists", and the "redirect" modifier. Each one counts as a single lookup at the point it appears, but if an "include" points to another record that itself contains includes or other lookup mechanisms, those nested lookups are added to the running total too. A single "include:_spf.google.com" can quietly expand into several lookups because it chains to further includes underneath.

Two mechanisms do not count: "ip4" and "ip6". Because they list raw addresses or CIDR ranges directly in the record, no DNS resolution is needed to evaluate them. This distinction is the key to almost every fix, because it means you can replace lookup-heavy mechanisms with literal IP ranges that cost nothing against the budget. Note also that "ptr" is both lookup-expensive and discouraged by the RFC, so it should be removed entirely rather than counted.

What PermError means for deliverability

When evaluation exceeds 10 lookups, the receiver must return a PermError (permanent error) result for SPF rather than a pass or a fail. The practical effect is that SPF no longer authenticates your mail at all. Many receivers treat PermError as equivalent to no SPF, while stricter setups may treat it as a failure outright, increasing the chance your messages are filtered to spam or rejected.

The bigger problem is DMARC. DMARC passes only when SPF or DKIM produces a passing, aligned result. A PermError is not a pass, so it cannot contribute to DMARC alignment. If you rely on SPF for alignment and it PermErrors, your DMARC posture weakens even if DKIM is fine, and a too-aggressive SPF can undermine an otherwise healthy DMARC Check policy. After fixing SPF, recheck how it feeds your overall authentication.

How to count your lookups

You cannot reliably count lookups by eye, because nested includes hide most of the cost. The dependable method is to expand the record fully: start at your own "v=spf1" record, then recursively resolve every include, redirect, a, mx, ptr and exists mechanism, tallying one for each DNS query performed along the way. Doing this manually with a DNS Lookup lookup is possible but tedious and error-prone for a deep tree.

The fast approach is to run your domain through our SPF Check checker, which parses the record, follows every include, and reports the total lookup count along with the chain that produced it. That breakdown is what tells you which single include is responsible for three or four lookups, so you know exactly where to cut. Recount after every change rather than assuming a fix landed.

Where the bloat usually comes from

Most over-limit records are not malformed; they have simply accumulated senders. The biggest culprits are the large platform includes. Google Workspace's "include:_spf.google.com" and Microsoft 365's "include:spf.protection.outlook.com" each expand into multiple nested lookups on their own. Stack those alongside a marketing platform, a CRM, a helpdesk, a transactional email provider, and an e-commerce plugin, and you can pass 10 with only five or six visible includes.

A second common cause is leftover includes for services you no longer use. Vendors get trialed, replaced, or churned, but their SPF include is rarely removed, so it keeps consuming part of your budget for no benefit. Redundant "a" and "mx" mechanisms that duplicate IPs already covered elsewhere add to the waste.

How to fix it: cut, flatten, and segment

Start with the cheapest win: remove unused includes. Audit every mechanism against the services you actually send mail through today, and delete any include for a vendor you have stopped using. This alone resolves a surprising number of PermErrors. Also drop any "ptr" mechanism and collapse redundant "a"/"mx" entries into the "ip4"/"ip6" addresses they resolve to when those addresses are stable.

If you are still over the limit, consider SPF flattening: replacing an "include" with the explicit "ip4"/"ip6" ranges it currently authorizes. Because IP mechanisms cost zero lookups, flattening can dramatically reduce the count. The serious trade-off is maintenance: when a provider changes its sending IPs, your flattened record becomes stale and will start failing legitimate mail. Only flatten senders with stable, published ranges, and either monitor those ranges or use a service that keeps the flattened record updated automatically.

A cleaner structural fix is segmentation. Send different mail streams from different subdomains or dedicated sending domains, each with its own SPF record and its own independent 10-lookup budget. For example, route marketing mail from "news.yourdomain.com" and transactional mail from "mail.yourdomain.com". This also improves reputation isolation, since a problem with one stream no longer drags down the others.

Don't forget the void-lookup limit

RFC 7208 adds a second, less famous cap: the void-lookup limit. A void lookup is a DNS query that returns no answer, either an empty result or an NXDOMAIN. If SPF evaluation encounters more than two void lookups, the result is also a PermError, independent of the 10-lookup total. This typically happens when an include points to a record that no longer exists, or when an "a"/"mx" mechanism references a host that has been decommissioned.

So removing dead includes is not just about trimming the lookup count, it also prevents void-lookup PermErrors. When you audit the record, treat any include or host that fails to resolve as something to delete, not something to keep "just in case."

Verifying after changes

DNS changes are not instant. SPF lives in a TXT record, and receivers may cache the old value until its TTL expires, so a fix can take from a few minutes to a few hours to apply everywhere. Lower the TTL before a planned change if you want faster turnaround. Remember too that a domain may have only one "v=spf1" record; if you accidentally publish a second, that is its own error to clear up.

Once the change propagates, re-run the SPF Check checker to confirm the lookup count is at or below 10, that there are no void lookups, and that every legitimate sender is still authorized. Then watch your DMARC aggregate reports over the following days: a healthy fix shows SPF passing and aligning again. For ongoing assurance, recheck the record whenever you add or remove a sending service, since that is exactly when records drift back over the limit.

Tools mentioned in this guide