How Office 365 does SPF checks for customer-to-customer mail
There may be some confusion about how Office 365, or Exchange Online Protection (EOP), does SPF checks on incoming email - especially in the case when Customer A sends email to Customer B and both parties are EOP customers. This applies to the case when the sending email account is from a separate mail server, not from a fully hosted mailbox within EOP.
Setting up connectors
Customers who use EOP for sending outbound email typically do it by setting up an Inbound On-premise Connector (that is, to send outbound email through EOP, you need to set up an inbound on-premise connector). For example, suppose CustomerA.com uses the IP 188.8.131.52 to relay outbound email through EOP, they might set up a connector like the following:
You would enter in your connecting IPs and any associated sender domains. I personally recommend adding actual domains and not putting wildcards like *.com, or at least *.customerA.com, because leaving it as a wildcard makes it more susceptible to phishing attacks.
Mail routing and SPF checks in EOP
When customer A sends an email to customer B through the IP 184.108.40.206, the email is relayed out through EOP, relayed back in to EOP, and then routed to customer B (Customer B may be fully hosted, or have an on-premise mailer, it doesn’t matter which). So, the mail loops out and around, like below:
Customer A needs to publish the following TXT record:
customerA.com. 3600 IN TXT "v=spf1 include:spf.protection.outlook.com ip4:220.127.116.11 -all"
Customer A must add include:spf.protection.outlook.com because when the email goes out to the Internet (e.g., Gmail), or to another EOP customer, EOP or the 3rd party on the Internet (e.g., Gmail) looks to see if the connecting IP is in customerA.com’s SPF record. The connecting IP is EOP’s outbound IP.
Customer A also must add ip4:<on-premise IPs> into their SPF record because EOP does an SPF check at point (1) above when it scans the email when sending the message outbound. It then does a second SPF check at point (3) when the mail is relayed back into EOP.
Typically, the on-premise IPs in the SPF record are the same ones that you would put into an inbound on-premise connector.
If you do the above, everything will work properly with regards to SPF.
Attribution of outbound email and SPF checks
EOP’s SPF checking for customer-to-customer mail is more complicated than the above.
If you relay outbound email from 18.104.22.168 and the sending domain (e.g., customerA.com) matches the domains you have set up in the connector, this is called an outbound attributed message and the message is attributed to your organization. When sending email from Customer A to Customer B, then at point (3) EOP will use the IP in EOP’s SPF record:
However, if you relay outbound email from 22.214.171.124 and the sending domain (e.g., random.com) does not match any domains you have set up in the connector, this is called an outbound unattributed message and the message is attributed to a default organization – not your own. When sending email from Customer A to Customer B, then at point (3) EOP will use the original sending IP address and not the connecting IP:
This is a change that was introduced in December 2014. It is done to combat phishing and spoofing.
This is most noticeable in two places:
When you send email from a subdomain that is not in your list of sender domains.
For example, the inbound on-premise connector lists the domain customerA.com, but you send email from bounce.customerA.com, autoreply.customerA.com, and so forth. These will be unattributed messages and if sending to another EOP customer, the SPF check will use the original sending IP address. However, 3rd parties (e.g., Gmail) will use EOP’s relaying IP address.
When your on-premise mail servers sends bounces, auto-replies, or other messages with an empty 5321.MailFrom, <>.
An empty SMTP MAIL FROM will always be an unattributed message. See the next section to see how EOP handles this.
How EOP handles messages with an empty SMTP MAIL FROM <>
If a message has an empty mail from, then there is no domain upon which to perform an SPF check. EOP then falls back to the EHLO/HELO string and checks that instead. So, ff the message comes from an external 3rd party such as GoDaddy, EOP will use GoDaddy’s connecting IP address and the EHLO/HELO string used to in the SMTP transaction. Other 3rd party receivers do the same thing to EOP – if you send an email with <> to a 3rd party, the 3rd party uses EOP’s EHLO/HELO string in their SPF check (EOP has SPF records set up on all of its EHLO/HELO strings).
However, if the message with <> comes from another EOP customer, the message is unattributed. Therefore, EOP uses the original connecting IP address and falls back to the original connecting HELO/EHLO string, that is, your server’s HELO/EHLO string. Therefore, you should ensure that you have SPF records set up on your server’s HELO/EHLO string, too.
This behavior change is coming in Feb or March 2015.
To summarize everything, here’s what customers need to do:
If connecting email from an on-premise mail server (which you will if you have an on-premise environment or are a hybrid customer), every IP in an inbound on-premise connector should also be in the SPF record for each domain you send mail from. The SPF record must also have include:spf.protection.outlook.com.
The HELO/EHLO string of the on-premise mail server should also have an SPF record but only needs to include the IPs in the inbound on-premise connector. It is not necessary to have include:spf.protection.outlook.com. But to make things easier, you could simply copy/paste the SPF record from the domains you send mail from.
If you don’t do the above, there’s a good chance that you, or the senders you send to, will get false positives.
- Customize an SPF record to validate outbound email sent from your domain