When using Exchange Online, configuring the SPF record is a must. Failing to do so will most certainly cause you problems with messages sent to some recipients, as any message that you send from your email@example.com email will fail the SPF checks and can be marked as spam.
The value for the SPF record that Exchange Online recommends, which can be found under Domains -> View DNS Settings, is the following:
v=spf1 include:spf.protection.outlook.com -all
This is fine, IF you are only going to use Exchange Online to send messages. For most enterprises however, this is not the case. And here is where the trouble starts. First of all, the ‘-all’ clause instructs the SPF validator to reject all messages coming from sources not included in the SPF record as spam. So, if there is at least one non-Exchange Online source of emails for your domain, make sure to either include them in the SPF or change the clause to “~all” (which will result in the more acceptable SoftFail).
The inclusion of another mechanisms is the other issue. There is a limit of maximum 10 DNS lookups per SPF record, which is intended to prevent Denial of Service attacks. Anything above 10 should result in PermError, causing you trouble. The “INCLUDE”, “A”, “MX”, “PTR”, and “EXISTS” mechanisms as well as the “redirect” modifier do count against this limit. The “all”, “ip4”, and “ip6” mechanisms do not require DNS lookups and therefore do not count against this limit.
So how is this an issue? Surely the include:spf.protection.outlook.com counts for only one lookup? Not really, because once we look at the SPF records for that domain, we find the following:
v=spf1 include:spf-a.outlook.com include:spf-b.outlook.com include:spf-c.outlook.com include:spf.messaging.microsoft.com -all
So there are 4 more lookups there, and the spf.messaging.microsoft.com domain contains 3 more. Overall, the innocent looking SPF record already has exhausted 8 of the 10 allowed lookups. Now, before you start pointing fingers at Microsoft, there are reasons behind this. They need to include a large list of IP ranges to make sure all the relevant Exchange Online servers are present into that single SPF include. And that’s a large list indeed, while in the same time it’s a very good idea to keep the length of a single record under 255 bytes. Could they have done a better job with it? Probably yes, and they did improve on it recently (previously they were using the include:outlook.com one, which had 9 lookups!).
So, how to work around this? First of all, if you need 2 or less lookups, you will be able to add any relevant entries with no issues. Another option is to simply add an IP (range) instead of A or MX record, but that comes with the downside that you might have to change it if the corresponding IP is changed in the future.
In most cases 2 more lookups and adding few IP ranges should be good enough. But what if you need more still? You might consider ‘reworking’ the Exchange Online part by eliminating one or more lookups. For example, flatten the ‘third level’ entries (spfX.frontbridge.com). This will not cause you any trouble now, but in the long run you will have to constantly monitor any changes made on these records by Microsoft and adjust the SPF record accordingly. For example, if they decide to remove the SPF record for spfc.frontbridge.com, the “include” mechanism will now point to something non-existent, instantly invalidating the whole SPF record for your domain.
Forget about adding more than one SPF record, this will break things as well! What you can do instead is to create a subdomain and use it for Exchange Online mail. For example, you can have @domain.com for your local servers, and @cloud.domain.com for the Office 365 originating mail. Much like using two separate email providers.