As you're aware there's a hard maximum of 10 lookups. A lookup is counted each time you see the word include
; so say your DNS TXT records were like this:
DNS Record |
Value |
example.com |
v=spf1 ip4:123.123.123.123 include:spf1.example.com include:spf2.example.com -all |
spf1.example.com |
v=spf1 include:mail.thidparty.com -all |
spf2.example.com |
v=spf1 include:mail.thidparty2.com include:mail.thidparty3.com -all |
mail.thidparty.com |
v=spf1 ip4:1.2.3.4/23 ip4:2.3.4.5/23 ~all |
mail.thidparty2.com |
v=spf1 ip4:2.2.3.4/23 ip4:3.3.4.5/23 ~all |
mail.thidparty3.com |
v=spf1 ip4:3.2.3.4/23 ip4:4.3.4.5/23 ~all |
In addition to your root domain you have 5 other DNS records referenced in your includes, so your SPF lookup count is 5 (the root isn't included in the count); so you could have up to 5 more.
You can get a good view of your SPF records (recursive) via this tool:
https://www.dmarcanalyzer.com/spf/checker/ (many others are also available).
Note: This count is the total recursive count; not just the number of lookups on any one record, or down any single branch; but across the entire tree/graph.
Flattening
There are some obvious things we can do to reduce the number of lookups; e.g. spf1.exmple.com
and spf2.example.com
aren't really adding any value; so we can just drop those records and update example.com
to refer directly to the thirdparty SPF records; thus removing 2 from our count.
DNS Record |
Value |
example.com |
v=spf1 ip4:123.123.123.123 include:mail.thidparty.com include:mail.thidparty2.com include:mail.thidparty3.com -all |
mail.thidparty.com |
v=spf1 ip4:1.2.3.4/23 ip4:2.3.4.5/23 ~all |
mail.thidparty2.com |
v=spf1 ip4:2.2.3.4/23 ip4:3.3.4.5/23 ~all |
mail.thidparty3.com |
v=spf1 ip4:3.2.3.4/23 ip4:4.3.4.5/23 ~all |
One thing to be careful of when doing this: consider why those were created in the first place, given they're just increasing complexity... Maybe they're referred to by other domains. E.g. My company owns many domains, some of which will all share the same service (e.g. we use Office/Exchange 365 for mail and ZenDesk for support; both configured to send emails from the countries' specific domains). Because we have this sharing, we have an SPF record in our primary domain which has the includes for those services which are shared by all these domains, so we can manage them all in one place / update all referencing domains via a single record.
To flatten things further you can fetch the third party's records and put their values into your records instead of having an include
to dynamically reference it. The issue here is that if the third party changes the value of this record, your implementation will break as you'll have the wrong values. You can mitigate that by either having scripts monitor the original record (and automatically correct your records with updates, or alert you of the issue when this is detected), or some companies implement their own management layer over DNS meaning you can define your lookups, and they'll flatten the DNS records for you. I've no experience with those so won't link to anyone; but a simple search for DNS Management Service SPF Flattening
should give you a few options.
Note: DNS TXT values also have a max length of 255 characters in a string. However, you can have multiple strings per record; so just create additional values (essentially you can have an array of <=255 character strings across which you can hold your value).
Alternative Options
Remove Services
Often multiple SPF records are needed because different teams within a company have purchased different solutions which fulfil the same requirement (e.g. SMTPaaS solutions). If you can consolidate providers you'll be able to remove some of these. That said, this often required buy in from more seniour management, who often don't appreciate the implications of this scenario.
Subdomain per Service
Though your example.com
domain can only have 10 lookups against it, you can have an entirely separate 10 lookups for support.example.com
or sales.example.com
, so you could partitionl your lookups by function (or even service; e.g. zendesk.example.com
to have:
DNS Record |
Value |
Notes |
example.com |
v=spf1 include:spf.protection.outlook.com -all |
Users' mailboxes |
support.example.com |
v=spf1 include:mail.zendesk.com ~all |
Support tickets |
sales.example.com |
v=spf1 include:spf.protection.outlook.com include:_spf.salesforce.com ~all |
Sales system notifications |
Then work with addresses specific to those subdomains (e.g. [email protected]
for your service desk). If those addresses need to be associated with a real mailbox you'd need to include your outlook.com
value on the relevant subdomain too (as shown in the Sales
example above), but it should be rare for you to need ALL lookups for any domain (e.g. SalesForce AND ZenDesk AND Outlook).
Note that you can also use email aliases to give the same mailbox multiple addresses, so even if you do have a mailbox that needs to be associated with multiple systems, maybe you can have different sender addresses for that mailbox, but still have replies to any of those addresses resolve to the same target mailbox.
Documentation
Not so much a solution to a current problem, but useful to help with future issues. Every time you add a service to your SPF record, record why those entries were added. Often people in the business request these without understanding the implications, then forget about them once all's working. Very often they'll be setup for a temporary requirement but no one will think to inform you when that requirement ceases to exist. By documenting things you can review your records periodically & find the people to contact to check whether the requirement still exists (or at least have some idea of where to look to see if ServiceX still has any relevancy), helping you to remove outdated services or know who to contact if you need to move a service off to its own sub domain / etc.