SPF record flattening: a practical guide

When you need it, when you don't, and how to do it without breaking email delivery.

SPF flattening is the process of replacing include: mechanisms in your SPF record with the IP addresses they resolve to. The goal is to reduce the number of DNS lookups during SPF evaluation and stay within the 10-lookup limit defined in RFC 7208, Section 4.6.4.

Flattening works, but it comes with its own problems. This guide explains what flattening does, when it makes sense, and when a different approach is the better call.

What you will learn

Why the 10 DNS lookup limit exists and what happens when you exceed it
How SPF flattening works and the trade-offs it creates
The risks: stale IP addresses, TTL mismatches, and lost troubleshooting context
Alternatives to flattening that may be a better first step

The problem: too many DNS lookups

Every time a receiving mail server evaluates your SPF record, it performs DNS lookups for each mechanism that requires one. RFC 7208 caps this at 10 lookups per evaluation. Exceed that, and the receiver returns PermError. SPF fails. If DKIM also fails or is missing, your DMARC policy applies, and email may be quarantined or rejected.

Why the limit exists

The limit is a security measure. RFC 7208, Section 11.1 describes the attack scenario: an attacker creates an SPF record referencing a victim's domain many times, then sends emails to many different mail servers. Each server performs DNS lookups against the victim's domain while evaluating SPF, amplifying the attacker's traffic into a distributed denial-of-service attack against the victim's DNS infrastructure. The 10-lookup cap limits this amplification factor.

What counts and what does not

Mechanisms that count (1 lookup each):

  • include: — plus all mechanisms inside the included record count against the same budget
  • a
  • mx
  • exists:
  • redirect= modifier
  • ptr (deprecated per RFC 7208 Section 5.5, avoid using)

Mechanisms that do not count:

  • ip4: — specifies IPv4 addresses directly, no DNS query needed
  • ip6: — specifies IPv6 addresses directly, no DNS query needed
  • all — catch-all, no DNS query
  • exp= modifier — only queried after evaluation, not during

The initial DNS query to retrieve the SPF TXT record itself does not count toward the 10-lookup limit. The limit applies to mechanisms evaluated within the record.

Includes are recursive. When you write include:_spf.google.com, the receiver looks up that record (1 lookup), then evaluates the mechanisms inside it. If Google's record contains more include: mechanisms, those count too. A single Google Workspace include can consume 3-4 lookups from your budget.

# This looks like 5 mechanisms, but the recursive includes push the total to 12-15 lookups: v=spf1 include:_spf.google.com include:sendgrid.net include:spf.protection.outlook.com include:servers.mcsv.net include:mail.zendesk.com ~all # Approximate expansion: # include:_spf.google.com → 1 + 3 nested includes = 4 lookups # include:sendgrid.net → 1 + 1 nested include = 2 lookups # include:spf.protection.outlook.com → 1 + 2 nested includes = 3 lookups # include:servers.mcsv.net → 1 lookup # include:mail.zendesk.com → 1 + 1 nested include = 2 lookups # Total: ~12 lookups → PermError

The void lookup limit

There is a second, less-known limit. RFC 7208 Section 4.6.4 also defines void lookups: DNS queries that return NXDOMAIN (domain does not exist) or NOERROR with zero answers. Implementations should limit these to 2. Exceeding this also produces a PermError.

This matters because stale include: references to decommissioned vendor domains or typos can trigger void lookups. Two such stale references anywhere in the evaluation chain, including inside nested includes, can break SPF.

How SPF flattening works

Flattening replaces include: mechanisms with the ip4: and ip6: addresses they ultimately resolve to. Since ip4: and ip6: do not count toward the 10-lookup limit, this reduces your DNS lookup count.

# Before flattening (12+ DNS lookups): v=spf1 include:_spf.google.com include:sendgrid.net include:spf.protection.outlook.com ~all # After flattening (0 DNS lookups from these mechanisms): v=spf1 ip4:209.85.128.0/17 ip4:74.125.0.0/16 ip4:172.217.0.0/19 ip4:167.89.0.0/17 ip4:208.117.48.0/20 ip4:40.92.0.0/15 ip4:40.107.0.0/16 ip6:2a00:1450:4000::/36 ~all

That is the basic operation. In practice, a flattening process works like this:

  1. Read the current SPF record and identify include: mechanisms
  2. Resolve each include recursively, following nested includes until you reach ip4: and ip6: entries
  3. Replace the includes with the resolved IP ranges
  4. Publish the updated record in DNS

The risks of flattening

Flattening fixes the lookup count. It also creates problems you did not have before.

