SPF mechanisms: ip4, ip6, a, mx, include, exists, ptr, all
The eight SPF mechanisms decide which servers match a record. What each one tests, what it costs in DNS lookups, and when to use or avoid it.
Mechanisms are the matching directives of an SPF record: each one tests the connecting server's IP address in a specific way, and the first mechanism that matches ends the evaluation with its qualifier's result. RFC 7208 defines eight. Two of them cost nothing to evaluate, five consume the 10-lookup DNS budget, and one is deprecated. Choosing the right ones is most of SPF record design.
The zero-cost mechanisms: ip4 and ip6
ip4 and ip6 match the connecting IP against a literal address or CIDR range: ip4:198.51.100.7 for a single host, ip4:198.51.100.0/24 for a block, ip6:2001:db8::/32 for IPv6 space. They trigger no DNS lookups, evaluate instantly, and cannot break when someone else's infrastructure changes. For servers you operate and whose addresses you control, literal IP mechanisms are the most robust choice available.
Their weakness is the flip side: the record is only as current as your last edit. Renumbering the MTA fleet without updating the record silently deauthorizes your own mail. IP mechanisms suit stable, self-operated infrastructure, and suit rented, vendor-managed address space poorly.
The delegation mechanism: include
include:otherdomain.com evaluates the other domain's SPF record and matches if that evaluation returns pass. It is how vendors publish their sending infrastructure once and let every customer reference it: include:_spf.google.com, include:sendgrid.net. The vendor updates their record when their fleet changes, and your record follows automatically.
The convenience mechanisms: a and mx
a matches if the connecting IP appears in the A or AAAA records of the domain (or a named argument: a:mail.example.com). mx matches if the IP belongs to any of the domain's MX hosts. Both cost DNS lookups: one for a, and for mx one lookup for the MX set plus one per MX hostname resolved, which makes mx surprisingly expensive.
Both mechanisms encode an assumption that is frequently false: that the machines serving your website or receiving your mail are also the machines sending it. In modern setups with separate outbound infrastructure, a and mx authorize hosts that never send and miss the ones that do. Prefer explicit ip4 ranges or vendor includes, and use a and mx only where the assumption genuinely holds.
The specialist: exists
exists:domain matches if the named domain resolves to any A record, and its power comes from macro expansion: exists:%{i}.allow.example.com constructs a per-IP hostname and effectively turns DNS itself into an authorization database. Large infrastructure operators use it for fine-grained, dynamically managed authorization. For typical senders it is rarely needed, and records containing macros deserve careful review because few humans read them correctly at a glance.
The deprecated one: ptr
ptr matches by reverse-resolving the connecting IP and checking the resulting hostname, a design that is slow, unreliable, and abusable. RFC 7208 explicitly discourages it, some receivers skip it entirely, and its lookups count doubly painfully against the budget. Any record still containing ptr should be edited today; whatever it authorizes can be expressed with ip4 or include.
The mandatory terminator: all
all matches every IP unconditionally, which is why it stands last and defines what happens to mail from servers nothing else matched. Its meaning comes entirely from its qualifier: -all fails unauthorized senders, ~all softfails them, ?all shrugs. A record without an all (or a redirect) leaves unmatched senders at an implicit neutral, which defeats the point of publishing a record. Every production SPF record should end in an explicit all.
Mechanism reference
| Feature | Matches when | DNS lookup cost |
|---|---|---|
| ip4 / ip6 | IP is in the literal range | 0 |
| include | Included record returns pass | 1 + nested lookups |
| a | IP is in the domain's A/AAAA records | 1 |
| mx | IP belongs to a domain MX host | 1 + 1 per MX host |
| exists | Constructed name resolves | 1 |
| ptr (deprecated) | Reverse DNS name validates | expensive, avoid |
| all | Always | 0 |
The lookup costs in the table are the currency of the 10 DNS lookup limit, and mechanism choice is the main way records stay inside it. For how mechanisms combine into a full record, see the record syntax entry.
Frequently asked questions
Which mechanisms should a typical sender use?
Can I nest includes inside includes?
Does include:domain also authorize mail claiming to be from that domain?
What does a mechanism argument like ip4:198.51.100.0/24 mean exactly?
Key takeaways
- ip4 and ip6 are free to evaluate and ideal for infrastructure you control; include delegates to vendors at a lookup cost
- a and mx assume web or inbound hosts also send mail, an assumption that is usually false in modern setups
- exists with macros is powerful for large operators and overkill for typical senders
- ptr is deprecated: remove it from any record that still carries it
- Every record ends with an explicit all whose qualifier defines the fate of unauthorized mail