Correct and complete SPF configurations seem to escape the grasp and understanding of many a sysadmin, Managed Service Providers, and web developers; from the small business with often simple needs, through to larger firms with dedicated staff to deal with the configuration and management of this record. Common pitfalls, and unintended consequences in the configurations are seen more often than not - As one of the simplest and most overlooked DNS entries, it is often not taught or described in great detail other than by the use of checking tools and copy/paste solutions in knowledge-base articles. This working knowledge of SPF records can result in several scenarios from normality, to rejected emails, or worse - a security incident. As the penetration of DMARC expands, this stable foundation must underpin its operation. ## The legacy record type ### SPF record (type 99) This record type was intended to be dedicated for SPF records, it never saw full adoption and was formally killed off in [RFC 7208]( The final verdict and wording was: > __SPF records MUST be published as a DNS TXT (type 16) Resource Record (RR) ... only.__ It is best practice to remove any lingering type 99 records and ensure the correct type 16 (TXT) record is created/updated in its place. ## Looking up SPFs (and other records!) For the MSPs in this world - I suggest using [CIPP]( and specifically the individual domain lookup / domains Analyser. For others who aren't a Microsoft Partner - [MXToolbox]( For anyone wanting a consistent, and ongoing check of their domains: [URIPorts]( ## Structure of SPF The beginning of any SPF record must start with the version e.g. `v=spf1`, followed by the successive mechanisms and qualifiers. The end of the record will usually end in a variation of `all`, except for the redirection modifier. ### Qualifiers Each of the follow descriptions can be expanded by clicking the section to expand with more details. #### + Pass The default condition for any included entry in the mechanism and is usually omitted from the record due to the default nature, Allow the email to proceed. #### ? Neutral Nothing explicitly stated about the mechanism, Allow the email to proceed. #### ~ SoftFail In transition mechanism, Allow the email to proceed, but mark/flag it. #### - Fail Reject the email, delivery should fail (but mostly doesn't due to SPF misconfigurations). ### Mechanisms #### all This mechanism goes at the end of almost every record except for a redirect, this is the catch all for any returns not listed in the record. The only valid entries in production are `-` i.e. fail, or `~` i.e. soft fail.  In my professional opinion, if you don't know about the third party it should not be sending on your behalf. Therefore fail should be used exclusively combined with DMARC reporting on failures for either SPF, or DKIM alignment. #### IP4 / IP6 This set of mechanisms allows a specific IPv4 host, IPv6 host, or network range to be authorised in the record for sending. These mechanism types do not incur any DNS lookups, and are often used to limit the DNS lookups. It is best practice to ensure any allowances are limited in scope to ensure wide swaths of public cloud/IP ranges are not allowed. #### a Looks up the A/AAAA records on the DNS entry provided to ensure they match, this can be everything from the current domain, DNS subdomain, or a network range. It is best practice to ensure any allowances are limited in scope to ensure wide swaths of public cloud/IP ranges are not allowed. #### mx Includes all entries under the current, or specified domain. A network range can be given on this mechanism. #### ptr Rarely used due to the expensive use of DNS lookups. This mechanism uses forward confirmed reverse DNS to validate the sender is valid. #### exists Not typically used other than with SPF macros and DNSBL queries. #### include References, and includes an SPF record located on another domain, this can be an effective way to delegate to a third party when they need to send on your behalf. It is best practice to check and validate the third party record completely and understand the implications of who, and what, can send on your behalf. ### Modifiers #### redirect This can be used to simplify the management of multiple domains by redirecting the entire record to another entry. #### exp Rarely used, this record type can give reasons for a rejection. ### Void Lookups ![]( Void lookup are not often discussed, and it isn't that common to come across it. SPF void lookups relate to the DNS lookups on the SPF record. SPF void lookups are separate to the 10 DNS queries lookup limit, and are capped to a maximum of 2 void lookups. The void lookup count increases every time an answer returns with either an empty, or null response. Once this maximum count is exceeded an SPF PermError i.e. hardfail will occur, and the message will typically be rejected. ## Common Issues / FAQ ****No record at all?**** ![]( Please, please, PLEASE just enter a basic record, monitor with DMARC p=none and work your way from there. ### DNS lookup limits The hard cut off for DNS lookups during an SPF record check is 10 ****additional**** DNS lookups. Beyond this limit the record is invalid, and may result in emails being marked as junk, quarantined, or rejected - depending on DMARC configuration, and the configuration of the receiving mail server. The first DNS lookup is used during the lookup of the initial record, leaving 10 for additional mechanism lookups. This includes any further DNS lookups down the line e.g. ``,'s record includes two other domains. Meaning four DNS lookups have occurred (three additional). One initially for the full record, one direct include on the original record, followed by two lookups for the referenced include. This scales with each subsequent lookup. Using the MX, and Include mechanisms can be quite costly in terms of lookups depending on the number of mail servers listed, and the subsequent chain of DNS lookups. Where possible these should be shifted into the IP4 and IP6 mechanisms to reduce the count. Please note, this needs to be monitored when you include third party entries - they can, and will modify their entries on occasion and this may result in your record pushing over the 10 additional DNS entries lookup limit. ### SPF Length limit The hard limit for the length of the type 16 (txt) record is 255 characters, anything beyond this will result in a failure/invalid record. At this point it is worth expanding out to including a subdomain SPF entry e.g. `` references `` which has more of the record to bypass the limit per entry. ### Multiple Records Having multiple type 16 (txt) records will result in "PermError" which usually means the recipient will junk or quarantine the mail. This results in an inability to correctly interpret the domain’s published records. Should DMARC with a Reject configuration be involved - this will result in the email not being received at all. ### Missing entries Forgetting to include a third party service in your SPF may result in deliverability issues. It is best to pair SPF/DKIM with DMARC reporting in order to get visibility over the hosts sending on your behalf, this not only ensures you're getting through successfully, it can also give you an early warning on spoofing and abuse of your domains. ### Spaces? Another common issue is having spaces between the mechanism such as: `v=spf1 include: -all` The inclusion of the space will cause the entry to interpreted as an empty value i.e. no entry at all. The value after the space is then interpreted with an unknown mechanism. In this specific example, no senders would be authorised to send on behalf of the domain, in others it may result in a particular third party service, IP or other mechanism from being used as a valid sender. ### Being overly specific with the plus operator One of the worst qualifiers to use is `+` with the `all` mechanism, in effect, allowing ANY host to send email on behalf of the domain. Unfortunately I still see this even in 2022. ### I'm not sending email from a domain, what record should i use? The following txt record type specifies no authorised mechanisms, and has a hard fail `v=spf1 -all` This would reject all email, as long as the recipient server is configured to take action on the SPF. ## SPF Macros ### Wait, what? Macros in a text record? ![]( This one is definitely beyond the scope of this post, and a follow up post will happen in the near future with further details. --- [[Epistemic status|Colophon: Brewing]]