Why it matters
A PermError means the domain effectively has no working SPF policy. Receivers commonly treat this as an SPF failure, so legitimate mail can be sent to spam or rejected, even if one of the two records would have authorized the sender. It also breaks DMARC: SPF cannot produce a "pass" for alignment, removing one of the two authentication paths DMARC relies on, which weakens both deliverability and your defense against spoofing. Because the failure is silent (mail still leaves your server; only receivers see the error), it often goes unnoticed until deliverability drops. This is governed by RFC 7208: Sender Policy Framework (SPF).
Common causes
- Two teams or vendors each published their own SPF record (e.g. one for Google Workspace, one for a marketing platform) instead of merging them into one
- A new email service's setup wizard told you to 'add this TXT record' and you added a second v=spf1 record rather than editing the existing one
- A copy of the SPF record was left behind after a migration between email providers
- DNS was managed in two places (registrar panel plus a separate DNS host) and each holds its own SPF record
- An automated provisioning tool or IaC template appended an SPF record without checking whether one already existed
- Confusing SPF with DKIM/DMARC and adding a 'second' record thinking each sender needs its own
How to fix Multiple SPF Records
- Enumerate every TXT record on the exact domain: run `dig +short TXT example.com` (or nslookup -type=txt) and identify each string that starts with v=spf1. There must be exactly one; more than one is the bug.
- Inventory the authorized senders from ALL of the v=spf1 records: collect every include:, a, mx, ip4:, and ip6: mechanism across them so nothing legitimate is dropped when you consolidate.
- Merge them into a SINGLE v=spf1 record containing the union of those mechanisms, ending with one 'all' qualifier (use ~all soft-fail while validating, -all hard-fail once confident). Example: v=spf1 include:_spf.google.com include:sendgrid.net ip4:203.0.113.10 ~all
- Delete the extra v=spf1 TXT record(s) so only the merged one remains. Keep non-SPF TXT records (DKIM, DMARC, domain verification) untouched, they legitimately coexist.
- Check the DNS-querying mechanism count while merging: SPF permits at most 10 DNS lookups across the full recursive expansion (include, a, mx, ptr, exists, and the redirect modifier count; ip4/ip6/all do not). include:_spf.google.com alone costs several. If you exceed 10 you trade a multiple-record PermError for a too-many-lookups PermError: remove unused senders, delegate senders to subdomains (e.g. mail.example.com) with their own SPF, or flatten includes to static ip4/ip6 ranges (accepting that flattened IPs must be re-checked as vendors change them).
- Wait for DNS TTL/propagation, then re-verify with `dig +short TXT example.com` (one v=spf1 record) and confirm a validator reports 'pass' rather than PermError. Watch your DMARC aggregate (RUA) reports over the next few days to confirm SPF now aligns and passes.
Frequently asked questions
Can I have two SPF records if one is for a subdomain?
Yes. The one-record rule is per domain name. example.com may have one v=spf1 record and mail.example.com may have its own separate one. The error only occurs when two v=spf1 records exist at the *same* name. Delegating a sender to a subdomain is in fact a recommended way to spread out senders and stay under the 10-lookup limit.
Will receivers just pick the record that passes?
No. RFC 7208 requires the check to return PermError as soon as more than one v=spf1 record is found. Receivers must not merge them or choose one, so you get zero working policy rather than a lucky pass. Never rely on this behavior.
Do DKIM and DMARC records count as extra SPF records?
No. Only TXT records beginning with 'v=spf1' are SPF. DKIM (selector._domainkey), DMARC (_dmarc), and verification TXT records are separate and can - and should - coexist with your single SPF record.
How do I add a new email vendor without creating a second record?
Edit your existing SPF record and add the vendor's include: (or ip4:/ip6:) mechanism inside it, before the 'all' term. Do not publish the vendor's snippet as its own record. Recheck that you're still within 10 DNS lookups afterward.