In case you’re not familiar with what an SPF record is, it’s essentially a Text record attached to a domain that can confirm which sources are authorised to send emails on behalf of that domain. A correctly configured SPF record is an easy and effective way to prevent email forgeries coming from your domain, which makes your legitimate emails less likely to be flagged as spam. No SPF record, or an incorrectly defined SPF record, can mean genuine emails are more likely to get sent straight to spam or even rejected entirely.
The syntax is pretty straightforward, but recently we started seeing the following in the headers of emails sent by us (Via Office 365):
Received-SPF: PermError (protection.outlook.com: domain of firstname.lastname@example.org used an invalid SPF mechanism)
The cause is obvious – the SPF record being used is invalid, right? However, at a glance the record looked correct to me. To make matters more confusing, other email providers had no issue with it – Gmail reported an SPF Pass in its headers, while Exchange/Office 365 gave the above error. Office 365’s own readiness checker was also happy with the SPF record. What gives?
Googling around, it seems that not many people have encountered this specific problem. Plenty of people had genuinely invalid SPF records, but even the 3rd result on Google was a post on Serverfault from 2010 that garnered zero replies.
Eventually, I figured out the issue by sheer luck. Let’s play spot the difference:
“v=spf1 a:example.com -all”
“v=spf1 a:example.com ̵all”
The two SPF records above look nearly identical, right? Except the second one contains an invalid character. Rather than having a hyphen before the “all” part, it’s using a character that looks a bit like a hyphen. Somehow, almost every other provider out there didn’t seem to care, except anything Exchange – Exchange server, Exchange online and, of course, Office 365.
A quick change, then a wait around for DNS to propagate and we had a valid SPF record once more. I never determined where the mysterious character came from, but it’s almost certain that someone (possibly me) copied and pasted from a poorly coded “SPF Generator”, a PDF or other kind of document file that automatically inserted “fancy” formatting. I’m looking at you, Word.
All was well and good with the world until relatively recently when we encountered the same issue again – except this time, there were no odd characters. I typed out our SPF record manually, in notepad, to be extra sure. I triple-checked with every SPF tool I could find, everything was fine except exhange servers still rejected it. Sadly, the above error is of no help what so ever – it would be nice to have some indication of what was actually invalid, but never the less it was a guessing game.
As it turns out, the issue was to do with a subdomain listed within the record. Some time ago, we had added include:subdomain.domain.com to the record and all was well, but that subdomain was eventually made defunct. It turns out, if exchange finds an issue with any included domains, it treats the whole SPF record as invalid, even if your sending server is listed explicitly in the record.
There’s certainly a lesson there about keeping our own SPF records up to date, however it again would have been nice to have a more detailed message in the header file from Exchange.
Finally, another issue we’ve encountered that’s similar to the above is prefixing the “+” mechanism to each “include”. Some SPF tools (including the one built into cPanel) do this automatically. Again, every other email provider I could see didn’t seem to care but exchange did and it spat out the same, tired error above.
- Ensure any included domains contain valid SPF records themselves.
- Ensure there’s no spurious characters, like a dodgy hyphen or whitespace characters other than spaces.
- Don’t use the + mechanism as it’s implied already and exchange hates it.
I’m sure there’s other potential issues with SPF records that most mail providers ignore but exchange doesn’t. If you know of any, feel free to list them in the comments and hopefully this post will help someone in a similar situation.