Blog · Spf
How to Add Multiple Email Services to Your SPF Record Without Breaking It
Every time you add a third-party email service to your domain, you are probably adding an SPF include: mechanism. That mechanism chains to the service provider's own SPF record, which chains further. Add a few services and you are suddenly at 14 lookups. SPF hits its DNS limit, returns a permanent error, and all your legitimate mail starts failing -- silently.
This is one of the most common SPF mistakes, and one of the hardest to diagnose without knowing what to look for.
Why Your SPF Record Breaks When You Add a Second Email Service
RFC 7208 specifies that evaluating an SPF record must not require more than 10 DNS lookups. The limit exists because broken or circular SPF records could otherwise cause recursive DNS resolution storms.
Each of these mechanisms counts as one lookup when SPF evaluates your record:
include:(the mechanism most email services give you)amxptrexistsredir
The problem: every include: points to another SPF record, which may itself contain more include: mechanisms. If you have Google Workspace (which has its own nested includes) and Brevo and ImprovMX and a legacy SMTP provider, you can easily exceed 10 lookups before you hit a single ~all or -all directive.
When the lookup limit is exceeded, SPF returns PermError. Receiving servers treat this as a permanent authentication failure. Your mail gets flagged or rejected, and you may not be notified at all -- the failure often shows up only in your DMARC aggregate reports.
The PermError situation is particularly insidious because it does not show up as an SPF pass or fail in conventional monitoring. It shows up as an SPF alignment failure in your DMARC reports, which many practitioners misread as a DKIM problem or a spoofing problem when the real cause is a lookup count overflow.
How to Check if Your SPF Record Is Over the Lookup Limit
The fastest way to count your SPF lookups is to use an online SPF analyzer. These tools fetch your SPF record, follow every include chain recursively, and report the total lookup count in seconds.
You can also do it manually with dig:
dig TXT yourdomain.com | grep v=spf1
Then for each include:service.com mechanism, dig that service's TXT record and count again. Keep going until you have the full chain.
In your DMARC aggregate reports, look for sources that show SPF evaluating to PermError. A cluster of SPF failures with no clear pattern from a single service is a strong signal that your record has exceeded the lookup limit.
Three Ways to Fix an Over-Limit SPF Record
Option 1: Flatten Each Include to Direct IP Addresses
Instead of telling SPF to look up a provider's SPF record every time, you look up the IP addresses once and hard-code them in your own record.
Before:
v=spf1 include:_spf.brevo.com include:_spf.google.com ~all
After (if Brevo publishes fixed ranges):
v=spf1 ip4:152.199.0.0/16 ip4:142.250.0.0/15 include:_spf.google.com ~all
The challenge: many ESPs do not publish fixed IP ranges. They only give you an include. If you flatten an include and the provider rotates to new IPs without telling you, your flattened record goes stale and mail breaks again. Some providers (Brevo, SendGrid) publish their IP ranges explicitly. Others do not.
Option 2: Consolidate Email Services Under One Provider's Infrastructure
The cleanest long-term solution is to reduce the number of sending infrastructure you depend on. If one provider can handle both your transactional and your bulk sending, your SPF record shrinks to a single include mechanism.
This means accepting some trade-off in flexibility or cost, but it eliminates the lookup limit problem entirely and simplifies your email authentication story.
Option 3: Use a Dedicated Subdomain for Each Email Service
This is the most scalable approach for complex sending environments.
Instead of sending all mail from yourdomain.com, you use subdomains to segment sending infrastructure:
- Internal mail:
yourdomain.com-- SPF includes Google Workspace - Transactional mail:
send.yourdomain.com-- SPF points to Brevo - Marketing mail:
marketing.yourdomain.com-- SPF points to Mailchimp
Each subdomain has its own lightweight SPF record. None of them approach the 10-lookup limit.
This approach also gives you flexibility in your DMARC policy. You can set p=reject on your primary domain while running p=quarantine on a subdomain that has a legacy SMTP relay you have not yet migrated. DMARC policies apply independently per subdomain.
How to Structure an SPF Record That Supports Multiple Email Services
A practical template for a domain that uses Google Workspace and Brevo, with a dedicated subdomain for bulk mail:
Primary domain (yourdomain.com):
v=spf1 include:_spf.google.com ~all
Dedicated sending subdomain (send.yourdomain.com):
v=spf1 include:relay.brevo.com ~all
Bulk mail subdomain (marketing.yourdomain.com):
v=spf1 include:servers.mcsv.net ~all
Keep each record to two or fewer include mechanisms. Flatten wherever the provider publishes fixed IPs. Remove any include for a service you stopped using -- abandoned includes are a common source of unexpected lookup bloat.
Use ~all (softfail) while you are testing. Switch to -all (fail) only after you have confirmed that every legitimate sending source is covered and aligned.
How to Verify Your SPF Fix Using DMARC Aggregate Reports
Making the change is only half the work. You need to confirm the fix actually resolved the problem.
Set your DMARC policy to p=none (monitor only) before making any structural SPF changes, so you have a baseline. After the change, check your aggregate reports for:
- SPF alignment failures: did the total count decrease?
- PermError signals: did the permanent error count drop to zero?
- New failure sources: did the fix accidentally uncover an undiscovered sending source that was previously masked?
If you see new failures after flattening an include, it usually means the provider rotated IPs and your flattened record is now stale. Return to include: for that provider or update your IP list.
DMARCFlow aggregate reports break down SPF pass and fail by source IP and aligned domain, making it straightforward to confirm each sending service is now passing SPF before you tighten your DMARC policy. This is particularly valuable after restructuring your SPF record because you want to catch any stale includes before they cause a mail outage.
FAQ
Q: What exactly counts as one SPF lookup?
A: Each of these mechanisms triggers a DNS lookup when SPF evaluates your record: include:, a, mx, ptr, exists, and redir. Simple ip4: and ip6: mechanisms do not count because they resolve to direct IP addresses without a DNS query.
Q: Does ~all or -all count toward the lookup limit?
A: No. The ~all or -all directive at the end of your record does not count as a lookup. The limit applies to the mechanisms that come before it.
Q: Can I have more than one SPF record per domain?
A: Technically the RFC allows a maximum of two SPF records per domain. In practice, having two records is a configuration smell that usually indicates confusion about which record is authoritative. A single well-structured record is almost always preferable.
Q: One of my email services does not publish fixed IP ranges. What can I do?
A: Your options are: (1) use a dedicated subdomain for that service and keep its SPF record lightweight, (2) contact the service and ask if they offer dedicated IPs with published ranges, or (3) accept the include and keep your other includes to a minimum. For many SaaS email services, the include is the only option and you simply have to manage your lookup budget carefully.
Q: Will fixing my SPF record also fix my DMARC alignment?
A: Not always. SPF and DMARC are separate checks. Even if your SPF record is correct, DMARC alignment additionally requires your From address domain to match the domain used in the SPF check. If an email service sends from a different subdomain or a different domain entirely, you can have a perfect SPF record and still get DMARC failures. DMARC aggregate reports show both SPF-aligned and DKIM-aligned failures separately, so you can tell which one is the actual problem.