Learn

Multiple SPF records: why they break SPF and how to merge them

A domain may publish only one SPF record. With two, SPF returns a permanent error for every message, not just some. Here is how duplicates appear, how to find them and how to merge them into one.

By Ahmet Karaca · Updated · Checked against RFC 7208 (SPF) on

The rule, and what breaking it does

RFC 7208 is blunt about it. Section 3.2 says a domain name must not have multiple records that would cause an authorization check to select more than one record. Section 4.5 spells out what a receiver does: it fetches every TXT record at the domain, throws away the ones that do not begin with exactly v=spf1, and looks at what is left. No record means the result none. More than one means permerror, a permanent error that, in the RFC's words, definitely requires DNS operator intervention.

The receiver does not try to pick the better record or combine them. It stops. So the effect is not that half your senders fail; every message gets permerror, including mail from servers that both records list. A receiver may reject on that result; the RFC leaves it to local policy and names the SMTP reply to use if it does. For DMARC, a permanent error is simply not an SPF pass, so SPF can no longer align for anyone, and your mail passes DMARC only where it carries an aligned DKIM signature.

Other TXT records are not the problem. A domain can hold a site verification token, a key for some SaaS tool and one SPF record side by side; only records that start with v=spf1 count. The rule is also per name. Your root domain and mail.example.com each get their own single SPF record.

How a second record gets there

Nobody publishes two SPF records on purpose. The usual routes are mundane:

  • Following a second provider's instructions literally. A new sending service says "add this TXT record" and shows a complete value starting with v=spf1. Pasting it as a new record, rather than copying its include into the existing one, creates the duplicate, and from that moment SPF fails for the old services and the new one alike.
  • A DNS host or registrar template. Some panels can create a default SPF record when you register a domain or switch on their email product. Add your real record later and there are two.
  • Migrations. Moving from one mailbox provider to another, the new record goes in and the old one stays because removing things feels risky.
  • The old SPF record type. The first SPF standard, RFC 4408, gave SPF its own DNS record type, number 99. Section 14.1 of RFC 7208 retired it: implementations are not to use it, and only TXT records count. A leftover type-99 record does not cause the permanent error, but panels that show it next to the TXT record make it easy to edit the wrong one. Delete it once your TXT record is correct.

Find every SPF record you have

Run the domain through the SPF record checker. When it finds more than one record starting with v=spf1, it reports an error that names how many there are and shows all of them in one block, separated by a vertical bar, so you can compare them. It deliberately stops there: there is no include tree and no lookup count, because a receiver would not get that far either. The same check runs for every domain your record includes, so a duplicate inside a provider's own record is caught as well.

The domain health check scores the situation as harshly as receivers treat it. With two records there is no usable SPF policy, so all three SPF items fail at once: "SPF record published", "SPF within lookup limits", "SPF blocks unlisted servers", together 30 points of the score.

From a terminal, dig lists every TXT record at a name:

$ dig +short TXT example.com
"google-site-verification=…"
"v=spf1 include:_spf.google.com ~all"
"v=spf1 include:sendgrid.net -all"

The first line is unrelated and harmless. The other two both start with v=spf1, and that pair is the problem. Check the DNS panel too, because a record you are about to delete should be the one you actually see in DNS, not one you only remember adding.

Merge them into one record, step by step

Say the domain sends staff mail through Google Workspace and receipts through SendGrid, and each service's setup left its own record behind:

TXTHost@
v=spf1 include:_spf.google.com ~all

Before: record 1, from the Google Workspace setup

TXTHost@
v=spf1 ip4:192.0.2.25 include:sendgrid.net -all

Before: record 2, from the SendGrid setup plus an office server

  1. Write down every term from both records except the version tag and the ending. Here that is include:_spf.google.com, ip4:192.0.2.25 and include:sendgrid.net.
  2. Remove duplicates and anything retired. If both records include the same provider, keep it once. If one names a service you no longer use, this is the moment to drop it.
  3. Order them. Start with v=spf1, put ip4 and ip6 entries first since they need no DNS query, then the includes.
  4. Choose one ending. The two records disagreed, ~all against -all, and the merged record can have only one all, at the very end. If you are unsure, keep ~all for now; SPF ~all vs -all explains when the stricter ending is worth it.
  5. Edit one record and delete the other. Replace the value of one record with the merged value, then delete the second record. Do both in the same sitting, so the gap in which neither or both exist stays short.
TXTHost@
v=spf1 ip4:192.0.2.25 include:_spf.google.com include:sendgrid.net ~all

After: one record that authorizes all three senders

If one of the old records uses redirect= instead of an all ending, take care. RFC 7208 ignores redirect= whenever the record also contains all, so you cannot simply paste both together. Either turn the redirect target into an include: and keep your own all, or keep the redirect and leave all out. The SPF record generator builds a clean single record from a list of senders if you would rather start fresh than edit by hand.

Count the lookups again after merging

Each of the old records may have been comfortably under the limit on its own. Merged, their costs add up. Every include, a, mx, ptr, exists and redirect costs a DNS lookup, and so does every one of those inside the records you include. A receiver allows at most 10 per check; one more and the result is, once again, permerror, and you have traded one permanent error for another.

So once the merged record is live, run the domain through the SPF lookup counter again. Now that there is a single record, it follows every include, draws the tree and shows the total against the limit. If the total is close to 10, look for includes of services you have stopped using, and for services that do not need an SPF entry at all because they send with their own envelope domain and sign with DKIM. Fixing SPF "too many DNS lookups" explains which terms count and how to cut them safely.

Long values: split the string, not the record

Sometimes a second record appears because someone hit a length limit. A single string inside a TXT record holds at most 255 characters, and a record for a domain with many senders can be longer than that. The fix is not a second record. Section 3.3 of RFC 7208 lets one TXT record contain several quoted strings, which receivers join back together without adding spaces:

TXTHost@
"v=spf1 ip4:192.0.2.25 ip4:198.51.100.0/24 include:_spf.google.com " "include:sendgrid.net ~all"

One record made of two strings; note the space kept inside the first string

Because the strings are joined exactly as written, the space between two terms has to sit inside one of the strings, as at the end of the first string above. Some DNS panels split long values for you; others expect the quoted pieces pasted in. Either way it is still one record, and the SPF checker shows it joined. The RFC also asks that SPF answers stay small enough to fit in a single 512-byte DNS response, which is one more reason to prune includes rather than keep adding to a long record.

SPF setup guides by service

Mailbox providers

Marketing platforms

Transactional email

Help desks

Related tools and articles

We use Google Analytics cookies only if you accept. Privacy policy