How to Fix the SPF Too Many DNS Lookups Error (PermError)

Fix the SPF permerror for too many DNS lookups: what counts toward the RFC 7208 limit of 10, how nested includes add up, the two void lookup rule, lookup costs of common vendor includes, and safe fixes before you try flattening.

Home › Guides › SPF too many DNS lookups

Last updated 17 October 2026

Quick answer

SPF evaluation may trigger at most 10 DNS lookups. Every include, a, mx, ptr, exists and redirect costs one, including the ones inside the records you include. Go over 10 and receivers stop and return permerror, so SPF fails for every message from that domain, not just the ones from the last sender you added.

To fix it, in this order:

  1. Count the lookups with the SPF Record Checker. It expands every include and numbers each lookup.
  2. Remove senders you no longer use, and drop a, mx and ptr unless those hosts really send mail.
  3. Remove includes for services that send with their own bounce domain. They never helped your SPF or DMARC result.
  4. Move the remaining third-party senders to subdomains, each with its own 10-lookup budget.
  5. Only then consider replacing a vendor include with its IP ranges ("flattening"), and never for Microsoft 365.

What the error means

RFC 7208, the SPF standard, says in section 4.6.4 that the terms which cause DNS queries are the include, a, mx, ptr and exists mechanisms and the redirect modifier, and that implementations must limit the total to 10 during evaluation and return permerror when the limit is exceeded. The count covers the whole evaluation, so a vendor include that itself includes three more records costs four.

Receivers word it differently. You may see spf=permerror in an Authentication-Results header, "too many DNS lookups", "SPF PermError" in a DMARC report, or "include loop / lookup limit" in a checker. They all mean the same thing.

Why it matters: DMARC only counts SPF when the result is pass and the MAIL FROM domain aligns with the From domain. With a permerror, SPF can't help DMARC at all, so a message passes DMARC only if it also carries an aligned DKIM signature. Domains at p=quarantine or p=reject without DKIM on every sender start losing mail.

What counts toward the 10

TermLookupsNotes
include:vendor.example1 plus everything insideNested includes, a, mx and so on in the vendor's record all count against your 10.
redirect=other.example1 plus everything insideSame as include for counting purposes.
a, a:host1Looks up the A/AAAA records of the domain or host.
mx, mx:domain1Also may resolve at most 10 MX hosts' addresses per mx term, or the term itself is a permerror.
ptr1Deprecated by RFC 7208 ("SHOULD NOT be published"). Remove it.
exists:1Often used with macros, for example exists:%{i}._spf.example.
ip4, ip6, all0Free. These are what flattening converts includes into.
exp=0Only looked up later to build a rejection message; not counted.

The TXT lookup for your own top-level record is not counted. RFC 7208 also says receivers should allow no more than two void lookups (a name that returns no records, or does not exist). A third void lookup is also a permerror, so stale includes pointing at deleted vendor records hurt twice.

Worked example

A company on Microsoft 365 that has collected marketing, transactional and CRM senders over the years publishes:

v=spf1 mx a include:spf.protection.outlook.com include:_spf.google.com include:sendgrid.net include:mailgun.org include:_spf.salesforce.com -all

