Plainwork

Plainwork / Mail Auth Fix Sheet / SPF permerror: too many DNS lookups, how to fix

SPF "too many lookups" (permerror): the three fixes, in order

The short answer. An SPF record may trigger at most 10 DNS lookups while a receiver evaluates it. RFC 7208 section 4.6.4 says: "SPF implementations MUST limit the total number of those terms to 10 during SPF evaluation, to avoid unreasonable load on the DNS. If this limit is exceeded, the implementation MUST return "permerror"." A permerror means SPF fails for every message from your domain, including the legitimate ones. Fix it in this order: delete senders you no longer use, move bulk senders to their own subdomain, and only then flatten. Count your own record with the free checker.

What counts as a lookup

The terms include, a, mx, ptr and exists, and the redirect modifier, each cost one lookup, and the lookups inside an included record count too. The terms ip4, ip6 and all cost none. RFC 7208 also says "SPF implementations SHOULD limit "void lookups" to two": lookups that return nothing, such as an include pointing at a domain with no SPF record, count against a separate limit of two.

A real example, measured 2026-10-15 with the checker's own engine and cross-checked with a separate script: github.com publishes an SPF record with 8 include terms and it uses 10 of 10 lookups, with no room for another sender.

What well-known senders cost today

Each row is the cost of adding that sender's include to your record: one for the include itself plus any lookups nested inside it. The include text in each row is taken from that vendor's own help page (linked in the last column, read 2026-10-15), and the cost was then measured on 2026-10-15 from live DNS. Vendors change these records, so re-count yours rather than trusting this table in six months. HubSpot's include contains your own account number, so it has no single cost: count yours in the checker. Senders missing from the list (for example Mailchimp, Amazon SES, Salesforce, Brevo and Mailjet) are not "free": their own help pages could not be read here with the include text on them, so no number is printed.

Lookup cost of well-known SPF includes, measured 2026-10-15
SenderIncludeLookupsVendor page
Google Workspaceinclude:_spf.google.com1support.google.com
Microsoft 365include:spf.protection.outlook.com1learn.microsoft.com
SendGridinclude:sendgrid.net2twilio.com
Mailguninclude:mailgun.org5documentation.mailgun.com
Cloudflare Email Routinginclude:_spf.mx.cloudflare.net1developers.cloudflare.com
Zendeskinclude:mail.zendesk.com1support.zendesk.com
Postmarkinclude:spf.mtasv.net1postmarkapp.com
Zoho Mailinclude:zohomail.com2zoho.com
Fastmailinclude:spf.messagingengine.com1fastmail.help
HubSpotinclude:<your account number>.spf03.hubspotemail.netper accountknowledge.hubspot.com

To count a record you have not published yet, run the open-source checker from a clone: node cli.mjs yourdomain.com --spf "v=spf1 include:spf.messagingengine.com include:sendgrid.net ~all" prints the lookups of that proposed record, reading each include from live DNS.

Fix 1: delete what you no longer use

Most records over the limit carry dead senders: a newsletter tool cancelled two years ago, a CRM trial, an old helpdesk. Get the list of who really sends as your domain from your DMARC aggregate reports (the address in rua=) or from the "Authentication-Results" header of mail you received, and delete any include that appears in neither. This costs nothing and removes lookups permanently.

Fix 2: give bulk and transactional senders their own subdomain

SPF is evaluated against the envelope sender (Return-Path), not the visible From address. Many transactional services send with a Return-Path on a subdomain you delegate to them, so the root record does not need their include at all. For example, the root domain of this site publishes one include while its transactional sender uses a separate send. subdomain record. Mail still passes DMARC when the sender's DKIM signature uses your domain, because DMARC needs SPF or DKIM to pass and align. Check each vendor's own setup page for the subdomain option before removing anything, and test with a real message afterwards.

Fix 3: flatten only as the last step

Flattening replaces includes with the IP ranges behind them (ip4: and ip6: cost no lookups). It works, but vendors change their ranges without telling you, and a stale flattened record silently blocks real mail. If you flatten, do it with a service or script that refreshes the record on a schedule, keep the record under the DNS size limits, and never hand-copy ranges once and forget them. A DKIM-only setup with v=spf1 -all is another route that people ask about; it protects against forged envelope senders but receivers that check only SPF will reject your mail, so it needs DMARC reports first.

Check it worked

  1. Count again in the checker: total 10 or fewer, void lookups 2 or fewer.
  2. Send a message to a mailbox you control and read its Authentication-Results header: you want spf=pass or dkim=pass with the domain aligned with your From address.
  3. Publish or keep a DMARC record with a rua= address so you see failures before your customers do.

Want it written for you?

The Mail Auth Fix Sheet ($39, within 24 hours) takes your domain and the list of services that send as it, reads your live DNS and each service's current setup page, and returns the exact records to publish, a lookup budget and a safe order of changes. It is AI-written from public sources, never touches your DNS and cannot see your mail.

Sources

More from the catalogue

Other small tools

See everything →