<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: bbu99054-a11y</title>
    <description>The latest articles on DEV Community by bbu99054-a11y (@bbu99054a11y).</description>
    <link>https://dev.to/bbu99054a11y</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4179260%2F18418dbf-746b-461b-b901-6781d8a73bdc.png</url>
      <title>DEV Community: bbu99054-a11y</title>
      <link>https://dev.to/bbu99054a11y</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bbu99054a11y"/>
    <language>en</language>
    <item>
      <title>Why include:mailgun.org actually costs 5 SPF lookups (and broke our email)</title>
      <dc:creator>bbu99054-a11y</dc:creator>
      <pubDate>Mon, 12 Oct 2026 12:19:06 +0000</pubDate>
      <link>https://dev.to/bbu99054a11y/why-includemailgunorg-actually-costs-5-spf-lookups-and-broke-our-email-kf4</link>
      <guid>https://dev.to/bbu99054a11y/why-includemailgunorg-actually-costs-5-spf-lookups-and-broke-our-email-kf4</guid>
      <description>&lt;p&gt;If you manage DNS for any web app or SaaS, your SPF record probably looks innocent enough:&lt;/p&gt;

&lt;p&gt;v=spf1 include:_spf.google.com include:mailgun.org include:sendgrid.net ~all&lt;/p&gt;

&lt;p&gt;Count the tokens: Google (1), Mailgun (1), SendGrid (1). That's 3 lookups.&lt;br&gt;
Well within the RFC 7208 limit of 10, right?&lt;/p&gt;

&lt;p&gt;Except it's actually 8 lookups.&lt;/p&gt;

&lt;p&gt;Add just one more service—say, a sales tool like Klaviyo or support mail via Zoho—and your entire SPF setup silently fails with a PermError. Inbound servers stop evaluating, DMARC alignment breaks, and transactional emails start landing in spam.&lt;/p&gt;

&lt;p&gt;Here is what is actually happening under the hood.&lt;/p&gt;

&lt;p&gt;The 10-Lookup Rule is Recursive&lt;br&gt;
RFC 7208 §4.6.4 limits DNS lookups to 10 to prevent mail servers from being abused as DDoS amplification vectors.&lt;/p&gt;

&lt;p&gt;Most people assume each include: directive in their DNS dashboard equals 1 lookup. But receiving mail transfer agents (MTAs) don't stop at the first TXT record—they recursively follow every nested include until they hit raw IP addresses.&lt;/p&gt;

&lt;p&gt;And some popular email providers nest much deeper than you'd expect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Mailgun (mailgun.org) = 5 Lookups&lt;/strong&gt;&lt;br&gt;
When you add include:mailgun.org, here is the actual DNS resolution path that the receiving server has to walk:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;mailgun.org&lt;br&gt;
└── points to: include:_spf.mailgun.org include:_spf.eu.mailgun.org (Lookup 1)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;_spf.mailgun.org&lt;br&gt;
└── points to: include:_spf1.mailgun.org include:_spf2.mailgun.org (Lookup 2)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;_spf.eu.mailgun.org&lt;br&gt;
└── resolves EU pool IPs (Lookup 3)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;_spf1.mailgun.org&lt;br&gt;
└── resolves US pool 1 IPs (Lookup 4)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;_spf2.mailgun.org&lt;br&gt;
└── resolves US pool 2 IPs (Lookup 5)&lt;br&gt;
One line in your DNS record just burned 50% of your global lookup budget.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;2. Zoho Mail (zoho.com) = 5 Lookups&lt;/strong&gt;&lt;br&gt;
Zoho does something similar with its regional clusters:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;zoho.com&lt;br&gt;
└── points to: include:spf.zoho.com (Lookup 1)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;spf.zoho.com&lt;br&gt;
└── contains 4 regional cluster includes:&lt;br&gt;
   ├── include:spf1.zoho.com (Lookup 2)&lt;br&gt;
   ├── include:spf2.zoho.com (Lookup 3)&lt;br&gt;
   ├── include:spf3.zoho.com (Lookup 4)&lt;br&gt;
   └── include:spf4.zoho.com (Lookup 5)&lt;br&gt;
Again, 5 lookups for a single provider.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Real Problem: Silent Failures&lt;br&gt;
If you combine:&lt;/p&gt;

&lt;p&gt;Google Workspace: 1 lookup (_spf.google.com)&lt;br&gt;
SendGrid: 2 lookups (sendgrid.net → ab.sendgrid.net)&lt;br&gt;
Mailgun: 5 lookups&lt;br&gt;
You are at 8/10.&lt;/p&gt;

&lt;p&gt;If anyone on your marketing or sales team adds Klaviyo (3 lookups) or Zoho (5 lookups) to the root domain: 8 + 3 = 11 lookups&lt;/p&gt;

&lt;p&gt;The moment a DNS query count hits 11, the receiving server (Google, Microsoft, Yahoo) immediately throws PermError and aborts.&lt;/p&gt;

&lt;p&gt;Your DNS dashboard (Cloudflare, Route53, Namecheap) will show a green checkmark because the syntax itself is valid. But inbound servers will treat SPF as a complete failure.&lt;/p&gt;

&lt;p&gt;How to Fix It&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stop putting every service on the apex domain
The cleanest solution is subdomain isolation:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keep corporate mail on the root domain: example.com (include:_spf.google.com ~all)&lt;br&gt;
Move transactional mail to a subdomain: mail.example.com (include:mailgun.org ~all)&lt;br&gt;
Move marketing newsletters to another: news.example.com (include:sendgrid.net ~all)&lt;br&gt;
Each subdomain gets its own fresh 10-lookup quota.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check your actual recursive count
Don't trust tools that just count the number of words in your TXT string. You need to trace the actual recursion tree.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I got tired of manually running dig chains across DNS providers, so I put together a quick client-side tool to do the recursive walk in-browser: 👉 &lt;a href="https://tools.postsyncapp.com" rel="noopener noreferrer"&gt;https://tools.postsyncapp.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It queries Cloudflare and Google DoH (DNS-over-HTTPS) APIs directly from your browser, counts the real nested lookups, and flags if you're close to the PermError line. No signup required and zero backend storage.&lt;/p&gt;

&lt;p&gt;If you haven't checked your root domain's SPF lookup count recently, trace it. You might be closer to 10 than you think.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>sysadmin</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
