Adding one SaaS tool broke your SPF record

You signed up for HubSpot. Or Intercom. Or a new helpdesk tool that sends emails on your behalf. You added the include: line they told you to add, waited for DNS to propagate, and now your DMARC reports are showing authentication failures that weren’t there before.

The error buried in the report XML says permerror. Removing the newest sender isn’t the fix.

What SPF permerror actually means

SPF has a hard limit: evaluating a single SPF record can trigger at most 10 DNS lookups. Per RFC 7208 §4.6.4, every include, a, mx, ptr, and exists mechanism counts toward that limit, plus the redirect modifier, recursively, through every record those mechanisms point to.

When a receiving server evaluates your SPF record and hits lookup number 11, it stops and returns permerror, a permanent error indicating the record is malformed. The message fails SPF. Under a DMARC policy of p=quarantine or p=reject, that failure can cost you delivered email. (For how permerror compares to temperror and when each matters, see DMARC permerror vs. temperror.)

The limit isn’t about the number of services you’ve listed. It’s about DNS resolutions. include:_spf.google.com alone costs 2–4 lookups depending on Google’s current SPF tree. include:sendgrid.net costs 2 more. include:_spf.salesforce.com adds another 3. Add a few more SaaS tools and you’re over the limit without realizing it.

There’s a second, quieter limit in the same section: “void lookups,” where a DNS query returns nothing or a name error. RFC 7208 §4.6.4 recommends capping those at 2. A stale include: pointing at a provider that deleted its SPF record burns a void lookup every time your record is evaluated. Worth checking if you’ve decommissioned a sender but never removed its include: line.

Why this is easy to miss

Most SPF checkers tell you whether your record is syntactically valid. They don’t always simulate the full recursive lookup tree at the exact moment you check, and third-party providers change their SPF includes periodically. A record that was fine in January can silently go over the limit in April when SendGrid reorganizes their IP ranges.

This makes the failure mode particularly frustrating: email was working, nothing you own changed, and it broke anyway.

How to count your current lookups

Run this command to see your record:

dig TXT example.com +short | grep "v=spf1"

Then for each include: in the output:

dig TXT _spf.google.com +short
dig TXT sendgrid.net +short
# repeat for each include

Count every include:, a, mx, ptr, exists, and redirect= you encounter, across all levels, recursively. If the number is 10 or above, you already have a problem even if you haven’t hit it yet.

A faster approach: DMARC Guardian’s DNS tab shows your current SPF lookup count next to any suggested fix, so you can see how close you are before you add the next sender. It also rechecks whenever your SPF tree changes upstream.

The wrong fix and the right fix

Wrong fix: Remove a service from your SPF record to get back under the limit.

This “fixes” the lookup count by deauthorizing a legitimate sender. That sender’s messages will now fail SPF. If they don’t have DKIM configured, DMARC will fail for their traffic too.

Right fix: Flatten your SPF record.

SPF flattening resolves all the include: mechanisms down to their actual IP addresses and replaces the recursive structure with a single list of IP ranges. Instead of:

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

You get something like:

v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.0/24 ip4:203.0.113.0/24 ... ~all

One DNS lookup. Every sender still authorized. Problem solved.

The catch with manual flattening

IP ranges for major sending services change regularly. Google, SendGrid, Mailgun, and others update their sending infrastructure without much announcement. If you flatten manually by copy-pasting current IP ranges, you’re one provider infrastructure change away from breaking your own SPF again.

Manual flattening requires continuous maintenance: subscribe to provider changelogs, re-flatten when they update, test, deploy. Most teams do this once and forget, then hit the exact same failure six months later.

Size warning: a flattened record with many IP ranges gets long. Classic DNS over UDP carries 512 bytes per response; bigger answers need EDNS0 or a TCP retry, and a resolver or firewall that blocks those can fail the lookup. Keep the flattened record short, or split it across include: records you control.

Hosted SPF flattening

The durable solution is hosted SPF flattening: instead of publishing the raw flattened IPs yourself, you publish a single include: that points to a record maintained automatically. The hosted service resolves your configured providers continuously and updates the published IP list when providers change their infrastructure. Your DNS record stays constant; the content stays accurate.

DMARC Guardian’s hosted SPF flattening works this way. You add your sending services to a list in the dashboard, and the service resolves them, flattens the result, and publishes it under a subdomain (spf.dmarc-guardian.com by default). Your SPF record becomes:

v=spf1 include:spf.dmarc-guardian.com ~all

One lookup from the receiver’s perspective. Automatic updates when providers change.

What to check before you flatten

Before publishing a flattened record, confirm two things:

1. You have the complete sender list. Run your DMARC reports for the last 30 days and pull every IP that passed SPF. Map those IPs to providers (DMARC Guardian’s IP attribution column does this automatically). If a provider’s IP appears in your passing traffic but isn’t in your include: list, it’s getting through on an ~all soft fail — add it before you flatten.

2. DKIM is configured for every sender. SPF and DKIM are independent paths to DMARC alignment. If you flatten SPF and a provider updates their IPs before the hosted service catches the change, DKIM is your backup authentication path. Any sender without DKIM configured is one provider IP change away from a DMARC failure. Check every active sender, and see SPF passes, DMARC fails: the alignment trap if you’re not sure how the two paths combine.

After you flatten

Your DMARC reports should show the permerror failures disappear within 24–48 hours after the new record propagates. Watch for two things:

  • Any sender suddenly failing that was passing before. This means a provider’s IPs weren’t fully captured in your source list. Add the provider and republish.
  • SPF alignment errors alongside DKIM passes. Some senders route through IPs outside their canonical SPF range. If DKIM is configured, these still pass DMARC, but they’re worth understanding.

A practical checklist

Before you add the next SaaS tool that wants an include: in your SPF:

  1. Check your current lookup count (DMARC Guardian DNS tab, or manual dig)
  2. If you’re at 7 or more, set up hosted SPF flattening before adding the new service
  3. Add the new service to your hosted SPF source list instead of the raw record
  4. Verify DKIM is configured for the new sender
  5. Confirm passes appear in your DMARC reports within 48 hours

Already past the limit and seeing failures today? Merging duplicate records or fixing syntax is usually faster than a full flatten.

The lookup limit is a design constraint from an era when companies sent email from one or two providers. Today, a typical startup uses Google Workspace, a transactional email service, a CRM, a helpdesk, and a marketing platform, all sending from your domain. Flattening is the right tool for that reality.


If you’re running DMARC aggregate reports and want to know whether you’re already close to the limit, DMARC Guardian’s DNS tab shows your current SPF lookup count next to your record and flags anything approaching 10.

Check your domain’s SPF lookup count →