SPF Record: Check and Set It Up Correctly
SPF record check and setup: the three mistakes that break it — two records, +all, the 10-lookup limit — and how to fix each. Free instant check, no sign-up.
Check your domain for this issue now
Free, no sign-up. Runs the exact check this guide describes and shows what to fix.
Problem
You added a new mail service — Microsoft 365, a newsletter tool, your helpdesk — and it told you to “add this SPF record to your DNS.” So you added it, right next to the one that was already there. And now, quietly, everything is failing. Your legitimate mail lands in spam or bounces with a PermError, and the diagnostic you get back says something unhelpful about SPF.
Here’s the thing nobody tells you when they hand you that TXT record to paste: SPF is not a list of records you keep adding to. It’s a single record with strict rules, and the two or three ways people break it are always the same. Once you can see them, SPF stops being magic and becomes a five-minute check.
What an SPF record actually is
SPF — Sender Policy Framework, defined in RFC 7208 — is one DNS TXT record on your domain that answers a single question for the receiving mail server: is the machine trying to send this message allowed to send for this domain? It’s a published allowlist of your sending sources.
A minimal record looks like this:
v=spf1 include:_spf.google.com ~all
v=spf1 marks it as SPF. The middle is a list of mechanisms — include:, a, mx, ip4:, ip6: — each naming a source that’s allowed to send. The trailing all is the catch-all: what to do with everything you didn’t list. The receiver reads this record, checks the connecting server against it, and returns a result: pass, fail, softfail, or the two that mean you’ve made a mistake — permerror and temperror.
The three mistakes that break SPF
Nearly every broken SPF record fails for one of three reasons. None of them show up as a syntax error you’d notice by eye.
1. Two records instead of one. RFC 7208 §3.2 is blunt: a domain publishes exactly one record starting with v=spf1. Two records is not “extra coverage” — it’s an immediate PermError, and PermError fails authentication for everything, even mail from servers both records would have allowed. This is what happens when you add a provider by pasting a second record next to the first. The rule you have to internalize: you merge, you never append. Adding Microsoft on top of Google means taking the includes from both and putting them in one line:
v=spf1 include:_spf.google.com include:spf.protection.outlook.com ~all
2. The 10-lookup limit. SPF evaluation may trigger at most 10 DNS lookups (§4.6.4), a cap that exists so a hostile record can’t turn every inbound message into a DNS flood. Each include, a, mx, ptr, exists, and redirect costs a lookup — and includes nest, so one include: that references three more spends four. A single big provider’s include can burn 3–5 lookups on its own, so three or four stacked providers is all it takes to cross the line and earn a PermError. The trap is that this record looks fine; it’s short, it’s valid, and it fails only because of what its includes pull in. There’s a second, quieter cap too: no more than 2 void lookups (mechanisms that resolve to nothing), which is how a dead include: pointing at a service you dropped years ago silently poisons the whole record.
3. Ending in +all. The all mechanism takes a qualifier: -all (fail), ~all (softfail), ?all (neutral), or +all (pass). +all says every server on the internet is authorized to send as me. People paste it to “make the errors go away,” and it does — by making SPF pass unconditionally, which is worse than publishing no SPF at all, because now anyone can forge your domain and clear the check. If you see +all anywhere in your record, that’s the bug.
How to read and check your record
The checking order is always the same, and it’s fast:
- Confirm there’s exactly one. Look up your domain’s TXT records and count how many start with
v=spf1. If it’s more than one, that’s your problem before you look at anything else. - Count the lookups, not the length. Walk each
include,a,mx, andredirect, following includes into their own records, and add them up. Over 10 is a PermError waiting to happen; over 8 is a warning to start flattening. - Check for dead ends. An
include:orredirectthat resolves to nothing burns your void-lookup budget. Drop mechanisms for services you no longer use. - Read the
allqualifier.~allwhile you’re building the list,-allonce it’s complete, and never+all.
When you add a new sender, the discipline is: find your existing record, add the new provider’s include, and republish the one record. Never leave two.
Check it with DechoNet
- Email / SPF Check evaluates your domain’s SPF the way a receiving server does: it flags multiple records, counts the DNS lookups against the limit, resolves each
includeso you can see which one is bloated, and reads the finalallqualifier. This is the fastest way to catch the PermError causes that don’t look like errors. - DNS Lookup shows the raw
TXTrecords on the domain, so you can confirm with your own eyes that there’s exactly onev=spf1line and nothing stale hiding beside it.
Resolution Checklist
- Confirm the domain has exactly one
v=spf1TXT record. If there are two, merge them into one line — includes from both, published once. - Count the DNS-querying mechanisms (
include,a,mx,ptr,exists,redirect), following nested includes. Keep the total under 10. - Remove
include:orredirectentries for services you no longer send from — they waste lookups and can trip the void-lookup cap. - Make sure the record ends in
~allor-all, never+all. - After any change, re-check with Email Check and send a test message to confirm the result is
pass, notpermerror.
When to Escalate
- If you legitimately send from more providers than 10 lookups can cover, you need SPF flattening — replacing
include:chains with the resolvedip4:/ip6:ranges — but only with a tool or service that keeps those ranges up to date, because a provider changing its IPs will silently break a hand-flattened record. - If SPF passes but mail still fails DMARC, the problem is alignment, not SPF itself: the domain in your
From:header has to line up with the SPF-authenticated domain. That’s a separate check. - If the record is correct and receivers still return
temperror, that’s a transient DNS resolution failure on their side, not a record you can fix — retry before changing anything.
Related Tools
Related Guides
Share this guide