SPF

Email Domain Authorization

Sender Policy Framework (SPF) is a DNS-based mechanism to authorize hosts to use a domain name in “HELO” (“EHLO”) and “MAIL FROM” SMTP protocol identities.

DNS TXT RR record has the following format:

<domain_name> IN TXT “v=spf1 ([qualifier]mechanism / modifier) … ()”

There are four qualifiers:

 "+" - pass. The default if the qualifier is not specified.
 "-" - fail
 "~" - softfail
 "?" - neutral

The mechanisms are:

  1. “all” - basic mechanism that matches all, used as the default at the end of the record. Mechanisms after “all” are ignored.
  2. “include:<domain_name>” - another basic mechanism that designates other domain that is outside of the administrative boundary of original domain. It only authorizes a set of hosts from another domain but the sender policy is still determined by the original domain using qualifiers.
  3. “a” - designated mechanism that matches if the “A” of “AAAA” domain host record DNS lookup equals to the sender’s IP.
  4. “mx” - designated mechanism that matches if the sender’s IP equals to one of the IPs of MX hosts.
  5. “ptr” - designated mechanism that matches if the reverse lookup on the sender’s IP matches the domain name. Do not use - slow and not reliable!
  6. “ip4:<ipv4_address/mask>” - designated mechanism that matches if sender’s IPv4 matches the ip_address or a range of IPv4.
  7. “ip6:<ipv6_address/mask>” - designated mechanism that matches if sender’s IPv6 matches the ip_address or a range of IPv6.
  8. “exists:<domain_name>” - designated mechanism that matches when DNS “A” RR lookup on domain_name returns any “A” record. It is used for complex queries with expansions.

There are two modifiers:

  1. “redirect=<domain_name>” - consolidates authorization of multiple domains under the same administrative control and policies into a single record.
  2. “exp=<domain_name>” - If the result of check is “failed”, then DNS TXT RR lookup is done on the domain_name and the string is return as an explanation for the failure.

The following macros can be used in <domain_name>:

 "%%" - literal "%".
 "%_" expands to a single " " space.
 "%-" expands to a URL-encoded space, viz., "%20".
 %{s} = <sender>
 %{l} = local-part of <sender>
 %{o} = domain of <sender>
 %{d} = <domain>
 %{i} = <ip>
 %{p} = the validated domain name of <ip> (do not use)
 %{v} = the string "in-addr" if <ip> is ipv4, or "ip6" if <ip> is ipv6
 %{h} = HELO/EHLO domain

The following macros are allowed only in “exp” text:

 %{c} = SMTP client IP (easily readable format)
 %{r} = domain name of host performing the check
 %{t} = current timestamp

These are the results of an SPF check:

  1. “none” - no errors but no info to make a conclusion
  2. “neutral” - the policy exists but no decision can be made. Should be treated the same as none.
  3. “pass” - the domain authorizes the mailing host to send emails from it
  4. “fail” - the domain explicitly forbids the mailing host to send emails from it
  5. “softfail” - between none/neutral and fail. The receiver should not reject an email solely based on this result
  6. “temperror” - Usually results from a DNS error. The receiver may accept or temporarily reject an email with reply code 451 or enhanced 4.4.3. status codes.
  7. “permerror” - Usually results from a bad SPF record. The receiver should reject an email with 550 reply code or 5.5.2 enhanced status codes.

It is recommended to write the results of the SPF check into the email headers such as Received-SPF or Authentication-Results. For the format of these fields, see the RFC 7208.

An email receiver is recommended to check “HELO” (“EHLO”) first. If a decision can be made, then checking “MAIL FROM” is not necessary. Checking “HELO” (“EHLO”) might be the only option for bounced emails that may have an empty “MAIL FROM”.