Looking only at the top level it seems to use 7 lookups. Expanded, it uses 13: mx 1, a 1, Microsoft 1, Google 1, SendGrid 2, Mailgun 5 and Salesforce 2. Every message from the domain now gets permerror. Removing mx and a (the MX points at Exchange Online for inbound mail, and the website host doesn't send) and the Google include left over from a migration brings it to 10, which is legal but leaves no room. Moving Mailgun to mail.example.com brings the root record down to 5.

Lookup cost of common includes

We expanded these vendor records on 17 October 2026. The number is what one include of that value adds to your total (the include itself plus anything nested). Vendors change their records, so always recount your own.

Include valueServiceLookups
spf.protection.outlook.comMicrosoft 365 / Exchange Online1
_spf.google.comGoogle Workspace1
amazonses.comAmazon SES1
servers.mcsv.netMailchimp1
spf.mandrillapp.comMailchimp Transactional (Mandrill)1
spf.brevo.comBrevo1
mail.zendesk.comZendesk1
mktomail.comMarketo1
spf.mtasv.netPostmark1
sendgrid.netSendGrid2
_spf.salesforce.comSalesforce2
mailgun.orgMailgun5

Most large vendors now list their IP ranges directly, so one include costs one lookup. The expensive ones are records that chain several includes, like Mailgun's, and anything you add twice through different vendors.

Fix 1: Remove what you don't need

Fix 2: Drop includes that don't affect your result

SPF checks the envelope sender (MAIL FROM / Return-Path), not the visible From address. Many bulk-mail and CRM platforms send with their own bounce domain, such as bounces.vendor.example. For those messages, receivers check the vendor's SPF record, not yours, so your include does nothing except use up lookups.

To check, send a test message from the service to an outside mailbox and paste the headers into the Email Header Analyzer. Look at smtp.mailfrom in Authentication-Results. If it isn't your domain (or a subdomain of it), the include is dead weight. For DMARC, set up DKIM signing with your domain at that vendor, or a custom return-path domain if the vendor offers one, which then needs its own SPF record (often a CNAME the vendor gives you). The DMARC alignment guide covers both.

Fix 3: Move senders to subdomains

SPF is evaluated per domain, so news.example.com gets its own 10-lookup budget and its own record. Send newsletters from news.example.com, transactional mail from mail.example.com and so on, and keep only the services that must send as the bare domain (usually Microsoft 365 or Google Workspace) on the root. DMARC at the organizational domain still covers subdomains through sp= or inheritance, so you don't lose protection. Microsoft also recommends subdomains for services you don't directly control.

Fix 4: Flatten carefully, or not at all

Flattening replaces an include with the ip4/ip6 ranges it currently resolves to, which costs zero lookups. The catch is that you stop following the vendor's changes: when they add a range, your record is wrong and their mail from that range fails SPF until you notice.

Check the fix before and after publishing

  1. Paste the new record into the optional box on the SPF Record Checker to count lookups before you change DNS. You can draft it with the SPF Record Builder.
  2. Publish it as a single TXT record at the domain (still exactly one record starting with v=spf1).
  3. Confirm resolvers see the new value with the DNS Propagation Checker (TXT), then rerun the checker against the live record.
  4. Send test messages from each remaining service and check for spf=pass in the Email Header Analyzer, or run the whole domain through the Email Deliverability Checker.
  5. Watch the next week of DMARC reports for any source that switched from pass to fail.

Audit hundreds of domains at once

Need SPF, DMARC and MX checks across a whole client list? Run the Bulk SPF / DMARC / MX Auditor on Apify ($2 per 1,000 domains).

Related tools and guides

Count lookups with the SPF Record Checker, draft a smaller record with the SPF Record Builder, find every real sender in your DMARC reports, and check SPF, DKIM, DMARC and MX together with the Email Deliverability Checker. Platform guides: SPF for Microsoft 365, SPF, DKIM and DMARC for Google Workspace and the bulk sender requirements.

FAQ

How many DNS lookups are allowed in an SPF record?

Ten. RFC 7208 limits the include, a, mx, ptr and exists mechanisms and the redirect modifier to 10 in total across the whole evaluation, including the ones inside records you include. The ip4, ip6 and all mechanisms do not count.

Do nested includes count toward the SPF limit?

Yes. If you include a vendor record that itself includes three more records, that one include costs four lookups out of your 10. This is why a record with only six includes can still go over the limit.

What happens when SPF has more than 10 lookups?

The receiver stops evaluating and returns permerror. SPF then fails for every message from the domain, and DMARC can only pass through an aligned DKIM signature.

What is an SPF void lookup?

A DNS lookup made during SPF evaluation that returns no records or a non-existent domain. RFC 7208 says receivers should allow at most two; a third is also a permerror. Stale includes for vendors you no longer use are a common cause.

Should I flatten my SPF record?

Only after removing unused senders and moving third-party senders to subdomains, and only for vendors with stable published ranges that you recheck regularly. Never flatten include:spf.protection.outlook.com, because Microsoft says its addresses change.

Want the full kit?

Runbooks, checklists and helpdesk templates: IT Admin Packs on Gumroad.