Whether you host your own mail server or you outsource your email needs, if your domain sends even a small amount of email, you need a robust, accurate SPF record. Your SPF record helps protect your domain's reputation by making it more difficult for spammers, phishers, and other evildoers to spoof email from your domain. When you publish an SPF record, you let other mail servers know exactly which hosts are allowed to send mail for your domain, and which are not. Large email services may even refuse mail from domains with a missing or invalid SPF record, tightening their stranglehold on email. And, unfortunately, even a small error in your SPF record can make it invalid, resulting in bounced or lost outgoing mail for your domain. It's important that you get your SPF record right.
This guide provides a detailed explanation and several examples to help you understand SPF: what it does, how it works, and how to build a suitable SPF record. If you just need a quick solution, though, our SPF Record Wizard can walk you through the process, check for common mistakes, and suggest an SPF record for your domain, suitable for copy-pasting into a DNS TXT record.
At its core, a Sender Policy Framework (SPF) policy is a tool that helps prevent unauthorized senders from spoofing (forging) your domain name in their email. Your sender policy identifies the IP address of each mail server that is authorized to send mail for your domain, and specifies what should be done with mail from unauthorized hosts. SPF policies are normally based on the MAIL FROM address (also called the envelope-from or return-path address), but they can additionally apply to a your mail servers' HELO/EHLO hostnames. SPF validation does not consider message headers, such as the header From: field, at all. For that, we have DKIM and DMARC.
Your SPF policy is published to the world as a DNS TXT record under your domain. A typical SPF record might look something like this:
"v=spf1 a:mail.example.com mx ~all"
This SPF record specifies that, "Only the host mail.example.com and example.com's MX servers are authorized to send mail with an @example.com email address." The "~all" part further requests that, "If an unauthorized server presents mail claiming to be from an @example.com address, go ahead and accept it, but mark it as possible spam." Although host names are often used in SPF records, it is actually the IP addresses of the hosts that are used for validation.
In this guide, the term client host refers to the mail server (hopefully your own) that is trying to deliver mail for your domain. The term inbound mail server refers to the recipient mail server -- the server at the other end of the pipeline that reads your SPF record and decides whether or not the client host is authorized for your domain and, ultimately, whether or not to accept the mail. The term sender domain refers to the domain in an email's MAIL FROM (envelope) address.
SPF and DKIM (DomainKeys Identified Mail) are different frameworks with different goals. SPF aims to foreclose sender domain spoofing spoofing by publishing a list of your domain's authorized outbound mail servers. Implementation of SPF only requires that you publish the policy in a special DNS record. DKIM (and it's soon-to-be-introduced successor DKIM2) aims to prevent modification of mail content (including headers) in transit. It requires configuring your mail server to cryptographically sign outgoing mail at the source and publishing a public key that inbound servers use to verify the signature. You need both SPF and DKIM properly configured if your domain sends email. Otherwise, very little of your mail will be successfully delivered.
Unfortunately, neither SPF nor DKIM are perfect. SPF does not survive forwarding that keeps the original MAIL FROM header intact and DKIM can fail when additional information is added to a message along the way, for example, by group mailing lists. It would be uncommon, however for both SPF and DKIM to fail for the same message if both are configured correctly.
An additional framework, DMARC (Domain-based Message Authentication, Reporting, and Comformance), ties SPF and DKIM together by aligning a message's From: header with the sender domain (verified by SPF, DKIM, or both). DMARC also lets you clearly outline your expectations for what inbound mail servers should do when a message fails SPF or DKIM validation.
SPF records don't have to be complicated. For many common mail hosting strategies, one of the following boilerplate SPF records are suitable. When in doubt, you can always try the SPF Record Wizard. It can suggest an appropriate SPF record for your domain and help you avoid common pitfalls.
If your domain doesn't send mail at all, then you can (and should!) instruct inbound mail servers to bounce all mail that fraudulently purports to be from your domain:
v=spf1 -all
If you only have one outbound mail server, it is most efficient to use a single a mechanism:
v=spf1 a:your server's host name -all
Swap "~all" for "-all" above if you'd prefer inbound servers to mark mail from unrecognized servers as spam instead of rejecting it.
If your MX records include all of your outbound servers and you don't use any other mail servers, this SPF record is appropriate:
v=spf1 mx -all
Again, swap "~all" for "-all" above if you'd prefer inbound servers to mark mail from unrecognized servers as spam instead of rejecting it.
If multiple domains share the same mail servers, you can create one target SPF record at your primary domain (or just choose one) and point the other domains to that SPF record with:
v=spf1 redirect=your primary domain
SPF mechanisms lay out a set of rules that inbound mail servers use to determine if a client mail host is authorized to send mail bearing your domain's name. Each mechanism ultimately resolves to one or more IP addresses, which are then compared against the client host's IP address to make a decision.
The eight valid SPF mechanisms are summarized in this quick reference table. You can click any mechanism name to jump ahead to a description and examples for any mechanism.
SPF Mechanism Quick Reference | ||
Mechanism | Description | Examples |
mx | Authorizes the IP addresses of all mail hosts listed in a domain's MX records. If a domain is not specified, authorizes all mail hosts in the sender domain's MX records. | mx mx:example.com |
a | Authorizes the IP address of a specific mail host. If a mail host is not specified, authorizes root IP of the sender domain. Accepts CIDR notation to authorize subnets. | a a/24 a:outbound.example.com |
ip4 | Authorizes a specified IPv4 address or IPv4 range. Accepts CIDR notation to authorize subnets. | ip4:1.2.3.4 ip4:1.2.3.4/30 |
ip6 | Authorizes a specified IPv6 address or IPv6 range. Accepts CIDR notation to authorize subnets. | ip6:2001:db8::1 ip6:2001:db8::1/64 |
include | Authorizes IP addresses that match SPF mechanisms from the SPF record of another domain. | include:example.net |
all | Matches all IP addresses and declares your domain's default policy for mail hosts that have not been specifically authorized by another mechanism. | ~all -all |
exists | Looks up the A record for a specified domain and authorizes the client mail host if the A record exists. Used with SPF macros only. | exists:%{i}.spf.example.net |
ptr | Deprecated. Do not use. Performs a double-lookup against the client mail host's IP address and authorizes the client if the validated result matches the specified domain. | ptr:outbound.example.com |
Mechanisms in your SPF record are tried in order, left-to-right, until a mechanism matches the client host's IP address. By default, when a match is found, a Pass result is returned, which tells the receiving domain that the client host is authorized to send your domain's mail, but this behavior can be changed by prefixing a mechanism with -, ?, or ~ (see "Qualifiers" below).
For example, the SPF record:
"v=spf1 mx a:outbound.example.com ip4:1.2.3.4 -all"
instructs inbound mail servers to first check if the client host shares an IP address with any server listed in your MX records, then check if the client's IP address matches the A record for outbound.example.com, then check if the client's IP address is exactly 1.2.3.4. If none of these mechanisms match, the -all mechanism provides that the (probably-spoofed) mail should be rejected.
By default, mechanisms result in a Pass result when a matching IP address is found, but this behavior can be changed by prefixing the mechanism with one of the qualifiers listed below.
SPF Qualifiers | ||
Qualifier | Meaning | Expected Action |
+ | Pass | Host is authorized. Accept the mail. (This is the default action) |
- | Fail | Host is not authorized. Reject the mail. |
~ | SoftFail | Host may not be authorized. Accept the mail, but quarantine it or mark it as spam. |
? | Neutral | The SPF asserts no opinion on the status of the host. Accept the mail. |
For example, this SPF record:
"v=spf1 ~a:inbound.example.com mx ~all"
instructs inbound mail servers to accept mail if it comes from any of your MX servers except inbound.example.com (note the ~ before it's mechanism), which should return SoftFail, along with any unknown client.
This SPF record:
"v=spf1 a:mail.example.com ?include:example.org -all"
instructs servers to accept mail if it comes from mail.example.com and reject mail from all other servers except servers that domain example.org trusts, for which your domain asserts no opinion (note the ? before the include mechanism).
Since SPF works by matching IP addresses, several SPF mechanisms need to perform DNS lookups on your hosts' A or MX records. For busy servers, this can put a heavy burden on DNS resources, so limits are enforced. The lookup needed to retrieve your SPF record is "free," but after that there is a hard limit of 10 mechanisms that require additional DNS hits. The mx, a, include, exists, and ptr mechanisms, as well as the redirect modifier all require additional DNS lookups and all count towards the limit. This includes those mechanisms in your domain's SPF record as well as those in any SPF records you include or redirect to.
In addition, each MX record that is retrieved for an mx mechanism needs a separate DNS lookup to find the MX server's IP address. There is a separate limit of 10 total MX records (not mechanisms). This includes records retrieved due to mx mechanisms in your own SPF record as well as those in any SPF records you include or redirect to.
Both limits are strictly enforced! If evaluation of your SPF record exceeds either limit, it will return a PermError result. Inbound MTAs vary in how they handle error results, but some will refuse to accept your domain's mail due to the invalid SPF record.
The mx mechanism matches all hosts listed in a domain's MX records. When it is followed by a domain name (mx:example.com), it matches the MX hosts for that domain. If no domain is listed (simply mx), it matches the MX hosts for the sender's domain. This mechanism is commonly used to authorize a domain's MX hosts when its mail server(s) handle both incoming and outgoing mail.
For example:
mx | Authorizes the IP addresses for all MX hosts for the sender domain. |
mx:example.com | Authorizes the IP addresses for all MX hosts for example.com |
If you have multiple MX hosts and they do not all send mail, it may be better to authorize the sending hosts using a, ip4, or ip6 mechanisms instead. Alternately, you can exclude a specific host with an a mechanism prefixed with a - or ~ qualifier (-a:mail2.example.com). If you do this, be sure to put the exclusion before the mx mechanism.
Each mx counts against the limit of 10 mechanisms requiring an additional DNS lookup. Further, each MX record retrieved counts against the separate limit of 10 total MX records that can be consulted. If either limit is exceeded without a match, a PermError result is returned, which can result in rejected mail.
A common error that new mail admins make is to include an mx mechanism when it is not needed. If your MX (inbound) mail servers do not also send mail, you should not use the mx mechanism. Also, if all of your outbound mail hosts are identified with a mechanisms elsewhere in your SPF record, the mx mechanism is not needed. You should try to avoid redundancy where possible.
The a mechanism matches a specific host by it's fully-qualified domain name. If a domain name is not specified, it matches the sender domain's root. Optionally, a subnet can be specified by appending a CIDR prefix length. Although the mechanism is called "A," it will match either A or AAAA records.
For example:
a | Authorizes the IP address(es) for the sender domain's root zone. |
a:mail.example.com | Authorizes the IP address for mail.example.com |
Each a mechanism counts against the limit of 10 mechanisms requiring an additional DNS lookup. A common mistake made by new mail admins is to include a mechanisms for hosts that are already authorized by mx. This sort of redundancy is not harmful, but it is unnecessary and makes it more likely that you will run into the limit.
These mechanisms match a specific host by IPv4 of IPv6 address, respectively. Each can authorize a single host or, when a CIDR prefix length is affixed, a subnet. For ip6, shorthand notation is allowed.
For example:
ip4:192.168.0.25 | Authorizes the IPv4 address 192.168.0.25. |
ip4:192.168.0.25/25 | Authorizes the IPv4 address range 192.168.0.1 - 192.168.0.127. |
ip6:2001:db8::1 | Authorizes the IPv6 address 2001:0db8:0000:0000:0000:0000:0000:0001. |
ip6:2001:db8::1/64 | Authorizes the IPv6 address range 2001:0db8:0000:0000:0000:0000:0000:0000 - 2001:0db8:0000:0000:ffff:ffff:ffff:ffff |
ip4 and ip6 mechanisms don't require DNS lookups, so they don't contribute to the limit of 10 such mechanisms. For this reason, they may be preferred over a mechanisms when you need to authorize many individual hosts. This "flattening" of your IP record comes at a cost to readability and future-proofing, though.
The include mechanism allows your SPF record to include rules from the SPF record of another domain. It is probably the most misunderstood and misused of all the SPF mechanisms. If any of the rules in the target domain's SPF record would result in a Pass result, the client's IP address is a match and your SPF will return the result specified by it's qualifier (Pass by default). However, all other results from the target SPF, other than an error, only return "no match," meaning no result at all for that mechanism. The include mechanism cannot selectively fail hosts based on the target SPF's rules. There are also other caveats, described below.
For example:
include:example.com | Retrieve the SPF record for example.com and authorize any host that example.com would authorize. |
?include:example.com | Retrieve the SPF record for example.com and return a Neutral result for any host that example.com would authorize. |
Take heed. There are some important caveats surrounding the use of include mechanisms:
A common use case where the include mechanism is appropriate is when you have a very long SPF record, as might happen if you have many ip4 and/or ip6 mechanisms. In this case, your SPF record might exceed 255 characters, which is not allowed for any DNS record. A solution is to split the SPF record into multiple parts with different identifiers and include each part in your main SPF record. For example:
example.com 1800 IN TXT "v=spf1 include:_spf1.example.com include:_spf2.example.com ~all"
_spf1.example.com 1800 IN TXT "v=spf1 (a list of SPF mechanisms)"
_spf2.example.com 1800 IN TXT "v=spf1 (another list of SPF mechanisms)"
As its name implies, the all mechanism matches all IP addresses. As such, there can be only one all and it must be the last mechanism in your SPF record, unless it has a redirect modifier instead. Any mechanisms that come after it will never be evaluated. Further, if there is no all (or redirect) mechanism, SPF validation will return a None result for unauthorized client hosts instead of the normally-expected Fail or Soft Fail.
Unlike the other mechanisms, all should always be prefixed with a qualifier (?, -, or ~, but never +), depending on how you want mail servers to treat your domain's mail when it comes from unauthorized servers. See "Qualifiers", above, for a description of the qualifiers.
Most SPF records use ~all as their final mechanism, which tells inbound MTAs that you would like them to accept your domain's mail from unauthorized client hosts, but mark it as possible spam. This is strongly recommended, at least until you have thorougly tested your SPF record to make sure all of your legitimate mail passes SPF checks.
~all | Inbound MTAs should accept mail from client hosts that haven't otherwise been authorized, but quarantine it or mark it as spam. |
-all | Inbound MTAs should reject mail from client hosts that haven't otherwise been authorized. |
Note that an SPF record may not have both an all mechanism and a redirect modifier. If both are present, only the all mechanism will be honored.
The exists mechanism takes the form exists:domain and returns a match if domain has a valid A (not AAAA) DNS record. domain for this mechanism is typically a custom subdomain name built on-the-fly using SPF macros. For example, the macro %{i} expands to the client host's IP address. If the client host has an IP address of 1.2.3.4, exists:%{i}._spf.example.com would match only if 1.2.3.4._spf.example.com has any valid A record. This mechanism is not common, but is sometimes used to authorize IP addresses that are subject to change.
exists:%{i}._spf.example.com | Authorizes clients if their IP address._spf.example.com has an A record. |
exists:%{i}._spf.%{d} | Same as above, but uses the %{d} macro, which expands to the sender domain. |
Each exists mechanism counts toward the limit of 10 DNS lookup elements.
The ptr mechanism is deprecated and should not be included in SPF records, but it is still supported by SPF validators for legacy reasons. The mechanism takes the form ptr (for the sender's domain) or ptr:domain (for outside domains). When used, which it should not be, the SPF validator will perform a reverse lookup of the client server's IP address, validate the returned domain name against the client IP with a forward lookup, and then check to see if the returned domain name matches domain (or the sender's domain if no outside domain is specified).
ptr | Authorizes the client host if a double-lookup on its IP address matches and if the reverse lookup's result matches the sender domain. |
ptr:example.net | Authorizes the client host if a double-lookup on its IP address matches and if the reverse lookup's result matches "example.net". |
Each ptr mechanism counts toward the limit of 10 DNS lookup elements.
Unlike mechanisms, SPF modifiers don't return a decision about whether a client host is authorized. Rather, they give a command to the inbound server to switch to a different domain's SPF record or to use a custom error message for unauthorized client hosts. Modifiers are always followed by =, then by a domain specification.
This table summarizes the two allowed SPF Modifiers. Click either of the modifier names to jump to a more detailed description and examples.
SPF Modifiers Quick Reference | ||
Modifier | Description | Examples |
redirect | Redirects the SPF validator to another domain's SPF record and return its results. | redirect=_spf.example.com |
exp | Specifies a DNS TXT record with an error message that should be sent when SPF validation returns a "Fail" result. | exp=_spffail.example.com exp=_spffail.%{d} |
This modifier causes the validator to switch to another domain's SPF record. It can follow one or more mechanisms and, if present, it must be the last element in the SPF record. In fact, if it is not the last element, it will still be evaluated last.
redirect=example.net | Instructs the SPF validator to retrieve the SPF record for example.net and evaluate the client host's IP address using example.net's SPF. |
redirect is commonly used by itself when an individual or organization sends mail for multiple domains from a single mail server. For example, if you control 3 domains (example.com, example.net, and example.org), all of which send mail and all of which use the same mail servers, you might create a full SPF record for one domain and redirect the other domains to it:
example.com 1800 IN TXT "v=spf1 mx:example.com ~all"
example.net 1800 IN TXT "v=spf1 redirect=example.com"
example.org 1800 IN TXT "v=spf1 redirect=example.com"
All of the caveats for the include mechanism also apply to the redirect modifier:
Also, the all mechanism and the redirect modifier cannot co-exist in the same SPF record. If they do, the redirect modifier will be ignored.
The exp (explanation) modifier specifies a custom TXT record with an error message that should be returned when the SPF validation returns Fail (but not SoftFail). If there is no exp modifier (as is usually the case since it is not commonly-used), a Fail result returns a default message.
For example, these DNS records instruct inbound MTAs to reject spoofed mail with the message "Mail from this domain should be sent only by its own servers":
example.com 1800 IN TXT "v=spf1 mx -all exp=_spffail.example.com"
_spffail.example.com 1800 IN TXT "Mail from this domain should be sent only by its own servers"
SPF macros can also be used within the error message. This example will return a message similar to "1.2.3.4 is not authorized to send mail for example.com."
example.com 1800 IN TXT "v=spf1 mx -all exp=_spffail.example.com"
_spffail.example.com 1800 IN TXT "%{i} is not authorized to send mail for %{d}"
Although it's not required for mail deliverability and, frankly, not widely adopted, RFC 7208 also recommends publishing SPF records for your mail servers' HELO/EHLO host names. In years past, doing this could help prevent evil servers from masquerading as your domain's mail servers. These days, almost all inbound mail servers use a validated reverse-lookup to determine the client host's name instead of HELO/EHLO, but creating an SPF record for each of your outbound servers can add an additional layer of protection if you choose to do so. It can also make SPF validation more efficient since fraudulent servers will be turned away at the door.
To publish an SPF record for a mail server, simply create a TXT record with a single a or ip4/ip6 mechanism and -all. For example, an SPF record for host name mail.example.com might look like this:
mail.example.com 1800 IN TXT "v=spf1 a -all"
or this:
mail.example.com 1800 IN TXT "v=spf1 ip4:1.2.3.4 -all"
Note that the record is attached to the hostname (mail.example.com) and not the domain (example.com).
SPF records are flexible and offer a wide variety of (somewhat obtuse) ways to enumerate your mail servers. Consequently, it's easy to make mistakes. Some mistakes are minor but some can significantly affect your domain's mail deliverability. These are the most common mistakes I've seen new (and, sometimes, even experienced) mail admins make when building an SPF record.
❌ Authorizing the same host multiple times
I don't think most admins intend to do this, but I see it often. If you've used an mx mechanism, for example, all of your MX servers are already authorized. You should not also include those same hosts with an a mechanism.
❌ Blindly including an mx mechanism
If your mail servers both send and receive mail using the same host names, by all means, use an mx mechanism. If your MX servers only receive incoming mail, though, there's no reason to do so. List your outbound servers using a or ip4/ip6 mechanisms instead. SPF records should only authorize your outbound mail server(s).
❌ Using an mx mechanism incorrectly
If your MX servers also send mail, your mx mechanism should list your domain, not any individual host name. The SPF validator will look up your MX record(s) to find the host names. For example, mx:example.com is probably correct; mx:mail.example.com probably is not.
❌ Using an include mechanism for an SPF record that does not exist
If you must use an include mechanism for an external domain (and you should really ask yourself if it's necessary), double check that the target SPF record actually exists. Frequently. An include mechanism that points to a domain with no valid SPF record can invalidate your entire SPF record.
❌ Not testing the SPF record
Once you've published your SPF record, it is critical that you test it to avoid having mail rejected unnecessarily. Fortunately, there are some free online services that receive a test email from your domain and test its deliverability. These services also check DKIM and DMARC conformance and possibly other characteristics. One such service that does this in an entertaining way is Learn and Test DMARC. Another, this one more suitable for bulk mailers, is About my Email.
When in doubt, it's always best to go to the source. The entire SPF framework is defined by RFC 7208: Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, Version 1.
Happy Mailing!
Copyright 2024 Steve Derby for The Status Line (https://www.statusline.org/)
spfemailanti-spam
The spell trickles away to nothing. The merchant smiles. "Do you think you are the first magician to try to use lawless, thieving magic on a humble merchant?" He throws you into the street and bars the door.