In this post, I will share my best practices for getting a handle on your SPF record.
Why it makes sense to have a good SPF procedure in place
In a previous blog post, I explained the limitations of SPF and how it works with DKIM and DMARC. It’s crucial to have a well-structured SPF procedure to avoid future problems, especially since exceeding the DNS lookup limit of 10 can cause issues, such as:
- Your domain is vulnerable to spoofing on the P1 sender domain (
RFC5321.MailFrom
) - Your domain authentication or validation may fail (
spf=PermError
) - Your emails will be undeliverable without any warning
Around the globe you will find an answer to bypass the DNS lookup limit with SPF flattening. This approach converts hostnames to IP addresses, which don’t count in the DNS lookup count.
The dangers of SPF flattening
The problem with SPF flattening is that email service providers can change or add IP addresses without notifying you. As a result, your SPF record becomes inaccurate, leading to complications with email delivery. Yes, there are paid tools available to automate this process. However, SPF flattening also increases the likelihood of forgetting to remove entries that are no longer needed, resulting in over-authorization.
From a security perspective, over-authorization of unnecessary SPF entries creates a potential attack vector. If an adversary gains access to any infrastructure listed in an SPF record, they can bypass your SPF and DMARC to send DMARC-compliant email.
When you segment your vendors and email streams, there is no need for SPF flattening, as subdomain segmentation creates dedicated domains for specific email streams, each with its own 10 DNS lookups.
Subdomain segmentation can be implemented in three ways:
- Using a direct subdomain address, such
news.yourdomain.com
, where both the P1 sender (envelope sender) and P2 sender (header sender) use the subdomain (e.g.,news@news.yourdomain.com
). - Setting only the P1 sender to a subdomain (if supported by your vendor or email stream, such as SendGrid) allows SPF alignment in relaxed mode (assuming your DMARC policy uses the default
aspf=r
tag). For example, SPF aligns with subdomainnews.yourdomain.com
as the P1 sender, while the email is still sent from your primary domainyourdomain.com
as the P2 sender (e.g.,news@yourdomain.com
).- DMARC policy tag
aspf=r
(SPF relaxed mode): In this mode, the authenticated signing domain and the sender domain can be subdomains of each other and still be considered aligned.
- DMARC policy tag
- Using an SPF macro that points to a subdomain allows you to continue sending from your main domain, but only from a fixed/static sender address (e.g.,
news@yourdomain.com
).
These subdomain segmentation options can be combined, as covered in this blog. Adopting SPF segmentation increases control, reduces attack surfaces, and mitigates the impact of potential cyber incidents.
SPF flattening attempts to work around the too many DNS lookups problem without addressing its underlying causes. Avoiding SPF record flattening will help you get a handle on your SPF record.
How to get a handle on your SPF record
A quick win on how to handle your SPF record:
- Not using entries like
a
andmx
, these mechanisms are often useless and probably should not be included in your SPF record (and other duplicate SPF mechanisms).
For the long term:
Imagine your organization has an SPF record on yourdomain.com
with 9 of the 10 allowed DNS lookups, such as:
v=spf1 ip4:11.222.33.444 ip4:44.33.222.111 ip4:22.33.444.555 ip4:55.66.777.8 ip4:88.99.999.99 ip4:99.88.777.66 mx include:spf.protection.outlook.com include:_spf.salesforce.com include:mail.zendesk.com include:_spf.app1.com include:_spf.app2.com -all
Calculation of DNS lookups:
DNS Lookup | Count |
---|---|
include:spf.protection.outlook.com |
1 DNS Lookup |
include:_spf.salesforce.com |
2 DNS Lookups |
include:mail.zendesk.com |
1 DNS Lookup |
include:_spf.app1.com |
2 DNS Lookups |
include:_spf.app2.com |
2 DNS Lookups |
mx (your MX record) |
1 DNS Lookup |
Total: | 9 DNS Lookups |
Effective segmentation of your email streams is essential for maintaining control and clarity over your SPF record.
Cut your SPF record
Based on the information provided, identify which SaaS applications can be restricted to sending emails from a fixed sender address using an SPF macro. Additionally, determine which services, such as Microsoft 365, require sending emails from multiple addresses using your primary domain, and which services are not subject to these restrictions and can send through a subdomain, or where the email stream supports SPF alignment in relaxed mode through a subdomain.
A helpful approach is to create a list of your SPF record entries and specify the desired behavior for each entry, as shown in the example below:
Look up | Outcome |
---|---|
include:spf.protection.outlook.com |
Uses multiple email addresses and must send through the primary domain yourdomain.com . |
include:_spf.salesforce.com |
Must send through the primary domain, but can be restricted to send from a fixed sender address invoices@yourdomain.com using an SPF macro. |
include:mail.zendesk.com |
Must send through the primary domain, but can be restricted to send from a fixed sender address support@yourdomain.com using an SPF macro. |
include:_spf.app1.com |
Uses multiple addresses and is capable of sending through a subdomain for both the P1 sender and P2 sender, with a new SPF TXT record configured for app1.yourdomain.com . |
include:_spf.app2.com |
Uses multiple addresses, but since the email stream supports setting the P1 sender to a subdomain, a new SPF TXT record is created for app2.yourdomain.com , but emails can still be sent using the primary domain yourdomain.com as the P2 sender. |
mx |
Duplicate mechanisms, can be removed. When using Microsoft 365, the MX endpoint IP is already listed in include:spf.protection.outlook.com . |
If you look at the example above, we have 2 DNS lookups left after cutting the current SPF record for the primary domain:
Look up | Count |
---|---|
include:spf.protection.outlook.com |
1 DNS Lookup |
include:%{l}._spf.yourdomain.com |
1 DNS Lookup, using an SPF macro for both Salesforce and Zendesk (configuration of this SPF macro is covered later in this blog) |
IP address management in your SPF record
So we cleaned up 7 DNS lookups from the previous 9 DNS Lookups, good job! But what about the IP addresses in the SPF record? IP addresses don’t cost any DNS lookups because we’re not talking to the DNS. One disadvantage of using IP addresses in your SPF record is that it will result in an unmanageable and too long record. So, we can add a new include with the cost of 1 DNS lookup, such as include:_spf.yourdomain.com
.
- In the SPF record for
yourdomain.com
, add the following DNS lookup:
include:_spf.yourdomain.com
- Now we create a new
TXT
record in the DNS zone ofyourdomain.com
listing the IP addresses.
Host | Type | Value |
---|---|---|
_spf.yourdomain.com |
TXT |
v=spf1 ip4:11.222.33.444 ip4:44.33.222.111 ip4:22.33.444.555 ip4:55.66.777.8 ip4:88.99.999.99 ip4:99.88.777.66 -all |
CAUTION: When the SPF record for your IP addresses reaches its limit of two strings of 255 characters, it becomes inaccurate. You should avoid including too many IP addresses. While you can add another include, such as
_spf1.yourdomain.com
, at the cost of another DNS lookup, it is advisable to start segmenting this into subdomains. Also, get into the habit of documenting all of your IP addresses that send mail on behalf of your domain.
NOTE: There is also an SPF macro for IP addresses,
%{i}
, this macro replace the IP address of the SMTP client that submitted the message. However, using two separate SPF macros (because this blog already uses the macro%{l}
) is not advisable due to the limit of two allowed void lookups (NXDomain
). Even if you stay within the limit, there is still a risk of DNS timeouts due to slow DNS responses. Exceeding the limit will result in SPFpermerror
. Publishing an SPF policy that refers to data that does not exist in DNS is a poor practice and raises security concerns (see RFC7208 Section 4.6.4.).
Use an SPF macro to restrict a third-party service to send from a specific address
As described above, third-party services like Salesforce and Zendesk are mostly limited to sending from a single email address, such as invoices@yourdomain.com
and support@yourdomain.com
.
So it is unnecessary to have include:_spf.salesforce.com
and include:mail.zendesk.com
cost 3 DNS Lookups in the SPF record on yourdomain.com
.
Calculate the DNS Lookups from include:_spf.salesforce.com
in yourdomain.com
:
DNS Lookup | Count |
---|---|
include:_spf.salesforce.com |
1 DNS Lookup |
exists:%{i}._spf.mta.salesforce.com |
1 DNS Lookup (child lookup) |
Total: | 2 DNS Lookups |
Calculate the DNS Lookup from include:mail.zendesk.com
in yourdomain.com
:
DNS Lookup | Count |
---|---|
include:mail.zendesk.com |
1 DNS Lookup |
Total: | 1 DNS Lookup |
To reduce the 3 DNS Lookups to 1 DNS Lookup, we will use the SPF macro %{l}
, which replaces the local-part of the sender’s email address. Follow the two steps below to implement this.
- In the SPF record for
yourdomain.com
, add the following DNS lookup at a cost of 1 DNS Lookup:
include:%{l}._spf.yourdomain.com
CAUTION: Always place the
{l}
SPF macro at the end of your SPF record, as SPF evaluation processes this macro last during policy validation. Placing it elsewhere can lead to SPF permerrors, regardless of any subsequent includes in your SPF record.
- Now we will create two new
TXT
records in the DNS zone ofyourdomain.com
to restrict Salesforce to only send frominvoices@yourdomain.com
and Zendesk to only send fromsupport@yourdomain.com
.
Host | Type | Value |
---|---|---|
invoices._spf.yourdomain.com |
TXT |
v=spf1 include:_spf.salesforce.com -all |
support._spf.yourdomain.com |
TXT |
v=spf1 include:mail.zendesk.com -all |
After setting up the above, Salesfroce’s sending servers can only send from invoices@yourdomain.com
and Zendesk can only send from support@yourdomain.com
.
How the SPF macro %{l} works on the receiving mail server
To summarize what we have done
- The main SPF record is cleaned up by deleting 7 DNS lookups, this with segmenting your email streams with subdomains and using an SPF macro for fixed sender addresses.
- We deleted the
mx
DNS lookup because of a duplicate mechanism. - We have set all the IP addresses in a separate include.
Instead of 9 DNS lookups before cleaning, the cleaned SPF record has only 3 DNS lookups with SPF macros:
v=spf1 include:spf.protection.outlook.com include:_spf.yourdomain.com include:%{l}._spf.yourdomain.com -all
Final computation of DNS lookups:
DNS Lookup | Count |
---|---|
include:spf.protection.outlook.com |
1 DNS Lookup |
include:_spf.yourdomain.com |
1 DNS Lookup for the IP addresses |
include:%{l}._spf.yourdomain.comm |
1 DNS Lookup for Salesforce and Zendesk |
Total: | 3 DNS Lookups |
Lastly
For the future of your SPF record, add IP addresses using the separate include, and carefully decide whether a SaaS application should be sent through a subdomain or a fixed sender address instead of any address from your primary domain. In addition, make it a habit to monitor your SPF record frequently and document each sender you list.