Too Many DNS Lookups: Fix SPF PermError for Google, Microsoft 365 & SendGrid

Published September 11, 2026 ยท 6 min read ยท spFlat!

"Too many DNS lookups" is still the most common reason SPF records fail at runtime. The 10-lookup limit in RFC 7208 is a hard ceiling: the 11th DNS-querying term stops evaluation with a PermError. That is not the same as an SPF fail, but many receivers (including Gmail) treat it badly enough that deliverability takes a hit.

The trap is counting the include: tokens you typed. Receivers count the whole chain. Google Workspace and Microsoft 365 have flattened their own records recently, so those two look cheap. Add SendGrid, Mailgun, or a CRM, and the math goes over 10 without anyone editing the obvious parts of your TXT record.


Why "too many DNS lookups" happens

Every include:, a, mx, ptr, exists, and redirect= counts as a DNS lookup. Nested includes count too. Direct ip4: and ip6: mechanisms do not. The initial lookup of your own SPF TXT record also does not count.

A record that looks like five includes is not five lookups:

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

Resolved today, that stack is typically 11 lookups - already over the limit:

  • _spf.google.com - Google now publishes IP ranges directly: 1 lookup
  • spf.protection.outlook.com - Microsoft 365 is also a flat IP list: 1 lookup
  • sendgrid.net still nests include:ab.sendgrid.net: 2 lookups
  • mailgun.org fans out through _spf.mailgun.org โ†’ _spf1/_spf2 plus the EU record: 5 lookups
  • _spf.salesforce.com uses exists: on top of the include: 2 lookups
Vendor numbers drift. Google used to be four nested netblock includes. They flattened themselves. Last year's "Outlook is 3 lookups" is not this year's. Re-check the live chain; do not memorize a blog table forever.

Provider by provider

Google Workspace

Your Google include is one line:

v=spf1 include:_spf.google.com ~all

In 2026 that record is a list of ip4:/ip6: ranges, so it costs 1 lookup. It used to resolve through _netblocks.google.com, _netblocks2 and _netblocks3 (about 4 lookups). The leftover netblock names still exist; Google's top-level SPF no longer includes them. Cheap on its own - still 1 of your 10.

Microsoft 365

Exchange Online uses include:spf.protection.outlook.com. That record is currently a flat IP list as well: 1 lookup. The trap is everything a Microsoft shop adds next: a marketing platform, Dynamics, a security gateway, or a second tenant include. Those are extra lookups on a budget that is already partly spent.

SendGrid

SendGrid still nests:

include:sendgrid.net

sendgrid.net publishes a long IP list and include:ab.sendgrid.net. Fully resolved that is 2 lookups. Combined with Google, Outlook, Mailgun and a CRM, you are already over 10.

How to detect it (before mail is treated as unauthenticated)

Option 1: The SPFlat! checker (free, no signup)

Go to spflat.cloud, enter your domain and hit Check. SPFlat! resolves the full chain including nested includes and shows the lookup count a receiver would use - not the top-level token count.

Option 2: Manual dig

dig TXT yourdomain.com +short | grep -o 'include:[^ ]*' | while read inc; do
  dig TXT ${inc#include:} +short
done

This gives a rough count, but misses nested recursion unless you loop deeper - which is exactly where the extra lookups hide.

๐Ÿ”ด The kicker: some DNS validators stop at 10 lookups and do not show the rest of the tree. Your record can look "almost fine" in a dashboard and still PermError at the receiver.

How to fix it

The hard way: manual flattening

  1. Resolve every include:, a: and mx: in your record
  2. Collect all resulting IP addresses and CIDR ranges
  3. Build a new record with only ip4: and ip6: mechanisms
  4. Publish it and hope the providers don't change their ranges
โš ๏ธ The problem: Google, Microsoft and SendGrid rotate IP ranges. A manually flattened record goes stale - and you only find out when mail starts bouncing. Dumping every CIDR onto your own domain also blows past DNS size limits; see the 255-character / TXT size problem.

The smart way: SPFlat!

SPFlat! keeps the record a receiver evaluates under the 10-lookup limit and current:

  1. Check your domain - see the real lookup count instantly
  2. Add your sending services (Google, Microsoft 365, SendGrid, Mailgun, and whatever else you actually use)
  3. Publish one include - typically v=spf1 include:_yourdomain.spf.spflat.cloud ~all (one lookup). SPFlat! monitors provider IP changes 24/7 and updates the flattened record behind that include.

Prevention

  • Add new services through SPFlat! instead of editing the TXT record directly
  • Re-check after every provider change - one new include can silently push you over the limit
  • Monitor DMARC reports - a sudden drop in SPF alignment is often the first sign of a broken chain

๐Ÿ” Check your domain now

Ten seconds. Free. See exactly how many lookups your SPF record consumes - including all nested includes. Over 10? Flatten with SPFlat! in a 14-day trial.

Check Your SPF
Or start your free 14-day trial โ†’