What SPF actually authorises
Sender Policy Framework (RFC 7208) is a list of the hosts allowed to send mail for a domain. The critical detail almost everyone gets wrong: SPF authorises the envelope sender, the address in the SMTP MAIL FROM command, not the From: header your recipient sees. A message can pass SPF perfectly while showing a completely forged From: address, which is exactly why DMARC exists — DMARC is the layer that ties the authenticated envelope domain back to the visible header domain.
When a receiving mail server accepts a connection it takes the envelope sender domain, queries that domain for TXT records, and finds the one beginning v=spf1. It then walks the mechanisms left to right, stopping at the first one that matches the connecting IP address. The qualifier on that mechanism becomes the result: + Pass, - Fail, ~ SoftFail, ? Neutral. If nothing matches before the terminating all, the qualifier on all decides. That left-to-right, first-match-wins evaluation is why the order of your mechanisms matters and why anything after all is dead code.
The 10-lookup limit and PermError
RFC 7208 §4.6.4 caps the number of DNS-querying terms an SPF evaluation may use at ten. The terms that spend from that budget are include, a, mx, ptr, exists, and the redirect modifier. The terms that cost nothing are ip4, ip6, all, and exp. The limit is not per record — it is per evaluation, counted across the whole tree. If your record contains three includes and each of those provider records contains three includes of its own, you have spent twelve lookups, not three.
Read the full explanation of spf checker results ↓Show less ↑
The failure mode is nasty because it is invisible from your side. You add one more SaaS tool — a helpdesk, an invoicing app, a newsletter platform — the vendor tells you to append one include:, and nothing appears to break. Your own test messages still arrive because they match an earlier mechanism. But receivers that evaluate the whole record hit the eleventh lookup, abort, and return PermError. Bounces start arriving from a subset of recipients days later, and the change that caused it is long forgotten.
A second, separate limit catches people out too: the mx and ptr mechanisms may each trigger at most ten address lookups internally, and a "void lookup" limit of two applies to queries that return NXDOMAIN or an empty answer. A stale include: pointing at a decommissioned vendor domain burns a void lookup and, once the target has no SPF record at all, is itself a PermError.
How to read the results above
| What you see | What it means | What to do |
|---|---|---|
Green counter, -all | Record is inside budget and hardfails unlisted senders. | Nothing. This is the target state. |
| Amber counter (8–10) | One more provider will break the record. | Replace include: entries for your own servers with ip4: before adding anything else. |
| Red counter (>10) | PermError. SPF is failing for every message right now. | Remove unused includes, consolidate providers, or flatten. Fix today. |
?all or no all | Neutral — receivers learn nothing they did not already know. | Change to ~all, then -all once the sender list is complete. |
+all | Every host on the internet passes SPF for your domain. | Remove it immediately. This is worse than having no SPF record. |
Two v=spf1 records | PermError before a single mechanism is evaluated. | Merge them into one TXT record and delete the other. |
The mechanism table shows each term with the result it produces on a match and whether it spends a lookup. Work down it and ask, for every lookup-consuming term, "does this still send mail for us?" Most over-budget records are 60% dead weight — a former ESP, a CRM that was trialled and dropped, a hosting provider from two migrations ago.
The five failures that actually happen
- Two SPF records. A migration adds a new record instead of editing the old one. RFC 7208 §4.5 requires exactly one; two means PermError for everything. Check with a full TXT lookup, not just an SPF tool.
- Over ten lookups. The single most common cause of "email suddenly stopped authenticating". See the PermError guide for the flattening options and their trade-offs.
- A record on the wrong name. SPF belongs on the bare domain (
@), not onspf.example.comor_spf.example.com. Those names are only ever include targets. - `-all` published before the sender list was complete. Invoicing systems, monitoring alerts, and the CRM nobody remembers all start hardfailing. Publish
~allfirst and read your DMARC aggregate reports for a month. - A record longer than 255 characters not split correctly. A single TXT string is capped at 255 bytes; longer records must be published as multiple quoted strings inside one TXT record, which concatenate with no separator. A panel that inserts a space between chunks corrupts the record.
If you need to cut lookups, the order of preference is: delete includes for services you no longer use; replace include: with the literal ip4: ranges when a provider publishes a small, stable set; drop a and mx if your mail server IPs are already covered by an ip4:; and only then consider automated flattening. Flattening — expanding every include into literal IPs — works, but it makes you responsible for tracking a provider's IP changes forever. When Google or Microsoft renumbers, your mail fails and no one tells you.
Check it from the command line
Every result on this page is reproducible with dig. Query the domain for TXT and pick the record that starts with v=spf1:
# The domain's own SPF record
dig +short TXT example.com | grep spf1
# Follow an include by hand to see what it costs
dig +short TXT _spf.google.com
# Query a specific resolver to rule out local caching
dig @8.8.8.8 +short TXT example.com
# Full answer with TTL, so you know how long a fix takes to propagate
dig TXT example.com +noall +answerTo count lookups by hand, run the first command, note every include:, a, mx, ptr, and exists term, then run dig +short TXT against each include target and repeat. The total across the whole tree is your lookup count. That manual walk is exactly what the checker above automates.
SPF is one third of the job
SPF breaks on forwarding: when a recipient auto-forwards your message, the forwarding server connects from its own IP with your envelope domain, and SPF fails. DKIM survives forwarding because it signs the message itself, which is why DMARC accepts either aligned SPF or aligned DKIM. A domain with a perfect SPF record and no DKIM is one mailing list away from failing DMARC. Verify all three, then confirm the policy with the DMARC checker.