present, then processing proceeds as follows:
redirect = "redirect" "=" domain-spec
The domain-spec portion of the redirect section is expanded as per
the macro rules in Section 8. Then check_host() is evaluated with
the resulting string as the <domain>. The <ip> and <sender>
arguments remain the same as current evaluation of check_host().
The result of this new evaluation of check_host() is then considered
the result of the current evaluation with the exception that if no
SPF record is found, or if the target-name is malformed, the result
is a "PermError" rather than "None".
Note that the newly-queried domain may itself specify redirect
processing.
This facility is intended for use by organizations that wish to apply
the same record to multiple domains. For example:
la.example.com. TXT "v=spf1 redirect=_spf.example.com"
ny.example.com. TXT "v=spf1 redirect=_spf.example.com"
sf.example.com. TXT "v=spf1 redirect=_spf.example.com"
_spf.example.com. TXT "v=spf1 mx:example.com -all"
In this example, mail from any of the three domains is described by
the same record. This can be an administrative advantage.
Note: In general, the domain "A" cannot reliably use a redirect to
another domain "B" not under the same administrative control. Since
the <sender> stays the same, there is no guarantee that the record at
domain "B" will correctly work for mailboxes in domain "A",
especially if domain "B" uses mechanisms involving localparts. An
"include" directive may be more appropriate.
For clarity, it is RECOMMENDED that any "redirect" modifier appear as
the very last term in a record.
6.2. exp: Explanation
explanation = "exp" "=" domain-spec
If check_host() results in a "Fail" due to a mechanism match (such as
"-all"), and the "exp" modifier is present, then the explanation
string returned is computed as described below. If no "exp" modifier
is present, then either a default explanation string or an empty
explanation string may be returned.
The <domain-spec> is macro expanded (see Section 8) and becomes the
<target-name>. The DNS TXT record for the <target-name> is fetched.
If <domain-spec> is empty, or there are any DNS processing errors
(any RCODE other than 0), or if no records are returned, or if more
than one record is returned, or if there are syntax errors in the
explanation string, then proceed as if no exp modifier was given.
The fetched TXT record’s strings are concatenated with no spaces, and
then treated as an <explain-string>, which is macro-expanded. This
final result is the explanation string. Implementations MAY limit
the length of the resulting explanation string to allow for other
protocol constraints and/or reasonable processing limits. Since the
explanation string is intended for an SMTP response and [RFC2821]
Section 2.4 says that responses are in [US-ASCII], the explanation
string is also limited to US-ASCII.
Software evaluating check_host() can use this string to communicate
information from the publishing domain in the form of a short message
or URL. Software SHOULD make it clear that the explanation string
comes from a third party. For example, it can prepend the macro
string "%{o} explains: " to the explanation, such as shown in Section
2.5.4.
Suppose example.com has this record:
v=spf1 mx -all exp=explain._spf.%{d}
Here are some examples of possible explanation TXT records at
explain._spf.example.com:
"Mail from example.com should only be sent by its own servers."
-- a simple, constant message
"%{i} is not one of %{d}’s designated mail servers."
-- a message with a little more information, including the IP
address that failed the check
"See http://%{d}/why.html?s=%{S}&i=%{I}"
-- a complicated example that constructs a URL with the
arguments to check_host() so that a web page can be
generated with detailed, custom instructions
Note: During recursion into an "include" mechanism, an exp= modifier
from the <target-name> MUST NOT be used. In contrast, when executing
a "redirect" modifier, an exp= modifier from the original domain MUST
NOT be used.
7. The Received-SPF Header Field
It is RECOMMENDED that SMTP receivers record the result of SPF
processing in the message header. If an SMTP receiver chooses to do
so, it SHOULD use the "Received-SPF" header field defined here for
each identity that was checked. This information is intended for the
recipient. (Information intended for the sender is described in
Section 6.2, Explanation.)
The Received-SPF header field is a trace field (see [RFC2822] Section
3.6.7) and SHOULD be prepended to the existing header, above the
Received: field that is generated by the SMTP receiver. It MUST
appear above all other Received-SPF fields in the message. The
header field has the following format:
header-field = "Received-SPF:" [CFWS] result FWS [comment FWS]
[ key-value-list ] CRLF
result = "Pass" / "Fail" / "SoftFail" / "Neutral" /
"None" / "TempError" / "PermError"
key-value-list = key-value-pair *( ";" [CFWS] key-value-pair )
[";"]
key-value-pair = key [CFWS] "=" ( dot-atom / quoted-string )
key = "client-ip" / "envelope-from" / "helo" /
"problem" / "receiver" / "identity" /
mechanism / "x-" name / name
identity = "mailfrom" ; for the "MAIL FROM" identity
/ "helo" ; for the "HELO" identity
/ name ; other identities
dot-atom = <unquoted word as per [RFC2822]>
quoted-string = <quoted string as per [RFC2822]>
comment = <comment string as per [RFC2822]>
CFWS = <comment or folding white space as per [RFC2822]>
FWS = <folding white space as per [RFC2822]>
CRLF = <standard end-of-line token as per [RFC2822]>
The header field SHOULD include a "(...)" style <comment> after the
result, conveying supporting information for the result, such as
<ip>, <sender>, and <domain>.
The following key-value pairs are designed for later machine parsing.
SPF clients SHOULD give enough information so that the SPF results
can be verified. That is, at least "client-ip", "helo", and, if the
"MAIL FROM" identity was checked, "envelope-from".
client-ip the IP address of the SMTP client
envelope-from the envelope sender mailbox
helo the host name given in the HELO or EHLO command
mechanism the mechanism that matched (if no mechanisms matched,
substitute the word "default")
problem if an error was returned, details about the error
receiver the host name of the SPF client
identity the identity that was checked; see the <identity> ABNF
rule
Other keys may be defined by SPF clients. Until a new key name
becomes widely accepted, new key names should start with "x-".
SPF clients MUST make sure that the Received-SPF header field does
not contain invalid characters, is not excessively long, and does not
contain malicious data that has been provided by the sender.
Examples of various header styles that could be generated are the
following:
Received-SPF: Pass (mybox.example.org: domain of
myname@example.com designates 192.0.2.1 as permitted sender)
receiver=mybox.example.org; client-ip=192.0.2.1;
envelope-from=<myname@example.com>; helo=foo.example.com;
Received-SPF: Fail (mybox.example.org: domain of
myname@example.com does not designate
192.0.2.1 as permitted sender)
identity=mailfrom; client-ip=192.0.2.1;
envelope-from=<myname@example.com>;
8. Macros
8.1. Macro Definitions
Many mechanisms and modifiers perform macro expansion on part of the
term.
domain-spec = macro-string domain-end
domain-end = ( "." toplabel [ "." ] ) / macro-expand
toplabel = ( *alphanum ALPHA *alphanum ) /
( 1*alphanum "-" *( alphanum / "-" ) alphanum )
; LDH rule plus additional TLD restrictions
; (see [RFC3696], Section 2)
alphanum = ALPHA / DIGIT
explain-string = *( macro-string / SP )
macro-string = *( macro-expand / macro-literal )
macro-expand = ( "%{" macro-letter transformers *delimiter "}" )
/ "%%" / "%_" / "%-"
macro-literal = %x21-24 / %x26-7E
; visible characters except "%"
macro-letter = "s" / "l" / "o" / "d" / "i" / "p" / "h" /
"c" / "r" / "t"
transformers = *DIGIT [ "r" ]
delimiter = "." / "-" / "+" / "," / "/" / "_" / "="
A literal "%" is expressed by "%%".
"%_" expands to a single " " space.
"%-" expands to a URL-encoded space, viz., "%20".
The following macro letters are expanded in term arguments:
s = <sender>
l = local-part of <sender>
o = domain of <sender>
d = <domain>
i = <ip>
p = the validated domain name of <ip>
v = the string "in-addr" if <ip> is ipv4, or "ip6" if <ip> is ipv6
h = HELO/EHLO domain
The following macro letters are allowed only in "exp" text:
c = SMTP client IP (easily readable format)
r = domain name of host performing the check
t = current timestamp
A ’%’ character not followed by a ’{’, ’%’, ’-’, or ’_’ character is
a syntax error. So
-exists:%(ir).sbl.spamhaus.example.org
is incorrect and will cause check_host() to return a "PermError".
Instead, say
-exists:%{ir}.sbl.spamhaus.example.org
Optional transformers are the following:
*DIGIT = zero or more digits
’r’ = reverse value, splitting on dots by default
If transformers or delimiters are provided, the replacement value for
a macro letter is split into parts. After performing any reversal
operation and/or removal of left-hand parts, the parts are rejoined
using "." and not the original splitting characters.
By default, strings are split on "." (dots). Note that no special
treatment is given to leading, trailing, or consecutive delimiters,
and so the list of parts may contain empty strings. Older
implementations of SPF prohibit trailing dots in domain names, so
trailing dots should not be published by domain owners, although they
must be accepted by implementations conforming to this document.
Macros may specify delimiter characters that are used instead of ".".
The ’r’ transformer indicates a reversal operation: if the client IP
address were 192.0.2.1, the macro %{i} would expand to "192.0.2.1"
and the macro %{ir} would expand to "1.2.0.192".
The DIGIT transformer indicates the number of right-hand parts to
use, after optional reversal. If a DIGIT is specified, the value
MUST be nonzero. If no DIGITs are specified, or if the value
specifies more parts than are available, all the available parts are
used. If the DIGIT was 5, and only 3 parts were available, the macro
interpreter would pretend the DIGIT was 3. Implementations MUST
support at least a value of 128, as that is the maximum number of
labels in a domain name.
The "s" macro expands to the <sender> argument. It is an E-Mail
address with a localpart, an "@" character, and a domain. The "l"
macro expands to just the localpart. The "o" macro expands to just
the domain part. Note that these values remain the same during
recursive and chained evaluations due to "include" and/or "redirect".
Note also that if the original <sender> had no localpart, the
localpart was set to "postmaster" in initial processing (see Section
4.3).
For IPv4 addresses, both the "i" and "c" macros expand to the
standard dotted-quad format.
For IPv6 addresses, the "i" macro expands to a dot-format address; it
is intended for use in %{ir}. The "c" macro may expand to any of the
hexadecimal colon-format addresses specified in [RFC3513], Section
2.2. It is intended for humans to read.
The "p" macro expands to the validated domain name of <ip>. The
procedure for finding the validated domain name is defined in Section
5.5. If the <domain> is present in the list of validated domains, it
SHOULD be used. Otherwise, if a subdomain of the <domain> is
present, it SHOULD be used. Otherwise, any name from the list may be
used. If there are no validated domain names or if a DNS error
occurs, the string "unknown" is used.
The "r" macro expands to the name of the receiving MTA. This SHOULD
be a fully qualified domain name, but if one does not exist (as when
the checking is done by a MUA) or if policy restrictions dictate
otherwise, the word "unknown" SHOULD be substituted. The domain name
may be different from the name found in the MX record that the client
MTA used to locate the receiving MTA.
The "t" macro expands to the decimal representation of the
approximate number of seconds since the Epoch (Midnight, January 1,
1970, UTC). This is the same value as is returned by the POSIX
time() function in most standards-compliant libraries.
When the result of macro expansion is used in a domain name query, if
the expanded domain name exceeds 253 characters (the maximum length
of a domain name), the left side is truncated to fit, by removing
successive domain labels until the total length does not exceed 253
characters.
Uppercased macros expand exactly as their lowercased equivalents, and
are then URL escaped. URL escaping must be performed for characters
not in the "uric" set, which is defined in [RFC3986].
Note: Care must be taken so that macro expansion for legitimate
E-Mail does not exceed the 63-character limit on DNS labels. The
localpart of E-Mail addresses, in particular, can have more than 63
characters between dots.
Note: Domains should avoid using the "s", "l", "o", or "h" macros in
conjunction with any mechanism directive. Although these macros are
powerful and allow per-user records to be published, they severely
limit the ability of implementations to cache results of check_host()
and they reduce the effectiveness of DNS caches.
Implementations should be aware that if no directive processed during
the evaluation of check_host() contains an "s", "l", "o", or "h"
macro, then the results of the evaluation can be cached on the basis
of <domain> and <ip> alone for as long as the shortest Time To Live
(TTL) of all the DNS records involved.
8.2. Expansion Examples
The <sender> is strong-bad@email.example.com.
The IPv4 SMTP client IP is 192.0.2.3.
The IPv6 SMTP client IP is 2001:DB8::CB01.
The PTR domain name of the client IP is mx.example.org.
macro expansion
------- ----------------------------
%{s} strong-bad@email.example.com
%{o} email.example.com
%{d} email.example.com
%{d4} email.example.com
%{d3} email.example.com
%{d2} example.com
%{d1} com
%{dr} com.example.email
%{d2r} example.email
%{l} strong-bad
%{l-} strong.bad
%{lr} strong-bad
%{lr-} bad.strong
%{l1r-} strong
macro-string expansion
--------------------------------------------------------------------
%{ir}.%{v}._spf.%{d2} 3.2.0.192.in-addr._spf.example.com
%{lr-}.lp._spf.%{d2} bad.strong.lp._spf.example.com
%{lr-}.lp.%{ir}.%{v}._spf.%{d2}
bad.strong.lp.3.2.0.192.in-addr._spf.example.com
%{ir}.%{v}.%{l1r-}.lp._spf.%{d2}
3.2.0.192.in-addr.strong.lp._spf.example.com
%{d2}.trusted-domains.example.net
example.com.trusted-domains.example.net
IPv6:
%{ir}.%{v}._spf.%{d2} 1.0.B.C.0.0.0.0.
0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6._spf.example.com
9. Implications
This section outlines the major implications that adoption of this
document will have on various entities involved in Internet E-Mail.
It is intended to make clear to the reader where this document
knowingly affects the operation of such entities. This section is
not a "how-to" manual, or a "best practices" document, and it is not
a comprehensive list of what such entities should do in light of this
document.
This section is non-normative.
9.1. Sending Domains
Domains that wish to be compliant with this specification will need
to determine the list of hosts that they allow to use their domain
name in the "HELO" and "MAIL FROM" identities. It is recognized that
forming such a list is not just a simple technical exercise, but
involves policy decisions with both technical and administrative
considerations.
It can be helpful to publish records that include a "tracking
exists:" mechanism. By looking at the name server logs, a rough list
may then be generated. For example:
v=spf1 exists:_h.%{h}._l.%{l}._o.%{o}._i.%{i}._spf.%{d} ?all
9.2. Mailing Lists
Mailing lists must be aware of how they re-inject mail that is sent
to the list. Mailing lists MUST comply with the requirements in
[RFC2821], Section 3.10, and [RFC1123], Section 5.3.6, that say that
the reverse-path MUST be changed to be the mailbox of a person or
other entity who administers the list. Whereas the reasons for
changing the reverse-path are many and long-standing, SPF adds
enforcement to this requirement.
In practice, almost all mailing list software in use already complies
with this requirement. Mailing lists that do not comply may or may
not encounter problems depending on how access to the list is
restricted. Such lists that are entirely internal to a domain (only
people in the domain can send to or receive from the list) are not
affected.
9.3. Forwarding Services and Aliases
Forwarding services take mail that is received at a mailbox and
direct it to some external mailbox. At the time of this writing, the
near-universal practice of such services is to use the original "MAIL
FROM" of a message when re-injecting it for delivery to the external
mailbox. [RFC1123] and [RFC2821] describe this action as an "alias"
rather than a "mail list". This means that the external mailbox’s
MTA sees all such mail in a connection from a host of the forwarding
service, and so the "MAIL FROM" identity will not, in general, pass
authorization.
There are three places that techniques can be used to ameliorate this
problem.
1. The beginning, when E-Mail is first sent.
1. "Neutral" results could be given for IP addresses that may be
forwarders, instead of "Fail" results. For example:
"v=spf1 mx -exists:%{ir}.sbl.spamhaus.example.org ?all"
This would cause a lookup on an anti-spam DNS blacklist
(DNSBL) and cause a result of "Fail" only for E-Mail coming
from listed sources. All other E-Mail, including E-Mail sent
through forwarders, would receive a "Neutral" result. By
checking the DNSBL after the known good sources, problems with
incorrect listing on the DNSBL are greatly reduced.
2. The "MAIL FROM" identity could have additional information in
the localpart that cryptographically identifies the mail as
coming from an authorized source. In this case, such an SPF
record could be used:
"v=spf1 mx exists:%{l}._spf_verify.%{d} -all"
Then, a specialized DNS server can be set up to serve the
_spf_verify subdomain that validates the localpart. Although
this requires an extra DNS lookup, this happens only when the
E-Mail would otherwise be rejected as not coming from a known
good source.
Note that due to the 63-character limit for domain labels,
this approach only works reliably if the localpart signature
scheme is guaranteed either to only produce localparts with a
maximum of 63 characters or to gracefully handle truncated
localparts.
3. Similarly, a specialized DNS server could be set up that will
rate-limit the E-Mail coming from unexpected IP addresses.
"v=spf1 mx exists:%{ir}._spf_rate.%{d} -all"
4. SPF allows the creation of per-user policies for special
cases. For example, the following SPF record and appropriate
wildcard DNS records can be used:
"v=spf1 mx redirect=%{l1r+}._at_.%{o}._spf.%{d}"
2. The middle, when E-Mail is forwarded.
1. Forwarding services can solve the problem by rewriting the
"MAIL FROM" to be in their own domain. This means that mail
bounced from the external mailbox will have to be re-bounced
by the forwarding service. Various schemes to do this exist
though they vary widely in complexity and resource
requirements on the part of the forwarding service.
2. Several popular MTAs can be forced from "alias" semantics to
"mailing list" semantics by configuring an additional alias
with "owner-" prepended to the original alias name (e.g., an
alias of "friends: george@example.com, fred@example.org" would
need another alias of the form "owner-friends: localowner").
3. The end, when E-Mail is received.
1. If the owner of the external mailbox wishes to trust the
forwarding service, he can direct the external mailbox’s MTA