Reference
SPF mechanisms, modifiers and qualifiers
An SPF record is `v=spf1` followed by terms evaluated left to right. RFC 7208 defines eight mechanisms — all, include, a, mx, ptr, ip4, ip6 and exists — that match the sending address, two modifiers — redirect and exp — that change what happens around the match, and four qualifiers that set the result of a match: + pass, - fail, ~ softfail and ? neutral. Five mechanisms and the redirect modifier cost a DNS lookup, and a record may not need more than ten of them.
| Term | Kind | What it does | DNS lookup | What the scan checks |
|---|---|---|---|---|
| all | Mechanism | Always matches. Placed last, its qualifier decides the result for every sender not matched before it. | No | Its qualifier is graded; terms written after it are flagged because they are never evaluated. |
| include | Mechanism | Evaluates another domain's SPF record and matches if that evaluation passes. | Yes, plus every lookup of the included record | Requires a valid domain; its tree is walked to count lookups. |
| a | Mechanism | Matches if the sender's address is one of the A or AAAA addresses of the domain, optionally widened by a CIDR length. | Yes | Validates the domain if one is given; counted as a lookup. |
| mx | Mechanism | Matches if the sender's address is one of the addresses of the domain's mail exchangers. | Yes, plus a lookup per exchanger | Validates the domain if one is given; counted as a lookup. |
| ptr | Mechanism | Matches through a reverse lookup of the sender's address. RFC 7208 says it should not be published. | Yes | Flagged as deprecated. |
| ip4 | Mechanism | Matches if the sender's address is in the given IPv4 address or range. | No | Validates the address and prefix length. |
| ip6 | Mechanism | Matches if the sender's address is in the given IPv6 address or range. | No | Validates the address and prefix length. |
| exists | Mechanism | Matches if an A lookup of the given domain, usually built with macros, returns any address. | Yes | Requires a domain; macros are accepted without being expanded. |
| redirect= | Modifier | When nothing in the record matched, replaces the evaluation with another domain's record. Ignored if the record contains all. | Yes | Must name a valid domain and appear once; flagged when all makes it useless. |
| exp= | Modifier | Names a domain whose TXT record holds an explanation returned with a fail result. | Only when a fail result is explained | Recorded; its content is not fetched. |
| + | Qualifier | Pass: the sender is authorised. The default when no qualifier is written. | No | +all is reported as a failure: it authorises every server on the Internet. |
| - | Qualifier | Fail: the sender is explicitly not authorised. | No | -all is the result reported as correct. |
| ~ | Qualifier | Softfail: the sender is probably not authorised; receivers usually accept and mark the message. | No | ~all is reported for information, as a partial restriction. |
| ? | Qualifier | Neutral: the record makes no statement about the sender. | No | ?all is reported as a warning. |
How a receiver evaluates the terms
The receiver fetches the TXT record that starts with `v=spf1` and walks the mechanisms from left to right. The first one that matches the sending address decides the result, through its qualifier; nothing after it is read.
When no mechanism matches, a `redirect=` modifier hands the whole evaluation to another domain's record. Without one, the result is neutral — which is why a record should end with an explicit `all`.
Modifiers are not positional: `redirect=` and `exp=` apply to the record as a whole wherever they are written. Unknown modifiers are ignored by receivers, so a misspelled one fails silently.
A domain must publish one SPF record. Two records starting with `v=spf1` make the evaluation return a permanent error, which receivers treat as having no usable policy.
The ten-lookup budget
RFC 7208 caps the terms that trigger DNS queries — `include`, `a`, `mx`, `ptr`, `exists` and `redirect=` — at ten per evaluation, counting the ones inside included records. Past ten, the result is a permanent error.
`ip4`, `ip6` and `all` cost nothing, which is why replacing an `include` of a provider by the provider's published address ranges is a common way to get back under the limit — at the price of maintaining the ranges by hand.
The specification also limits "void" lookups, the ones that return no answer, to two, so an `include` of a domain that no longer publishes SPF costs more than it appears to.
What a scan validates, and what it does not
The SPF parser recognises the eight mechanisms and two modifiers above; any other mechanism name is an error, and any other modifier a warning. It validates the domain of `include`, `exists`, `redirect=` and of `a` or `mx` when one is given, and the address and prefix length of `ip4` and `ip6`.
`email.spf.lookups` walks the include and redirect tree over real DNS to count lookups, with bounds on depth and queries; when a bound is hit the count is reported as incomplete rather than guessed. `email.spf.all` grades the final qualifier, `email.spf.ptr` flags `ptr`, `email.spf.single` flags a second record and `email.spf.syntax` reports parse errors.
Macros such as `%{i}` are legal and are accepted as written; the scan does not expand them, so a record built mostly from macros is checked for structure, not for what it resolves to.
Frequently asked questions
- Should an SPF record end with -all or ~all?
- -all states that unlisted servers are not authorised, which is the precise statement once every legitimate sender is listed. ~all is a softer signal often used during a rollout. With an enforcing DMARC policy in place, receivers act on DMARC, and the difference matters less.
- Does ip4 count toward the ten-lookup limit?
- No. ip4, ip6 and all require no DNS query. Only include, a, mx, ptr, exists and the redirect modifier count, including those reached inside included records.
- Can a domain publish two SPF records?
- No. With two TXT records starting with v=spf1, evaluation ends in a permanent error. Senders must be merged into a single record.
Sources
Related
VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.
Scan a website