Debug SPF failures by checking your record exists (dig TXT domain.com), verifying syntax and lookup count (MXToolbox), confirming the sending IP is covered by your mechanisms, and checking email headers for the specific failure reason. Common failures: permerror (too many lookups or syntax error), softfail (~all and IP not listed), fail (-all and IP not listed).
Debugging SPF Failures with dig, nslookup, and Online Tools
Step 1: Verify Your SPF Record Exists
Using dig (Linux/Mac)
dig TXT yourdomain.com +short
Expected output:
"v=spf1 include:_spf.google.com include:sendgrid.net ~all"
If no output contains v=spf1, you don't have an SPF record.
Using nslookup (Windows)
nslookup -type=TXT yourdomain.com
Checking Specific DNS Servers
During propagation, check authoritative servers:
# Google DNS
dig TXT yourdomain.com @8.8.8.8 +short
# Cloudflare DNS
dig TXT yourdomain.com @1.1.1.1 +short
# Your domain's authoritative server
dig NS yourdomain.com +short
dig TXT yourdomain.com @ns1.yourdns.com +short
Step 2: Validate Syntax and Lookup Count
Using MXToolbox
- Go to MXToolbox SPF Record Lookup
- Enter your domain
- Check for:
- Syntax errors (highlighted in red)
- DNS lookup count (must be ≤10)
- Void lookups (must be ≤2)
- Multiple SPF records (must have exactly 1)
Using dmarcian SPF Surveyor
- Go to dmarcian.com/spf-survey
- Enter your domain
- View the visual tree of all includes
- See total lookup count at each level
Practitioner note: MXToolbox is my first stop for SPF debugging. It catches 90% of issues in 10 seconds—multiple records, lookup limits, syntax problems—all flagged clearly.
Step 3: Find the Failing IP
The sending IP is what SPF checks. To debug, you need to know which IP tried to send.
From Email Headers
Open the failed email and find headers. Look for:
Authentication-Results: mx.google.com;
spf=softfail (google.com: domain of [email protected] does not designate 192.0.2.50 as permitted sender) [email protected]
The IP address in the SPF result (192.0.2.50) is what failed.
From Received Headers
Received: from mail.example.com (192.0.2.50) by mx.google.com ...
The IP in parentheses is the connecting server.
Step 4: Check If IP Is Covered
Now verify if your SPF record authorizes that IP.
For include Mechanisms
Trace the include chain:
# Your record
dig TXT yourdomain.com +short
# "v=spf1 include:sendgrid.net ~all"
# SendGrid's record
dig TXT sendgrid.net +short
# "v=spf1 ip4:167.89.0.0/17 ip4:208.117.48.0/20 ..."
Is 192.0.2.50 within those IP ranges? If not, SPF correctly fails.
For ip4 Mechanisms
Check if the IP falls within your listed ranges:
ip4:192.0.2.0/24
This covers 192.0.2.0 through 192.0.2.255. Check with an IP calculator if needed.
Step 5: Common Failure Patterns
Pattern 1: permerror
Header shows:
spf=permerror
Causes:
- Too many DNS lookups (>10) — see the 10 DNS lookup limit guide
- Syntax error in record
- Multiple SPF records
- Void lookup limit exceeded (>2)
Debug:
# Check for multiple records
dig TXT yourdomain.com +short | grep -c spf
# Should return 1
# Check lookup count with MXToolbox
Pattern 2: softfail
Header shows:
spf=softfail (domain does not designate IP as permitted sender)
Causes:
- Record ends with
~all - Sending IP not covered by any mechanism
- Forwarded email (forwarder IP not authorized)
Debug:
- Identify the IP from headers
- Trace include chain to see if IP should be covered
- If legitimate sender, add their include or IP
Pattern 3: fail
Header shows:
spf=fail
Causes:
- Record ends with
-all - Sending IP definitely not authorized
- Spoofing attempt (expected behavior)
Debug: Same as softfail—verify if the IP should be authorized.
Pattern 4: neutral
Header shows:
spf=neutral
Causes:
- Record ends with
?all - IP matched a mechanism with
?qualifier
Debug:
Check your record—you probably have ?all instead of ~all or -all.
Pattern 5: temperror
Header shows:
spf=temperror
Causes:
- DNS timeout during SPF lookup
- Temporary DNS server issue
- Network problem
Debug: Usually resolves on retry. If persistent, check DNS server health.
Step 6: Test Specific Scenarios
Test from Your ESP
Most ESPs provide test tools:
- SendGrid: Settings → Sender Authentication → Verify
- Mailgun: Sending → Domains → Check DNS Records
- Google Workspace: Admin → Apps → Google Workspace → Gmail → Authenticate Email
Send Test Email
- Send from the suspected service/IP
- Send to a Gmail account
- Open email → Three dots → Show original
- Check Authentication-Results for SPF
spf=pass (google.com: domain of [email protected] designates 167.89.123.45 as permitted sender)
Practitioner note: When clients report "SPF is failing," I always ask for the actual email headers first. Half the time, the issue isn't SPF at all—it's DKIM or DMARC, and they've misread the authentication results.
Quick Reference Commands
# Check SPF record
dig TXT yourdomain.com +short | grep spf
# Check specific include
dig TXT _spf.google.com +short
# Check with specific DNS server
dig TXT yourdomain.com @8.8.8.8 +short
# Count SPF records (should be 1)
dig TXT yourdomain.com +short | grep -c "v=spf1"
# Trace full include chain
dig TXT yourdomain.com +short
dig TXT _spf.google.com +short
dig TXT _netblocks.google.com +short
When to Get Help
If you've traced the include chain, verified the IP, checked lookup counts, and still can't identify the issue, schedule a consultation. Some SPF problems require deep DNS analysis or involve complex multi-sender configurations.
Sources
- RFC 7208: Sender Policy Framework (SPF)
- MXToolbox: SPF Record Check
- dmarcian: SPF Surveyor
- Google Admin Toolbox: Check MX
v1.0 · March 2026
Frequently Asked Questions
How do I check my SPF record with dig?
Run: dig TXT yourdomain.com +short | grep spf. This returns your SPF record. If nothing returns, you don't have an SPF record published.
How do I find the sending IP that failed SPF?
Check the email headers. Look for 'Received: from' lines or the 'Authentication-Results' header. The IP that connected to the receiving server is what SPF checks.
What does 'SPF permerror' mean in headers?
Permerror means your SPF record has a permanent error—usually too many DNS lookups (over 10), syntax errors, or multiple SPF records. The receiving server couldn't evaluate your record.
Why is SPF failing when my record looks correct?
Common causes: sending IP isn't covered by your includes, nested includes exceed lookup limit, you have multiple SPF records, or there's a propagation delay after recent DNS changes.
How long does DNS propagation take for SPF changes?
Typically 15-30 minutes, but can take up to 48 hours depending on TTL settings. Use dig with @8.8.8.8 to check Google's DNS or @1.1.1.1 for Cloudflare during propagation.
Want this handled for you?
Free 30-minute strategy call. Walk away with a plan either way.