<?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: Petr Michal</title>
    <description>The latest articles on DEV Community by Petr Michal (@petr_michal_178dc4f87ad91).</description>
    <link>https://dev.to/petr_michal_178dc4f87ad91</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%2F4048945%2Fbe90c809-dd24-48b8-8939-345609d0779f.png</url>
      <title>DEV Community: Petr Michal</title>
      <link>https://dev.to/petr_michal_178dc4f87ad91</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/petr_michal_178dc4f87ad91"/>
    <language>en</language>
    <item>
      <title>Why SPF Breaks After Adding One More Email Provider</title>
      <dc:creator>Petr Michal</dc:creator>
      <pubDate>Mon, 27 Jul 2026 07:43:47 +0000</pubDate>
      <link>https://dev.to/petr_michal_178dc4f87ad91/why-spf-breaks-after-adding-one-more-email-provider-1jle</link>
      <guid>https://dev.to/petr_michal_178dc4f87ad91/why-spf-breaks-after-adding-one-more-email-provider-1jle</guid>
      <description>&lt;h1&gt;
  
  
  Why SPF Breaks After Adding One More Email Provider
&lt;/h1&gt;

&lt;p&gt;Your SPF record may look valid and still produce a &lt;code&gt;PermError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This often happens after connecting one more service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google Workspace&lt;/li&gt;
&lt;li&gt;Microsoft 365&lt;/li&gt;
&lt;li&gt;Mailchimp&lt;/li&gt;
&lt;li&gt;Zendesk&lt;/li&gt;
&lt;li&gt;a CRM&lt;/li&gt;
&lt;li&gt;a support platform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each &lt;code&gt;include:&lt;/code&gt; can trigger additional DNS lookups. SPF allows no more than &lt;strong&gt;10 DNS-triggering mechanisms&lt;/strong&gt; during one evaluation.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple-looking record
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=spf1 include:_spf.google.com include:servers.mcsv.net include:mail.zendesk.com -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The record contains only three &lt;code&gt;include:&lt;/code&gt; mechanisms, but each included record may contain more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;include&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;redirect&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exists&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The limit applies to the &lt;strong&gt;complete evaluation tree&lt;/strong&gt;, not only to the mechanisms visible in the root record.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens after the limit is exceeded
&lt;/h2&gt;

&lt;p&gt;The receiving mail server may return an SPF &lt;code&gt;PermError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That does not necessarily mean every message will be rejected. The final outcome depends on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the receiving provider,&lt;/li&gt;
&lt;li&gt;whether DKIM passes,&lt;/li&gt;
&lt;li&gt;whether SPF or DKIM aligns with DMARC,&lt;/li&gt;
&lt;li&gt;the receiver's local spam-filtering rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why the problem can appear inconsistent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one provider accepts the message,&lt;/li&gt;
&lt;li&gt;another sends it to spam,&lt;/li&gt;
&lt;li&gt;another reports an authentication failure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to diagnose it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Expand every &lt;code&gt;include:&lt;/code&gt; recursively.&lt;/li&gt;
&lt;li&gt;Count all DNS-triggering mechanisms in the full tree.&lt;/li&gt;
&lt;li&gt;Identify senders and providers that are no longer used.&lt;/li&gt;
&lt;li&gt;Check whether multiple services authorize the same infrastructure.&lt;/li&gt;
&lt;li&gt;Look for nested includes that consume more lookups than expected.&lt;/li&gt;
&lt;li&gt;Avoid blindly flattening records without understanding how the provider updates its IP ranges.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Counting only visible includes
&lt;/h3&gt;

&lt;p&gt;Three visible &lt;code&gt;include:&lt;/code&gt; mechanisms do not necessarily mean three DNS lookups.&lt;/p&gt;

&lt;p&gt;An included record may trigger several additional lookups of its own.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a second SPF record
&lt;/h3&gt;

&lt;p&gt;A domain should publish a single SPF policy.&lt;/p&gt;

&lt;p&gt;Adding another TXT record beginning with &lt;code&gt;v=spf1&lt;/code&gt; does not extend the existing policy. Multiple SPF records can instead cause a &lt;code&gt;PermError&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flattening and forgetting
&lt;/h3&gt;

&lt;p&gt;Flattening can reduce DNS lookups by replacing includes with IP addresses, but it also creates a maintenance obligation.&lt;/p&gt;

&lt;p&gt;If the provider changes its sending infrastructure and the flattened record is not updated, legitimate mail may stop passing SPF.&lt;/p&gt;

&lt;h2&gt;
  
  
  A safer way to fix it
&lt;/h2&gt;

&lt;p&gt;Start by mapping the complete lookup tree.&lt;/p&gt;

&lt;p&gt;Then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;remove obsolete providers,&lt;/li&gt;
&lt;li&gt;remove duplicate authorization paths,&lt;/li&gt;
&lt;li&gt;simplify unnecessary mechanisms,&lt;/li&gt;
&lt;li&gt;confirm which systems still send mail for the domain,&lt;/li&gt;
&lt;li&gt;flatten only where you understand the update and monitoring strategy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal is not only to get below 10 lookups today. The SPF policy should remain correct when providers change their infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the full lookup tree
&lt;/h2&gt;

&lt;p&gt;I built a free SPF lookup visualizer for this type of diagnosis:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mxfend.com/spf-lookup-visualizer/" rel="noopener noreferrer"&gt;Open the MXFend SPF Lookup Visualizer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It expands the recursive lookup tree and helps show where the SPF lookup budget is being consumed.&lt;/p&gt;

&lt;p&gt;You can also browse more SPF guides in the&lt;br&gt;
&lt;a href="https://mxfend.com/knowledge/spf/" rel="noopener noreferrer"&gt;MXFend SPF knowledge base&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclosure: I built MXFend. The visualizer is free to use and does not require an account.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>email</category>
      <category>dns</category>
      <category>security</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