1. Stale IP addresses

Email providers add, remove, and rotate their sending IP addresses. Google, Microsoft, SendGrid, and others update their SPF records when their infrastructure changes. With include:, your SPF record dynamically references theirs, and changes propagate automatically. With flattened IPs, you have a snapshot from the moment of flattening. When the provider changes their IPs, your record becomes stale.

If a provider starts sending from a new IP that is not in your flattened record, those emails fail SPF. You will not know until you see failures in your DMARC reports or your recipients complain.

2. TTL and propagation delays

DNS records are cached by resolvers worldwide based on their TTL (Time To Live) value. Even after you update your flattened record, receiving servers may continue using the old cached version until the TTL expires.

If your SPF record has a TTL of 3600 seconds (1 hour), there is up to a 1-hour window where some receivers see the old IPs and others see the new ones. If a provider adds a new IP and you update your record immediately, emails from that new IP still fail SPF for receivers using cached records.

For flattened records, keep the TTL short. 300 seconds (5 minutes) is a common recommendation. Shorter TTLs mean faster propagation of updates, but they also increase DNS query volume to your authoritative servers.

3. TXT record size limits

Each include: you flatten expands into multiple ip4: and ip6: entries. A single provider's include can resolve to dozens of IP ranges. DNS TXT records have a 255-byte limit per string (RFC 1035), and the total response should ideally stay under 512 bytes to avoid UDP truncation and TCP fallback.

Large flattened records may need to be split across multiple DNS records or delegated behind a single include: that points to a hosted record containing the flattened IPs.

4. Lost troubleshooting context

include:sendgrid.net immediately tells you which service is authorized. ip4:167.89.0.0/17 does not. When troubleshooting delivery issues, flattened records make it harder to identify which provider an IP belongs to.

5. Macros cannot be flattened

Some providers use SPF macros (defined in RFC 7208, Section 7) like %{i} (connecting IP) or %{d} (current domain) in their SPF records. These resolve dynamically based on the sending context. You cannot flatten them into static IPs because the result depends on who is sending and from where. Any include containing macros must stay as-is.

Before you flatten: check if you actually need to

Flattening is one solution to the 10-lookup problem, but it should not be your first move. There are four alternatives that can reduce your lookup count without the maintenance burden.

1. Remove includes you do not need

This is the most effective step and the one most often skipped. Many SPF records contain includes for services that do not actually require them.

SPF validates the Return-Path (envelope sender, RFC5321.MailFrom) domain, not the visible From header. Many email service providers use their own domain as the Return-Path, not yours. In those cases, SPF validation happens against their DNS records, and adding their include to your SPF record wastes a lookup.

Providers like Mailchimp, HubSpot, Brevo (Sendinblue), Zendesk, and Freshdesk use their own Return-Path domain. They rely on DKIM for DMARC alignment. Adding include:servers.mcsv.net (Mailchimp) to your root domain's SPF record does nothing for DMARC compliance. It just burns one of your 10 lookups.

For a full breakdown of which providers need SPF includes and which do not, see the Return-Path and provider SPF requirements section in our SPF overview.

How to check

Send a test email through each service and inspect the headers. Look for the Return-Path header. If the domain is the provider's (like mcsv.net or hubspotemail.net), you do not need their include in your SPF record. Configure DKIM with that provider instead.

2. Use subdomains for different email streams

Each subdomain gets its own SPF record with its own 10-lookup budget. Instead of cramming everything into your root domain's SPF:

# Root domain: only corporate mail example.com TXT "v=spf1 include:_spf.google.com -all" # Marketing subdomain: only the marketing ESP marketing.example.com TXT "v=spf1 include:servers.mcsv.net -all" # Transactional subdomain: only the transactional ESP notify.example.com TXT "v=spf1 include:sendgrid.net -all"

This approach also improves deliverability visibility by isolating sender reputation per email stream. Marketing campaigns do not affect transactional email reputation, and vice versa.

The trade-off is DMARC alignment. If you send from subdomains, your DMARC record on the root domain must use relaxed alignment (aspf=r, which is the default) for SPF to align. DKIM alignment follows the same logic with adkim=r. For a detailed explanation, see our guide on DMARC, SPF, and DKIM alignment.

3. Rely on DKIM alignment instead of SPF

DMARC passes if either SPF or DKIM passes with alignment. You do not need both. For services where DKIM is properly configured, you can remove the SPF include and rely on DKIM alone for DMARC compliance.

