Mechanism Syntax |
|
Mechanisms can be prefixed with one of four characters:
- fail
~ softfail
+ pass
? neutral
If a mechanism results in a hit, its prefix value is used.
The default prefix value is 'pass".
Mechanisms are evaluated in order.
If a domain has no SPF record at all, its value is
"none". If a domain has a temporary error during DNS
processing, you get the value "error". If some kind of
syntax or evaluation error occurs (eg. the domain specifies
an unrecognized mechanism) the value is "unknown".
|
"v=spf1 -all"
"v=spf1 a -all"
"v=spf1 a mx -all"
"v=spf1 +a +mx -all"
|
| all |
|
This mechanism always matches. It goes at the end of your record.
|
| a a:domain a:domain/cidr-length a/cidr-length |
|
All the A records for domain are tested. If the
client IP is found among them, this mechanism matches.
If domain is not specified, the current-domain is used.
The A records have to match the client IP exactly, unless a
cidr-length is provided, in which case each IP address returned by
the A lookup will be expanded to its corresponding CIDR subnet, and the
client IP will be sought within that subnet.
|
"v=spf1 a -all"
The current-domain is used.
"v=spf1 a:example.com -all"
Equivalent if the current-domain is example.com.
"v=spf1 a:mailers.example.com -all"
Perhaps example.com has chosen to explicitly list all the
outbound mailers in a special A record under
mailers.example.com.
"v=spf1 a/24 a:offsite.example.com/24 -all"
If example.com resolves to 192.0.2.1, the entire class C of 192.0.2.0/24
would be searched for the client IP. Similarly for offsite.example.com.
If more than one A record were returned, each one would be expanded to a
CIDR subnet.
|
| mx mx:domain mx:domain/cidr-length mx/cidr-length |
|
All the A records for all the MX records for
domain are tested in order of MX priority. If the
client IP is found among them, this mechanism matches.
If domain is not specified, the current-domain is used.
The A records have to match the client IP exactly, unless a
cidr-length is provided, in which case each IP address returned by
the A lookup will be expanded to its corresponding CIDR subnet, and the
client IP will be sought within that subnet.
|
"v=spf1 mx mx:deferrals.domain.com -all"
Perhaps a domain sends mail through its MX servers plus
another set of servers whose job is to retry mail for
deferring domains.
"v=spf1 mx/24 mx:offsite.domain.com/24 -all"
Perhaps a domain's MX servers receive mail on one IP address, but send
mail on a different but nearby IP address.
|
| ptr ptr:domain |
|
The hostname or hostnames for the client IP are looked up
using PTR queries. The hostnames are then validated: at
least one of the A records for a PTR hostname must match the
original client IP. Invalid hostnames are discarded. If a
valid hostname ends in domain, this mechanism
matches.
If domain is not specified, the current-domain is used.
|
"v=spf1 ptr -all"
A domain which directly controls all its machines (unlike a
dialup or broadband ISP) allows all its servers to send
mail. For example, hotmail.com or paypal.com
might do this.
"v=spf1 ptr:otherdomain.com -all"
Any server whose hostname ends in otherdomain.com is designated.
|
| ip4:cidr-spec |
|
A CIDR-spec is an IP network range. If no prefix-length is given, /32 is assumed.
|
"v=spf1 ip4:192.168.0.1/16 -all"
Allow any IP address between 192.168.0.1 and 192.168.255.255.
|
| ip6:......... |
|
Could someone with IPv6 experience please provide some input?
|
| The Exists Mechanism |
|
Perform an A query on the provided domain. If a result
is found, this constitutes a match. It doesn't matter what
the lookup result is: it could be 127.0.0.2.
When you use macros with this
mechanism, you can perform RBL-style reversed-IP lookups, or
set up per-user exceptions.
|
In the following example, the client IP is 1.2.3.4 and the current-domain is example.com.
"v=spf1 exists:example.net -all"
If example.net does not resolve, the result is fail.
If it does resolve, this mechanism results in a match.
|
| Include:otherdomain |
|
The specified otherdomain is searched for a match.
If the lookup does not return a match or an error, processing
proceeds to the next directive.
Warning: If otherdomain does not have a valid SPF record, the
result is a Permanent Error. Some mail receivers will reject based on
a Permanent Error.
|
In the following example, the client IP is 1.2.3.4 and the current-domain is example.com.
"v=spf1 include:example.net -all"
If example.net has no SPF record, the result is PermError.
Suppose example.net's SPF record were "v=spf1 a -all".
Look up the A record for example.net. If it matches
1.2.3.4, return Pass.
If there is no match, the include as a whole fails to
match, but the -all value is not used;
the eventual result is still fail from the outer
directive set in this example.
|
|
Trust relationships - The include: mechanism is meant to cross
administrative boundaries. Great care is needed to ensure that include:
mechanisms do not place domains at risk for giving SPF Pass results to
messages that result from cross user forgery.
Unless technical mechanisms are in place at the specified otherdomain
to prevent cross user forgery, include: mechanisms should give a Neutral
rather than Pass result. This is done by adding "?" in front of include:.
The example above would be:
"v=spf1 ?include:example.net -all"
In hindsight, the name "include" was poorly chosen. Only the evaluated
result of the referenced SPF record is used, rather than acting as if the
referenced SPF record was literally included in the first. For example,
evaluating a "-all" directive in the referenced record does not terminate
the overall processing and does not necessarily result in an overall
"Fail". (Better names for this mechanism would have been "if-pass",
"on-pass", etc.)
|
Extension Mechanisms |
|
If the above directive syntax is not sufficiently
expressive to describe the email policy for your domain, you
are welcome to come up with your own mechanisms. Note,
however, that SPF clients will abort with an "unknown" if
they encounter a mechanism they do not recognize.
|
"v=spf1 habeas -all"
This might indicate that mail from a domain is sent with Habeas headers.
|
Modifiers |
|
Modifiers are optional. A modifier may appear only once per directive-set. Unknown modifiers are ignored.
|
| redirect=domain-macro |
|
The SPF directives for domain-macro replace the
current set of directives. The expanded
domain-macro is also substituted for the
current-domain in those lookups.
|
In the following example, the client IP is 1.2.3.4 and the current-domain is example.com.
"v=spf1 redirect=example.net"
If example.net has no SPF record, that is an error; the result is unknown.
Suppose example.net's SPF record were "v=spf1 a -all".
Look up the A record for example.net. If it matches
1.2.3.4, return allow.
If there is no match, the exec fails to match, and the
-all value is used.
|
| exp=domain-macro |
|
If an SMTP receiver rejects a message, it can include an
explanation. An SPF publisher can specify the explanation
string that senders see. This way, an ISP can direct
nonconforming users to a web page that provides further
instructions about how to configure SASL.
The domain-macro is expanded; a TXT lookup is
performed. The result of the TXT query is then
macro-expanded and shown to the sender.
|