A DMARC report or a bounce line says spf=fail for mail from your own domain, and the campaign is due out in an hour.
You’ve already pulled up the SPF record, confirmed your ESP’s include is in it, and re-sent a test.
It still fails, because “fail” is at least four different results wearing the same label, and the fix for a PermError has nothing to do with the fix for a missing IP.
The next 10 minutes separate softfail, hardfail and PermError, then give you the specific cause and fix for each.
If you’re reading this at 11pm because mail from your domain started bouncing the day a new CRM went live, you’re in the right place.
Run a free audit → — paste your email headers and see every failing check, with the fix for each. No account.
The Four SPF Results (and What Each Actually Means)
Not every non-pass result is the same severity. In order from “working as intended” to “actively broken”:
Neutral — the record explicitly declines to make a claim about this sender (rare in practice; usually from a ?all qualifier, which is close to having no policy at all).
Softfail — the sending server isn’t in the authorized list, but the record’s ~all qualifier asks receivers to go easy on it: accept, but weight it as suspicious. This is a real result, and depending on the receiver it often still lands in spam, not the inbox.
Fail (hardfail) — the sending server isn’t in the authorized list, and the record’s -all qualifier tells receivers to reject it outright. This is the strict, correct setting once you’ve confirmed every legitimate source is actually listed.
PermError — the record itself is broken and can’t be evaluated at all. This is the one that surprises people, because it can affect mail from servers that are correctly configured — the whole record is invalid, not just one entry in it.
The Most Common Causes, and the Fix for Each
1. Two SPF records exist for the same domain
A domain can only have exactly one SPF TXT record. This happens more often than it should: an ESP’s setup wizard adds a new record without checking whether one already exists, or a second team member adds one independently. The result is a PermError — receivers are required by RFC 7208 to treat the whole check as broken, not just merge the two.
Fix: Check your DNS for every TXT record starting with v=spf1. If there’s more than one, merge every mechanism (every include:, ip4:, ip6:) from both into a single record, then delete the duplicate. The SPF Record Generator builds one clean merged record from a picklist of your actual sending services.
2. You’re over the 10-lookup limit
Every include, a, mx, exists, and redirect mechanism costs one DNS lookup, and RFC 7208 caps the total at 10. Cross that line and the entire record becomes a PermError — not gracefully degraded, just invalid. This is the failure mode that’s hardest to notice yourself, because the record still looks fine in a DNS lookup tool; it’s only invalid at evaluation time.
Fix: Count your lookups. Each ESP include: is usually 1, but some ESPs nest further includes inside their own record, silently costing more than 1. The SPF Record Generator shows a live running count as you add sources, so you catch this before publishing rather than after.
3. A sending source isn’t listed
The straightforward case: you added a new ESP, a new transactional-email service, or a self-hosted server, and never updated the SPF record. Depending on your all qualifier, this shows up as a hardfail (rejected) or softfail (accepted but suspicious).
Fix: Add the missing source. If it’s a known ESP (Google Workspace, Microsoft 365, SendGrid, Mailgun, Amazon SES, and others), the SPF Record Generator has it as a one-click addition. If it’s a self-hosted server, add its IP directly as an ip4:/ip6: mechanism.
4. DNS hasn’t propagated yet
You published a fix, but the failure is still showing up. DNS changes typically take minutes but can take up to 48 hours depending on your provider’s TTL settings and caching along the resolution path.
Fix: Wait, then re-check. The DNS Checker queries live via DNS-over-HTTPS, so it reflects the current published state rather than a cached result — if it still shows the old record after a few hours, confirm the change actually saved at your DNS provider, not just that you clicked save.
5. Subdomains aren’t covered
SPF records don’t automatically inherit to subdomains the way some assume. mail.yourdomain.com sending mail needs its own SPF record if it’s used as a From or Return-Path domain — the root domain’s record doesn’t cover it.
Fix: Publish a separate SPF record at the subdomain if it sends mail independently, using the same generator with the subdomain’s actual sending sources.
Softfail vs Hardfail: Which Should You Actually Use?
Use ~all (softfail) only while you’re actively confirming every legitimate source is listed — treat it as temporary, not a resting state. Once you’ve watched your mail flow for a week or two with no unexplained failures, move to -all (hardfail). A permanent softfail is a common half-finished setup: it’s not protecting you the way a hardfail does, but it’s also not the “safe default” it can look like — spoofed mail using your domain can still get through more easily than it should.
Frequently Asked Questions
- What’s the difference between SPF softfail and hardfail?
Hardfail (-all) tells receivers to reject mail from unlisted servers outright. Softfail (~all) asks them to accept it but treat it with more suspicion — usually meaning it’s more likely to land in spam rather than being rejected. Softfail is meant as a transitional setting while you’re still confirming every sending source is listed correctly, not a permanent configuration.
- Why did my SPF record suddenly start failing after months of working fine?
The two most common causes: you (or an ESP) added a new sending source without updating the SPF record, or an existing include (an ESP’s own SPF record) changed its underlying IP ranges — which is entirely outside your control and can happen without any notice.
- Can I have two SPF records for redundancy?
No — this is one of the most common self-inflicted SPF failures. A domain can only have one SPF TXT record. If a second one exists (often added by a new ESP’s setup wizard without checking for an existing one), receivers are required to treat the entire SPF check as a PermError, which behaves like a fail everywhere.
- What is a PermError and how is it different from a fail?
A PermError means the SPF record itself is broken — usually a duplicate record or too many DNS lookups (over RFC 7208’s limit of 10) — so the check can’t even be evaluated. A fail means the record is valid but the sending server genuinely isn’t listed in it. PermError is worse: it can affect every message from your domain, not just ones from an unlisted source.