This is especially useful for third-party services. Configure DKIM signing with your domain on the provider's side, verify it works in your DMARC reports, and remove the SPF include.

4. Audit regularly

SPF records accumulate includes over time. A team signs up for a cold outreach tool, adds the include, and never removes it when the trial ends. Another team switches ESPs but leaves the old include in place. Quarterly audits of your SPF record against your actual sending services prevent this drift.

Use our free SPF record generator to rebuild your record from scratch with only the services you currently use, and compare it against what is published in DNS.

When flattening makes sense

After you have removed unnecessary includes, moved services to subdomains where practical, and confirmed DKIM alignment for providers that support it, you may still be over the 10-lookup limit. This is common for organizations with complex email infrastructure: corporate mail (Google Workspace or Microsoft 365), multiple transactional providers, CRM systems, and support platforms that all require SPF includes on the root domain.

At that point, flattening makes sense. You can do it manually or use an automated service.

Manual flattening

You resolve each include yourself using dig or nslookup, collect the IP ranges, and publish them in your SPF record.

# Resolve an include to see what IPs it contains: dig TXT sendgrid.net +short # Returns: "v=spf1 ip4:167.89.0.0/17 ip4:208.117.48.0/20 ..." # For nested includes, follow the chain: dig TXT _spf.google.com +short # Returns: "v=spf1 include:_netblocks.google.com include:_netblocks2.google.com ..." dig TXT _netblocks.google.com +short # Returns: "v=spf1 ip4:35.190.247.0/24 ip4:64.233.160.0/19 ..."

Manual flattening is free and gives you full control. The problem is maintenance. When a provider changes their IPs, you need to detect the change and update your record. Missing an update means legitimate email fails SPF. For one or two includes, manual flattening is manageable. For five or more, it becomes a recurring operational burden.

Automated SPF flattening services

Automated services handle the resolution, monitoring, and updating cycle for you. They typically work by hosting the flattened IPs behind a single include: on their own infrastructure:

  1. You configure which includes to flatten
  2. The service resolves them into IP addresses
  3. It publishes those IPs at a hosted DNS record
  4. Your SPF record points to that single hosted include
  5. The service monitors for IP changes and updates its hosted record automatically

This reduces your SPF record to one include (1 DNS lookup) regardless of how many services are behind it.

DMARCTrust Pro includes an SPF Optimizer that handles this process. It detects which includes can be safely flattened (skipping macros), resolves them on a regular schedule, and publishes the results automatically. Other vendors offer similar tools as standalone products.

If you flatten: best practices

Whether you flatten manually or use a service, follow these guidelines to minimize risk.

Keep TTLs short

Set the TTL on your SPF TXT record to 300 seconds (5 minutes) if you are actively managing a flattened record. Changes propagate faster with short TTLs. Only increase it once the record is stable and your monitoring is in place.

Monitor for provider IP changes

If you flatten manually, set a recurring reminder (weekly at minimum, daily if possible) to re-resolve the original includes and compare against your published record. Automated services handle this, but verify they are actually detecting changes by checking their logs or alerts.

Keep non-flattenable mechanisms intact

Mechanisms that use macros (%{d}, %{i}, %{l}) must not be flattened. Neither should the redirect= modifier if your SPF architecture depends on it. Only flatten include: mechanisms that resolve to static IP lists.

Preserve a, mx, and direct IP entries

If your SPF record contains a, mx, or direct ip4:/ip6: entries alongside includes, keep them as-is. These are your own infrastructure and should not be merged into a flattened record managed by a third party.

Test before publishing

After building a flattened record, validate it before publishing. Check that:

  • The total DNS lookup count is within the 10-lookup limit
  • The TXT record is syntactically valid
  • The record size fits within DNS limits (ideally under 512 bytes per response, or split across delegated records)
  • All your legitimate sending IPs are covered

Our free domain checker shows your current DNS lookup count and validates your SPF record syntax.

Summary: a decision framework

Situation Recommended action
Under 8 DNS lookups No action needed. You have headroom.
8-10 lookups, some includes are unnecessary Audit your includes. Remove ones for providers that use their own Return-Path. Check DKIM alignment.
Over 10 lookups, multiple distinct email streams Move email streams to subdomains. Each gets its own SPF budget.
Over 10 lookups after cleanup and subdomain delegation Flatten the remaining includes. Use an automated service for ongoing maintenance.
1-2 includes to flatten, stable providers Manual flattening is feasible. Monitor weekly for IP changes.
3+ includes to flatten, providers that rotate IPs Use an automated flattening service. Manual maintenance at this scale is error-prone.

Tools and further reading