{"id":1189,"date":"2024-07-05T06:55:44","date_gmt":"2024-07-05T06:55:44","guid":{"rendered":"https:\/\/zalvis.com\/docs\/?p=1189"},"modified":"2024-07-05T06:55:44","modified_gmt":"2024-07-05T06:55:44","slug":"add-spf-records","status":"publish","type":"post","link":"https:\/\/zalvis.com\/docs\/add-spf-records.html","title":{"rendered":"Add SPF records"},"content":{"rendered":"<p>This section defines HOWTO configure a Sender Policy Framework (SPF) record for a domain and its mail servers.<br \/>\nBriefly the design intent of the SPF record is to allow a receiving MTA (Message Transfer Agent) to interrogate the Name Server of the domain which appears in the email (the sender) and determine if the originating IP of the mail (the source) is authorized to send mail for the sender\u2019s domain.<\/p>\n<p>The SPF information is contained in a standard TXT RR (though a new RR type may be allocated if and when SPF reaches standardization by the IETF).<\/p>\n<p>If a SPF (TXT) RR exists and authorizes the source IP address the mail can be accepted by the MTA. If the SPF (TXT) RR does not authorize the IP address the mail can be bounced \u2013 it did not originate from an authorized source for the sender\u2019s domain. If the domain does not have an SPF RR the situation is no worse than before.<\/p>\n<p>Many Open Source MTAs have already been modified to use the SPF record and there is no down-side and plenty of potential up-side to implement the proposed record format now.<\/p>\n<p>We use the following terminology to try and simplify the descriptions below:<br \/>\nsender \u2013 the full email address of the originator of the mail item (typically uses return-path in the actual SPF checks)<br \/>\nsource-ip \u2013 the IP address of the SMTP server trying to send this message<br \/>\nsender-domain the domain name part of the sender\u2019s email address e.g. assume the sender is <a href=\"mailto:info@example.com\">info@example.com<\/a> the sender-domain is example.com.<\/p>\n<p>The SPF record defines one or more tests to carry out to verify the sender. Each test returns a condition code (pre below). The first test to pass will terminate SPF processing.<\/p>\n<p>v=spf1 Mandatory. Defines the version being used. Currently the only version supported is spf1.<br \/>\npre Optional (defaults to +). pre defines the code to return when a match occurs. If a test is conclusive either add + or omit (defaults to +). If a test might not be conclusive use \u201c?\u201d or \u201c~\u201d (tilde). \u201c-\u201c(minus) is typically only used with -all to indicate that if we have had no previous matches \u2013 fail.<br \/>\nValue Description<br \/>\n+ Default. Pass.<br \/>\n\u2013 Fail.<br \/>\n~ Softfail.<br \/>\n? Neutral.<\/p>\n<p>type<\/p>\n<p>Defines the mechanism type to use for verification of the sender. May take one of the following values:<br \/>\nBasic Mechanisms<\/p>\n<p>These types do NOT define a verification mechanism but affect the verification sequence.<br \/>\ninclude \u2013 Recurse (restart) testing using supplied domain. The sender-domain is replaced with the included domain name. Example:<\/p>\n<p>; spf record for example.com<br \/>\nexample.com. IN TXT \u201cv=spf1 include:example.net -all\u201d<br \/>\n; use the SPF details for example.net<br \/>\n; in the above case to replace example.com\u2019s SPF<br \/>\n; or<br \/>\nexample.com. IN TXT \u201cv=spf1 mx include:example.net -all\u201d<br \/>\n; additive \u2013 use MX RR for example.com<br \/>\n; AND if that fails use example.nets\u2019s SPF<br \/>\nall \u2013 The all type terminates processing (but may be optionally followed by a mod value). It is defined to be optional but it is a Good Thing\u2122 to include it. It is normally present in the form -all to signify that if processing reaches this point without a prior match the result will be fail. But if you are not sure that the tests are conclusive you could use ?all which would allow mail to be accepted even if all previous checks failed.<br \/>\nSender Mechanisms<\/p>\n<p>These types define a verification mechanism.<br \/>\nip4 \u2013 use IP Version 4 addresses e.g. 192.168.3.0 for verification<br \/>\nip6 \u2013 use IP Version 6 addresses for verification<br \/>\na \u2013 use DNS A RRs for verification<br \/>\nmx \u2013 use DNS MX RRs for verification<br \/>\nptr \u2013 use DNS PTR RRs for verification<br \/>\nexists \u2013 test for existence of domain<br \/>\nValue Description<\/p>\n<p>a<br \/>\na:domain<br \/>\na:domain\/cidr<br \/>\na\/cidr<\/p>\n<p>In its base form this uses the sender-domain to find an A RR(s) to verify the source. This form relies on an A RR for the domain e.g.<\/p>\n<p>; fragment for example.com<br \/>\n$ORIGIN example.com.<br \/>\nexample.com. IN TXT \u201cv=spf1 a -all\u201d<br \/>\n; needs domain A record<br \/>\n@ IN A 192.168.0.3<br \/>\n; functionally the same as<br \/>\nexample.com. IN A 192.168.0.3<\/p>\n<p>The form a\/cidr applies the test to the cidr (or IP refix or slash) range of the sender-domain\u2019s A RR.<\/p>\n<p>The form a:domain replaces sender-domain with domain\u2019s A RR for verification. This does NOT use domain\u2019s SPF record(s) (use include for that). The domain form may use macro-expansion features. Example:<\/p>\n<p>; fragment for example.net<br \/>\n$ORIGIN example.net.<br \/>\n@ IN TXT \u201cv=spf1 a:example.com -all\u201d<br \/>\n; will use a single A query to example.com<br \/>\n; which may not yield the result expected unless<br \/>\n; example.com has an A record as below<br \/>\n@ IN A 192.168.0.3<br \/>\n; functionally the same as<br \/>\nexample.com. IN A 192.168.0.3<\/p>\n<p>can take a host name format as shown below:<\/p>\n<p>; fragment for example.net<br \/>\n$ORIGIN example.net.<br \/>\n@ IN TXT \u201cv=spf1 a:mail.example.com -all\u201d<br \/>\n; will use a single A query for mail.example.com<\/p>\n<p>The form a:domain\/cidr applies the cidr range to the IP address obtained from the A query e.g.<\/p>\n<p>; fragment for example.net<br \/>\n$ORIGIN example.net.<br \/>\n@ IN TXT \u201cv=spf1 a:mail.example.com\/27 -all\u201d<br \/>\n; will use a single A query for mail.example.com<\/p>\n<p>Any of the 32 IP addresses that contain mail.example.com will pass. e.g. if the source-ip is 192.168.0.25 and the A RR for mail.example.net is 192.168.0.2 then the test will pass.<\/p>\n<p>mx<br \/>\nmx:domain<br \/>\nmx:domain\/cidr<br \/>\nmx\/cidr<\/p>\n<p>This basic form without any extensions uses the MX RR of the sender-domain to verify the mail source-ip. The MX record(s) return a host name from which the A record(s) can be obtained and compared with the source-ip. The form mx\/cidr applies the IP Prefix or slash range to the A RR address. With any of the domain extensions the MX record of the designated (substituted) domain is used for verification. The domain form may use macro-expansion features.<\/p>\n<p>Warning Remember the MX RR defines the receiving MTA. If this is not the same host(s) as the sending (SMTP) MTA tests based on an mx type will fail. Examples:<\/p>\n<p>; fragment for example.com<br \/>\n$ORIGIN example.com.<br \/>\nIN TXT \u201cv=spf1 mx:example.net -all\u201d<br \/>\n; verify sender using exmple.net MX and A RRs<\/p>\n<p>; fragment for example.com<br \/>\n$ORIGIN example.com.<br \/>\nIN TXT \u201cv=spf1 mx:\/26 -all\u201d<br \/>\n; verify sender using exmple.com MX and A RRs<br \/>\n; and use 16 address range<br \/>\nptr<br \/>\nptr\/domain<\/p>\n<p>Use the source-ip\u2019s PTR RR and a reverse map query. The AA RR for the host is then obtained. If this IP matches the sender-ip AND the sender-domain is the same as the domain name of the host obtained from the PTR RR then the test passes. The form ptr:domain replaces the sender-domain with domain in the final check for a valid domain name. The domain form may use macro-expansion features. The PTR record is the least preferred solution since it places a load on the IN-ADDR.ARPA (IPv4) or IPV6.ARPA reverse-map domains which generally have less capacity than the gTLD and ccTLD domains. Examples:<\/p>\n<p>; fragment for example.com<br \/>\n$ORIGIN example.com.<br \/>\n@ IN TXT \u201cv=spf1 ptr -all\u201d<br \/>\n; the effect is to allow any host which is reverse mapped<br \/>\n; in the domain to send mail<br \/>\nip4:ipv4<br \/>\nip4:ipv4\/cidr In its basic form defines an explicit ipv4 address to verify the mail source-ip. If the source-ip is the same as ipv4 the test passes. May optionally take the form ipv4\/cidr to define a valid IP address range. Since this type incurs the least additional load on the DNS the current draft of the proposed RFC recommends this format. Examples:<\/p>\n<p>; fragment for example.com<br \/>\n$ORIGIN example.com.<br \/>\n@ IN TXT \u201cv=spf1 ip4:192.168.0.2 -all\u201d<br \/>\n; if source-ip is 192.168.0.2 test passes<br \/>\n; cidr format<br \/>\n@ IN TXT \u201cv=spf1 ip4:192.168.0.2\/27 -all\u201d<br \/>\n; if source-ip is in range 192.168.0.1<br \/>\n; to 192.168.0.31 test passes<br \/>\nip6:ipv6<br \/>\nip6:ipv6\/cidr In its basic form defines an explicit ipv6 address to verify the mail source-ip. If the source-ip is the same as ipv6 the test passes. May optionally take the form ipv6\/cidr to define a valid IP address range. Since this type incurs the least additional load on the DNS the current draft of the proposed RFC recommends this format. Examples:<\/p>\n<p>; fragment for example.com<br \/>\n$ORIGIN example.com.<br \/>\n@ IN TXT \u201cv=spf1 ip6:2001:db8::10 -all\u201d<br \/>\n; if source-ip is 2001:db8:0:0:0:0:0:10 test passes<br \/>\n; cidr format<br \/>\n@ IN TXT \u201cv=spf1 ip4:2001:db8::10\/120 -all\u201d<br \/>\n; if source-ip is in range 2001:db8:0:0:0:0:0:0<br \/>\n; to 2001:db8:0:0:0:0:0:FF test passes<br \/>\nexists:domain<\/p>\n<p>The existence (any valid A RR) of the specified domain allows the test to pass. Domain may use macro-expansion features.<\/p>\n<p>mod<\/p>\n<p>Two optional record modifiers are defined. If present they should follow the last type directive i.e. after the all. The current values defined are as follows:<br \/>\nModifier Description<br \/>\nredirect=domain Redirects verification to use the SPF records of the defined domain. Functionally equivalent to include but can appear on its own (without a terminating all) or can placed after the all which means \u201cif all the previous test fail try this redirect\u201d. Examples:<\/p>\n<p>; fragment for example.com<br \/>\n$ORIGIN example.com.<br \/>\n@ IN TXT \u201cv=spf1 ip4:192.168.0.2 -all redirect=example.net\u201d<br \/>\n; if source-ip is 192.168.0.2 test passes<br \/>\n; if it fails redirect to example.net<br \/>\n; OR single redirect<br \/>\n@ IN TXT \u201cv=spf1 redirect=example.net\u201d<br \/>\n; only use example.net SPF record<br \/>\nexp=txt-rr<\/p>\n<p>The exp record if present should come last in a SPF record (after the all if present). It defines a DNS name whose TXT record\u2019s text may be returned with any failure message. Example:<\/p>\n<p>; domain SPF record<br \/>\nIN TXT \u201cv=spf1 mx -all exp=getlost.mydomain.com\u201d<br \/>\n; the getlost TXT record<br \/>\ngetlost IN TXT \u201cNot authorized to send mail for the domain\u201d<\/p>\n<p>The syntax allowed by this record is significantly more complex (see macro-expansion below.<br \/>\nMacro-Expansion<\/p>\n<p>SPF defines a number of macro-expansion features as defined below:<br \/>\nModifier Description<br \/>\n%(c) Only allowed in TXT records referenced by the exp field. The IP of the receiving MTA.<br \/>\n%(d) The current domain normally the sender-domain %(o) but replaced by the value of any domain argument in the type above.<br \/>\n%(h) The domain name supplied on HELO or EHLO, normally the hostname of the sending SMTP server.<br \/>\n%(i) sender-ip The IP of SMTP server sending mail for user <a href=\"mailto:info@example.com\">info@example.com<\/a>.<br \/>\n%(l) replace with local part of sender e.g. if sender is <a href=\"mailto:infor@example.com\">infor@example.com<\/a> local part is info.<br \/>\n%(o) The sender-domain e.g. if email address is <a href=\"mailto:info@example.com\">info@example.com<\/a> the sender-domain is example.com.<br \/>\n%(p) The validated domain name. The name obtained using the PTR RR of the sender-ip. Use of this macro will require an additional query unless a ptr type is used.<br \/>\n%(r) Only allowed in TXT records referenced by the exp field. The name of the host performing the SPF check. Normally the same as the receiving MTA.<br \/>\n%(t) Only allowed in TXT records referenced by the exp field. Current timestamp.<br \/>\n%(s) Replace with sender email address e.g. <a href=\"mailto:info@example.com\">info@example.com<\/a><br \/>\n%(v) Replaced with \u201cin-addr\u201d if sender-ip is an IPv4 address and \u201cipv6\u201d if an IPv6 address. Used to construct reverse map strings.<\/p>\n<p>The above macros may take one or more additional arguments as follows:<\/p>\n<p>r \u2013 Indicates reverse the order of the field e,g, %(or) would be displayed as com.example and %(ir) would display 192.168.0.2 as 2.0.168.192. The normal split used \u201c.\u201d (dor) as the separator but any other separator may be used e.g. %(sr@) would display example.com.info, when fields are rejojned they will always use a \u201c.\u201d (dot).<\/p>\n<p>digit \u2013 the presence of a digit (range 1 to 128) limits the number of right most elements displayed e.g. %(d1) displays com only from example.com but %(d5) would display up to five right hand element up to the maximum available e.g. example.com.<br \/>\nExamples<br \/>\nExample 1<\/p>\n<p>Example 1: Assumes a single mail server which both sends and receives mail for the domain.<\/p>\n<p>; zone file fragment for example.com<br \/>\n$ORIGIN example.com.<br \/>\nIN MX 10 mail.example.com.<br \/>\n\u2026.<br \/>\nmail IN A 192.168.0.4<br \/>\n; SPF stuff<br \/>\n; domain SPF<br \/>\nexample.com. IN TXT \u201cv=spf1 mx -all\u201d<br \/>\n; mail host SPF<br \/>\nmail IN TXT \u201cv=spf1 a -all\u201d<\/p>\n<p>Notes:<br \/>\nthe domain SPF is returned from a sender-domain query using the sender\u2019s email address e.g. sender = <a href=\"mailto:info@example.com\">info@example.com<\/a> sender-domain = example.com. The SPF record only allows the MX host to send for the domain.<br \/>\nthe mail host SPF is present in case the receiving MTA uses a reverse query to obtain the source-ip host name and then does a query for the SPF record of that host. The SPF record states that the A record of mail.example.com alone is permitted to send mail for the domain.<\/p>\n<p>If the domain contains multiple MX servers the domain SPF would stay the same but each mail host should have a SPF record.<\/p>\n<div class=\"vsoyd69e0ab6c6afa2\" >If you enjoyed this article, then you\u2019ll love Zalvis's Cloud Hosting platform. Turbocharge your website and get 24\/7 support from our veteran team. Our world-class hosting infrastructure focuses on auto-scaling, performance, and security. Let us show you the Zalvis difference! <a href=\"https:\/\/zalvis.com\/\">Check out our services.<\/a><\/div><style type=\"text\/css\">\r\n@media screen and (min-width: 1201px) {\r\n.vsoyd69e0ab6c6afa2 {\r\ndisplay: block;\r\n}\r\n}\r\n@media screen and (min-width: 993px) and (max-width: 1200px) {\r\n.vsoyd69e0ab6c6afa2 {\r\ndisplay: block;\r\n}\r\n}\r\n@media screen and (min-width: 769px) and (max-width: 992px) {\r\n.vsoyd69e0ab6c6afa2 {\r\ndisplay: block;\r\n}\r\n}\r\n@media screen and (min-width: 768px) and (max-width: 768px) {\r\n.vsoyd69e0ab6c6afa2 {\r\ndisplay: block;\r\n}\r\n}\r\n@media screen and (max-width: 767px) {\r\n.vsoyd69e0ab6c6afa2 {\r\ndisplay: block;\r\n}\r\n}\r\n<\/style>\r\n","protected":false},"excerpt":{"rendered":"<p>This section defines HOWTO configure a Sender Policy Framework (SPF) record for a domain and its mail servers. Briefly the design intent of the SPF record is to allow a receiving MTA (Message Transfer Agent) to interrogate the Name Server of the domain which appears in the email (the sender) and determine if the originating [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[],"class_list":["post-1189","post","type-post","status-publish","format-standard","hentry","category-email"],"_links":{"self":[{"href":"https:\/\/zalvis.com\/docs\/wp-json\/wp\/v2\/posts\/1189","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zalvis.com\/docs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zalvis.com\/docs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zalvis.com\/docs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zalvis.com\/docs\/wp-json\/wp\/v2\/comments?post=1189"}],"version-history":[{"count":2,"href":"https:\/\/zalvis.com\/docs\/wp-json\/wp\/v2\/posts\/1189\/revisions"}],"predecessor-version":[{"id":1191,"href":"https:\/\/zalvis.com\/docs\/wp-json\/wp\/v2\/posts\/1189\/revisions\/1191"}],"wp:attachment":[{"href":"https:\/\/zalvis.com\/docs\/wp-json\/wp\/v2\/media?parent=1189"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zalvis.com\/docs\/wp-json\/wp\/v2\/categories?post=1189"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zalvis.com\/docs\/wp-json\/wp\/v2\/tags?post=1189"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}