Diagnostic tutorial for SPF failures: identify what failed, why, and how to fix it. Covers spf=fail, spf=softfail, spf=permerror, spf=temperror, and spf=none in Authentication-Results, with command-line diagnostics and a decision tree to reach the root cause quickly.
spf=failspf=softfailspf=permerrorspf=temperrorspf=noneObtain the delivered message's Authentication-Results header. The SPF entry looks like:
Authentication-Results: mx.google.com;
spf=fail (google.com: domain of [email protected] does not designate 203.0.113.99 as permitted sender)
[email protected]Note three values:
fail, softfail, permerror, temperror, or none.smtp.mailfrom= shows the envelope sender domain.spf=failMeans the IP is not listed in the domain's SPF record, and the record terminates with -all. Three common root causes:
A new SaaS platform started sending as your domain; you never added it. Fix:
dig -x 203.0.113.99. PTR usually reveals the provider.v=spf1 include:existing include:provider.net -all.Provider rotated infrastructure; their macro updated but your flattened SPF is stale. Fix:
IP belongs to an attacker, not a legitimate sender. SPF correctly rejected. No action needed — DMARC enforcement handles. If attacker returns persistently, investigate via DMARC aggregate reports.
spf=softfailIP not authorised but record terminates with ~all. Same causes as fail, but your policy is permissive. If legitimate sender, add to SPF as above. Additionally: consider tightening ~all to -all once all senders are confirmed.
spf=permerrorPermanent error in SPF record itself. Severe — no SPF evaluation possible for your domain at all. Common causes:
Your SPF exceeds the 10-lookup ceiling. Diagnostic:
# Use MXToolbox SPF check or:
spfcheck firm.co.ukIf lookup count > 10, flatten some includes or consolidate senders. See SPF Flattening.
Malformed SPF. Common errors:
v=spf1 prefix.Diagnose:
dig TXT firm.co.uk | grep v=spf1Should return exactly one line; record content should match RFC 7208 syntax. Fix any malformed content.
ptr mechanismSome receivers treat ptr as permerror. Remove ptr from record.
spf=temperrorTransient DNS failure during evaluation. Usually self-resolving. If persistent:
dig TXT firm.co.uk @1.1.1.1 and @8.8.8.8.spf=noneNo SPF record published. Publish one immediately. See What Is SPF? for format.
Quick deploy for UK SME:
firm.co.uk. IN TXT "v=spf1 include:_spf.smartxhosting.uk -all"Adjust include to match your actual mail provider.
Authentication-Results shows spf=?
├── pass → no action
├── fail
│ ├── IP belongs to known legitimate sender → add to SPF
│ ├── IP unknown → investigate sender or treat as spoofing
│ └── IP is forwarder → SPF expected to fail; rely on DKIM + ARC
├── softfail → same as fail (but your SPF uses ~all instead of -all)
├── permerror
│ ├── Lookup count > 10 → flatten or consolidate
│ ├── Syntax error → fix record
│ └── Deprecated mechanism → remove ptr
├── temperror → DNS health check; retry; usually self-resolves
└── none → publish SPF record# Retrieve SPF record
dig TXT firm.co.uk | grep v=spf1
# Count lookups (approximate)
dig TXT firm.co.uk +short | grep v=spf1 | tr ' ' '\n' | grep -E '^(include|a|mx|exists|redirect|ptr):' | wc -l
# Check reverse DNS of sending IP
dig -x 203.0.113.99
# Check specific DNS server
dig TXT firm.co.uk @1.1.1.1
# Send test and verify at Port25
echo "Test" | mail -s "SPF Test" [email protected]
# Check DMARC aggregate reports for SPF failures per source
# (via your DMARC processing tool)Customer migrated from on-premise Exchange to Microsoft 365 without updating SPF. Old SPF has mx pointing at on-premise; new M365 server IPs not authorised. Fix: replace mx with include:spf.protection.outlook.com.
Mail sent to a university @alumni forwarder, forwarded to recipient's personal Gmail. Gmail sees forwarder's IP; SPF fails for original sender. Expected behaviour; DKIM survives, DMARC passes via DKIM alignment. No action needed unless DKIM also fails.
UK business bcc's all outbound to archive.firm.co.uk which relays through a different IP. If archive's IP not in SPF, SPF fails for mail seen by archive. Fix: add archive relay IP.
Zoom sends recording notifications appearing to come from your users. Their IPs are not in your SPF. Under DMARC p=reject, these are rejected. Fix: either add Zoom's SPF include, accept the behaviour (notifications go to spam), or configure Zoom with custom sending domain.
User sets up Google to "send as" from another address; mail sent via Google's SMTP but envelope sender is external. SPF for that external domain fails because Google's IP is not in it. Fix: include Google in the external domain's SPF.
Q: How do I tell if a sender should be in my SPF or should use DKIM delegation instead?
A: If the sender accepts CNAME-delegated DKIM for your domain, use DKIM delegation — it provides alignment via DKIM without SPF include growth. For services without custom-domain authentication, add to SPF.
Q: Why does my SPF pass when testing but fail in production?
A: Different receivers may evaluate from different DNS views. Check with multiple resolvers (1.1.1.1, 8.8.8.8, 9.9.9.9). If only some fail, investigate DNS caching or regional resolution issues.
Q: My mail server uses IPv6 but SPF only has IPv4 ranges. Problem?
A: Yes if IPv6 mail is being sent. Add ip6: ranges for the IPv6 infrastructure. Gmail in particular favours IPv6; missing v6 causes modern deliverability issues.
Q: SPF passes for most recipients but fails at Yahoo. What's different?
A: Yahoo's DNS resolution is strict. Check via Yahoo-specific resolvers if possible. Alternatively, ensure your SPF is under 8 lookups with no edge-case macros.
Q: Can I make SPF evaluation faster to avoid timing-related temperrors?
A: Reducing lookups helps. Fewer nested includes means faster resolution. Also consider DNS provider quality — premium DNS hosts have better latency characteristics.
Q: How quickly should I respond to SPF permerror alerts?
A: Immediately. Permerror = no SPF authentication for your domain across all receivers. Likely affecting all outbound. Same-day fix priority.