Why Microsoft 365 mail fails at Gmail when the tenant looks healthy
Exchange Online will send your mail whether or not your domain is authenticated. That is the part that fools people. Messages leave the tenant, the Sent folder fills up, nothing in the admin center is red, and yet a customer on Gmail says your quote landed in spam, or a bounce comes back saying the message was not authenticated.
On a Microsoft 365 domain the cause is almost always the same three-part story: SPF got published when the domain was added, DKIM for the custom domain was never switched on, and DMARC was never published at all. Microsoft signs outbound mail with your tenant's onmicrosoft.com domain until you enable DKIM for the custom domain yourself. So a signature exists, it just carries the wrong domain, and it does nothing for the address your reader actually sees in the From header. You end up authenticated by SPF alone, which is the fragile half: SPF breaks on any forwarded message, and there is no DKIM signature on your own domain to fall back on.
The three records, in the order that avoids downtime
Publish SPF first, DKIM second, DMARC last. Each record proves something different, and DMARC is the only one that can start rejecting mail, so it goes in after the other two are confirmed working.
- SPF says which servers are allowed to hand your mail to the internet. It is checked against the envelope sender, the address in the SMTP MAIL FROM command, not the From header your reader sees.
- DKIM attaches a cryptographic signature to the message. The receiver fetches the public key from your DNS and confirms the message was signed by whoever controls that domain and was not altered in transit.
- DMARC ties either result back to the domain in the visible From header, and tells receivers what to do when neither one lines up. A message passes DMARC when SPF or DKIM passes and the domain it passed for aligns with the From domain. One of the two is enough, which is exactly why the missing one matters.
SPF: one include, and the lookup budget you spend after it
For a tenant that only sends through Exchange Online, Microsoft documents a single record:
example.com. TXT "v=spf1 include:spf.protection.outlook.com -all"
The -all at the end is a hard fail: anything not authorized should be rejected. Microsoft documents both that and the softer ~all. Start with ~all if you are genuinely unsure you have found every sender, then tighten to -all once your DMARC reports have shown you the full list. Never publish two SPF records for the same domain. If one already exists, merge the include into it.
That record is cheap. It stops being cheap the moment you add a CRM, an invoicing system, a marketing platform and a helpdesk, because RFC 7208 section 4.6.4 caps SPF evaluation at 10 DNS lookups and requires receivers to return permerror past that. Every include, a, mx, ptr, exists and redirect term costs a lookup, including the ones nested inside somebody else's include. ip4 and ip6 entries cost nothing, which is why hybrid setups list their on-premises outbound addresses directly instead of adding another include:
example.com. TXT "v=spf1 ip4:203.0.113.25 include:spf.protection.outlook.com -all"
Count the live record with a checker that follows nested includes, not by counting the entries you can see. We walked through the counting and the ways out of it in the SPF lookup limit guide.
DKIM: two CNAMEs, and why Microsoft asks for two
Microsoft 365 uses two selectors per custom domain, selector1 and selector2, so it can rotate signing keys without leaving a gap. You publish two CNAME records pointing at keys Microsoft holds for your tenant:
selector1._domainkey.example.com. CNAME selector1-example-com._domainkey.contoso.onmicrosoft.com.
selector2._domainkey.example.com. CNAME selector2-example-com._domainkey.contoso.onmicrosoft.com.
Read the exact values out of the portal instead of building them by hand. The pattern is predictable, but the tenant name inside the target has to be right or the lookup resolves to nothing. In the Microsoft Defender portal these sit under Email and collaboration, Policies and rules, Threat policies, DKIM. Microsoft rearranges that menu periodically, so search the portal for DKIM if it is not where you expect it.
Order matters here too. Publish both CNAMEs, wait for them to resolve, then enable signing for the domain. Enabling first fails, because Microsoft checks that it can read the keys before it will sign with them. Key length is worth a look on older tenants: 2048-bit is the current standard, and a configuration created years ago may still be running 1024. In Exchange Online PowerShell that lives on the signing configuration, for example New-DkimSigningConfig -DomainName example.com -KeySize 2048.
Once signing is on for the custom domain, outbound mail is signed with that domain instead of the onmicrosoft.com one. That single change is what turns DKIM from decoration into an identifier DMARC can actually use.
DMARC: publish at p=none, then read the reports
The record is a TXT entry on the _dmarc subdomain:
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
p=none changes nothing about delivery. It asks receivers to send you aggregate reports naming every IP address sending as your domain, and whether SPF and DKIM passed and aligned for each one. That list is the only honest inventory of your senders, and it is always longer than the one in your head: the accounting system, the scheduling tool someone signed up for, the scanner in the back office.
Leave it at p=none for about two weeks, fix each legitimate sender until it aligns, then move to p=quarantine and finally p=reject. Enforcement is the whole point, and Microsoft's guidance walks the same monitor, quarantine, reject path, but jumping straight to reject on a domain you have not inventoried is how invoices stop arriving. Worth knowing in the other direction as well: Exchange Online Protection evaluates DMARC on inbound mail and honors the policy the sending domain published, so your own enforcement also protects your staff from mail spoofing your domain. Microsoft publishes a separate guide for putting DMARC reporting on parked domains and on the tenant's onmicrosoft.com routing domain, both worth doing once the primary domain is settled.
The alignment traps specific to Microsoft 365
Four things break alignment on tenants that otherwise look configured:
- The onmicrosoft.com signature. The most common one by a wide margin. A DKIM pass reading
header.d=contoso.onmicrosoft.comwhen your From address is at example.com does not align, and DMARC ignores it entirely. - Subdomains. A DMARC policy covers subdomains through the parent unless you override it with
sp=. If a subdomain sends real mail from a different platform, give it its own SPF and DKIM rather than discovering it in a reject report. - Microsoft services that are not Exchange Online. Workflow automation and a CRM's own mail engine send on your behalf from infrastructure your Exchange include does not cover. They are separate senders and need their own authorization or their own DKIM signing, exactly like an outside vendor would.
- Relays and connectors. An appliance, a website form on shared hosting, or an on-premises server routing outbound mail through a connector all add an address to the chain. If it is not in SPF and the message is not DKIM-signed on your domain, it fails.
Verify on a real message, not on a checker
DNS checkers tell you that a record exists and parses. They cannot tell you what a receiver concluded about an actual message, which is the only thing that matters. Send a test from the tenant to a Gmail address, open Show original, and read the Authentication-Results header. You want three things at once: spf=pass with an smtp.mailfrom on your domain, dkim=pass with header.d= on your domain rather than onmicrosoft.com, and dmarc=pass. Two out of three is where most tenants sit before this work, and where a lot of them quietly stay.
What the bulk sender rules add on top
Past a certain volume the three records stop being good practice and become entry requirements. Google's sender guidelines treat a domain sending close to 5,000 messages or more in a day to personal Gmail accounts as a bulk sender, and bulk senders need SPF, DKIM and a DMARC record of at least p=none, a user-reported spam rate kept under 0.3 percent, and one-click unsubscribe as described in RFC 8058. Microsoft has published a comparable requirement for high-volume senders reaching Outlook.com, Hotmail.com and Live.com addresses: SPF, DKIM and a valid DMARC record, with non-compliant mail routed to Junk ahead of harder enforcement. Cross either threshold without the records in place and the failures get loud quickly, showing up as authentication and reputation rejections rather than a quiet trip to the spam folder.
How Guanacos Tech helps
Most of the Microsoft 365 tenants we look at are two records away from passing everywhere, and the missing two are almost always DKIM on the custom domain and DMARC. We inventory every sender out of your aggregate reports, get each one aligned, and walk the policy from none to reject on a schedule that does not put your invoices at risk. If you are moving to or from Google Workspace, we do the same work on both sides of the cutover. Start with the free email troubleshooter or the DMARC analyzer, or book a call and we will read your headers with you.
Sources
- Set up SPF to identify valid email sources for your Microsoft 365 domain - Microsoft Learn
- How to use DKIM for email in your custom domain - Microsoft Learn
- Set up DMARC to validate the From address domain - Microsoft Learn
- Enable DMARC reporting for MOERA and parked domains - Microsoft Learn
- External DNS records required for Microsoft 365 - Microsoft Learn
- Email sender guidelines - Gmail Help
- Outlook requirements for high-volume senders - Microsoft Q&A
- RFC 7208, Section 4.6.4 - DNS Lookup Limits
- RFC 8058 - One-Click Unsubscribe