SPF Check
Find the SPF record, check its syntax, count DNS lookups against the limit of 10.
The Sender Policy Framework (SPF) is a TXT record in DNS that states which servers are allowed to send mail on behalf of a domain. A receiving mail server reads the record, compares the connecting server's IP address against the networks listed there and decides whether the message is authorised. SPF is, together with DKIM, one of the two foundations that DMARC builds on: without a passing SPF or DKIM result the DMARC policy takes over.
What this tool checks
It fetches the domain's v=spf1 TXT record, resolves every
include and redirect reference recursively and shows the full
tree. It counts the mechanisms that cost a DNS lookup (include,
a, mx, ptr, exists,
redirect), checks the syntax of each term against RFC 7208, detects loops and
empty references (void lookups) and sums up the networks that are actually authorised. If a
sending IP address is supplied as well, the tool runs the full RFC 7208 section 4
check_host() evaluation and names the mechanism that matched.
Reading the result
Green means: exactly one record, valid syntax, at most 10 lookup-costing terms, a
trailing -all or ~all. A warning appears for ?all or
+all, for more than two void lookups or when the lookup count sits close to
the limit. An error stands for a duplicate v=spf1 record, for more than 10
lookups (PermError) or for invalid syntax. With an IP set, the result also
shows pass, fail, softfail, neutral,
permerror or temperror, the way a real receiver would decide,
including a resolved exp= explanation string on fail.
Background
The reference is RFC 7208. The limit of 10 lookup-costing terms and the limit of at most
two void lookups are in section 4.6.4, the evaluation order is in section 4.6.2, the
optional exp= text is in section 6.2, the macro language is in section 8. The
older RFC 4408 is obsoleted by RFC 7208. Since RFC 7208 there is no dedicated SPF DNS
record type; SPF lives in the TXT record only.
Common problems and how to fix them
- No SPF record. Without a
v=spf1entry no receiver can check the origin and DMARC fails on the SPF side. Create a record that covers every legitimate sending path (your own mail server, newsletter service, CRM, ticketing system) and end it with-allor~all. - PermError from too many DNS lookups. Each
includeof a large provider often brings three to five further lookups. Remove includes you no longer use, have the provider merge several small services into one include (SPF flattening), or enter staticip4/ip6ranges directly instead of resolving them througha/mx. - Fixing a softfail. If legitimate mail ends up in the spam folder
despite
~all, a sending path is usually missing from the record. Read the actual sending IPs from the DMARC aggregate reports, add them to the record, then move from~allto-all. - Two SPF records. A second
v=spf1TXT entry, often left behind by an old service, produces an immediatePermError. Merge all permitted senders into a single record and delete the second one. ptrin the record. Theptrmechanism is slow and unreliable, RFC 7208 explicitly advises against it. Replace it withip4/ip6or anincludeof the provider.- Overly broad authorisation.
+allor a whole/8block lets practically any server send. Narrow it down to the addresses actually in use.
More background in the blog article Sender Policy Framework (SPF): how it works and when not to use it on frankysweb.de (in German).
Common questions
- What is the 10 lookup limit in SPF?
- RFC 7208 section 4.6.4 allows at most 10 DNS queries per evaluation through mechanisms such as include, a, mx, ptr, exists and the redirect modifier. ip4, ip6 and all do not count. If the limit is exceeded, SPF returns a PermError and the check is treated as failed.
- SPF reports 'too many DNS lookups', what now?
- Walk the resolved tree and count how many lookups each include costs. Drop unused services, replace a and mx mechanisms with fixed ip4/ip6 ranges, and ask the provider for a leaner or flattened include. Aim for clearly fewer than 10 terms so future changes do not immediately hit the limit again.
- Difference between ~all and -all?
- ~all (SoftFail) marks senders that are not listed as suspicious but usually lets them through. -all (HardFail) asks for rejection. Both are valid end states; which one fits depends on whether DMARC is in use. A trailing ?all (Neutral) or +all (anyone may send) is by contrast practically ineffective or a mistake.
- Should I use ~all or -all with DMARC?
- Without DMARC, -all is the actual enforcement signal and the stricter choice. With an enforced DMARC policy (p=quarantine or p=reject), DMARC makes the decision based on the alignment of SPF or DKIM, and many recommendations then favour ~all: -all makes forwarded mail and mailing lists fail already at the SPF stage, whereas with ~all a carried DKIM signature still rescues the message through DMARC. Forged mail without a valid, aligned signature is still caught by the DMARC policy. -all remains defensible, but ~all is often the more robust default with DMARC.
- Can a domain have more than one SPF record?
- No. With more than one v=spf1 TXT record the check returns a PermError. All permitted senders belong in a single record. Multiple entries often appear when a new service adds its own SPF record instead of extending the existing one.
- Is SPF alone enough against spoofing?
- No. SPF only checks the envelope sender domain (MAIL FROM), not the From address shown in the mail client, and it does not survive forwarding. Effective protection only comes with DKIM and an enforced DMARC policy (p=quarantine or p=reject) on top.
- What does the extra 'sending IP' field do?
- Only with an IP set does the tool additionally evaluate how a real receiver would decide: pass, fail, softfail, neutral, permerror or temperror, including the matching mechanism. Without an IP it stays a pure syntax and structure analysis of the record.
- What does a 'fail' result with an explanation mean?
- Some records publish an explanation string through exp= that a receiver would return on fail (RFC 7208 section 6.2). This tool resolves it, expands the macros it contains and shows it when present.