Microsoft 365 DKIM: the onmicrosoft.com d= problem
Microsoft 365 does not DKIM-sign mail from a custom domain with that custom domain until custom DKIM is switched on for it. Historically the tenant signed with its initial *.onmicrosoft.com domain instead, which verifies as dkim=pass but never aligns with a vanity From address, so DMARC gets no aligned DKIM pass. The fix is two CNAME records, selector1._domainkey and selector2._domainkey, then enabling signing in Microsoft 365.
Send from a Microsoft 365 tenant with a vanity domain and no custom DKIM, and the receiver may well report dkim=pass. It looks fine. It is not. The signature was made by a domain that is not the one in your From header, and DMARC does not care whether a signature verifies — it cares whether the verified domain lines up with the one the recipient can see.
What does Microsoft 365 sign outbound mail with by default?
Every Microsoft 365 tenant gets an initial domain of the form contoso.onmicrosoft.com — the MOERA domain. Microsoft documents that mail from senders in that initial domain is DKIM-signed automatically, with no configuration from you. Custom domains are a separate matter, and they are the source of the confusion.
In December 2015, Microsoft announced that Exchange Online Protection had begun adding DKIM signatures to outbound mail even for customers who had never enabled DKIM. The archived post spells out what the signature looks like on a custom domain that was never configured: the selector encodes the custom domain, but the signing domain does not.
From: Second Example <second.example@fabrikam.com>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
s=selector1-fabrikam-com; d=contoso.onmicrosoft.com;
t=1429912795; h=From:To:Message-ID:Subject:MIME-Version:Content-Type;
bh=<body hash>; b=<signed field>;Read the two tags side by side. The From address is at fabrikam.com. The s= selector says selector1-fabrikam-com, which mentions fabrikam.com but is only a label. The d= tag — the Signing Domain Identifier, the thing that actually decides which DNS record holds the public key and which domain is asserting responsibility — says contoso.onmicrosoft.com. RFC 6376 defines d= as "the SDID claiming responsibility for an introduction of a message into the mail stream" and requires it to be a valid DNS name under which the key record is published. Nothing in RFC 6376 requires it to match the From header; the RFC says explicitly that it "does not require the value of the SDID or AUID to match an identifier in any other message header field".
Why does dkim=pass still fail DMARC?
Because DMARC checks a second thing after the signature verifies. RFC 7489 calls it Identifier Alignment: "When the domain in the RFC5322.From address matches a domain validated by SPF or DKIM (or both), it has Identifier Alignment." A message satisfies DMARC only if at least one supported mechanism produces a pass result and produces it "based on an identifier that is in alignment".
A signature with d=contoso.onmicrosoft.com verifies perfectly and aligns with nothing. contoso.com and contoso.onmicrosoft.com are different registered domains — onmicrosoft.com is the registrable domain in the second case, contoso.com in the first — so they do not share an Organizational Domain, and relaxed mode does not rescue them. Microsoft publishes exactly this row in its own alignment table.
| From address | MAIL FROM or DKIM d= domain | Relaxed (r, default) | Strict (s) |
|---|---|---|---|
| user@contoso.com | contoso.com | Pass | Pass |
| user@contoso.com | bounces.contoso.com | Pass | Fail |
| user@marketing.contoso.com | contoso.com | Pass | Fail |
| user@contoso.com | contoso.onmicrosoft.com | Fail | Fail |
| user@contoso.com | adatum.net | Fail | Fail |
The adkim and aspf tags control strictness, and both default to r. Under relaxed alignment RFC 7489 requires the Organizational Domains of the d= domain and the From domain to be equal; under strict, "only an exact match between both of the Fully Qualified Domain Names (FQDNs) is considered to produce Identifier Alignment". The two tags are independent, and because DMARC passes on either mechanism, a strict failure on one side is harmless if the other passes.
There is one wrinkle that makes this bug harder to notice. In that same 2015 post, Microsoft described a receiver-side heuristic: if a receiver sees d=*.onmicrosoft.com, strips the "selector1-" or "selector2-" prefix from the selector, and finds that the remainder matches the From domain with dots replaced by dashes, it "can consider the message implicitly DMARC aligned". That algorithm was published for verifiers to adopt; nobody is obliged to, and RFC 7489 contains no such rule. The post dates from December 2015 and is archived, so treat it as history rather than a promise — but it explains how a test message to one receiver can look healthy while the same message to a DMARC-enforcing third party does not.
Authentication-Results: spf=pass (sender IP is 198.51.100.10)
smtp.mailfrom=bounces.adatum.com; dkim=pass (signature was verified)
header.d=adatum.com; dmarc=fail action=oreject
header.from=contoso.com;compauth=fail reason=000Compare header.d= against header.from=. That single comparison is the whole diagnosis, and it is the same comparison whether the signing domain is a SaaS vendor's domain or your own tenant's onmicrosoft.com.
What are the two CNAME records, and why are there two?
Enabling custom DKIM in Microsoft 365 generates two public-private key pairs for the domain. You publish two CNAME records; Microsoft holds both private keys and will not show them to you. Microsoft's documented syntax, for domains onboarded under the record format introduced in May 2025:
Hostname: selector1._domainkey
Points to: selector1-<CustomDomainWithDashes>._domainkey.<InitialDomainPrefix>.<DynamicPartitionCharacter>-v1.dkim.mail.microsoft
Hostname: selector2._domainkey
Points to: selector2-<CustomDomainWithDashes>._domainkey.<InitialDomainPrefix>.<DynamicPartitionCharacter>-v1.dkim.mail.microsoft
Older tenants and existing custom domains use the previous form:
Hostname: selector1._domainkey
Points to: selector1-contoso-com._domainkey.contoso.onmicrosoft.comThe hostnames are identical for every Microsoft 365 organisation. The targets are not — they carry your initial domain prefix and, in the new format, a per-tenant partition character. Microsoft is emphatic that the values in its documentation are illustrative only and that the two formats cannot coexist for the same selector. Read yours out of the Defender portal, or out of PowerShell.
Get-DkimSigningConfig -Identity contoso.com | Format-List Name,Enabled,Status,Selector1CNAME,Selector1KeySize,Selector2CNAME,Selector2KeySize,KeyCreationTime,RotateOnDate,SelectorBeforeRotateOnDate,SelectorAfterRotateOnDateThe second selector exists for rotation, and the design falls out of the fact that the CNAMEs point into a zone Microsoft operates rather than yours. Because the key material itself lives on Microsoft's side of the CNAME, Microsoft can publish a fresh key without you touching DNS — but only into the record you have already delegated. One selector is active and signs; the other is dormant. Rotate-DkimSigningConfig "creates new DKIM keys and uses the alternate DKIM selector", so the sequence is:
- selector1 is active. Mail carries s=selector1-contoso-com. The key behind selector2 is published but unused.
- You rotate. Microsoft generates a new key pair and points the dormant selector at it.
- For four days (96 hours) the old private key keeps signing, so messages already in flight and caches already warm stay verifiable.
- At RotateOnDate the active selector flips. SelectorBeforeRotateOnDate and SelectorAfterRotateOnDate tell you which is which, and they are always different values.
Publishing only selector1 is the classic half-done configuration. Signing works, so nothing looks wrong — until the first rotation, which cannot proceed because there is no second record to move to. Microsoft lists a missing selector2 CNAME as a named failure mode for exactly this reason. Note also that key rotation is a per-custom-domain operation: Microsoft states there is currently no automatic DKIM key rotation for the *.onmicrosoft.com domain.
How do I verify Microsoft 365 DKIM with dig?
Query the selector name in your own domain, then follow the CNAME to the key. A TXT query does both in one go, because a resolver chasing selector1._domainkey.example.com will return the CNAME and then the TXT it points at. Here is a real, correctly configured domain — bmw.com, which you can check yourself:
$ dig +short CNAME selector1._domainkey.bmw.com
selector1-bmw-com._domainkey.bmwgroup.onmicrosoft.com.
$ dig +noall +answer TXT selector1._domainkey.bmw.com
selector1._domainkey.bmw.com. 3381 IN CNAME selector1-bmw-com._domainkey.bmwgroup.onmicrosoft.com.
selector1-bmw-com._domainkey.bmwgroup.onmicrosoft.com. 3381 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtRnYg62F...DriUmDT" "IKN15MYvNYe7xPQfmj...TOdVfHFBDQIDAQAB;"Three things to read out of that. The initial domain prefix is bmwgroup, not bmw — the tenant name and the mail domain need not match, which is why you cannot guess the CNAME target. The key record is a TXT with v=DKIM1, k=rsa and p= carrying base64 public key material, exactly the tags RFC 6376 defines; an empty p= means the key has been revoked. And the value comes back as two quoted strings, because RFC 1035 defines a DNS <character-string> as "a single length octet followed by that number of characters" — 255 bytes of text at most — and the base64 for a 2048-bit key does not fit in one. That is legal: RFC 1035 defines TXT RDATA as "one or more <character-string>s", and RFC 6376 says "Strings in a TXT RR MUST be concatenated together before use with no intervening whitespace," and it also warns that TXT RRs must be unique per selector — if an RRset has two, "the results are undefined".
If you want the key length rather than the key, decode it. Microsoft's New-DkimSigningConfig defaults to a 1024-bit key and accepts 2048; Rotate-DkimSigningConfig takes the same parameter but upgrades only the currently inactive selector, so a full move to 2048 takes two rotations.
$ dig +short TXT selector1._domainkey.bmw.com |
grep DKIM1 |
tr -d '"; ' |
sed 's/.*p=//' |
{ echo "-----BEGIN PUBLIC KEY-----"; fold -w64; echo "-----END PUBLIC KEY-----"; } |
openssl pkey -pubin -noout -text | head -1
Public-Key: (2048 bit)What "not configured" looks like
No CNAME at the selector means no key, which means nothing can be signed with your domain. What you are looking for is an answer count of zero and no ANSWER section. The status code alongside it varies, and both values are normal: most zones answer NXDOMAIN, because selector1._domainkey.yourdomain.com is simply a name that does not exist, while some authoritative servers answer NOERROR with nothing but an SOA in the authority section. The example below is one of the latter. Read the answer count, not the status.
$ dig +nocmd +noall +comments +answer CNAME selector1._domainkey.example.com
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48864
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1Why is an SPF-only DMARC pass weaker than SPF and DKIM both aligning?
Because SPF is a statement about the connecting IP and DKIM is a statement about the message. One of those survives being relayed and one does not. Microsoft puts it plainly: "SPF breaks after messages encounter server-based email forwarding that redirects or relays messages," because the forwarding server is not authorised to send for the original MAIL FROM domain. Whereas "the DKIM signature in the message header isn't affected or altered during email forwarding".
RFC 7960, which documents how DMARC interacts with indirect mail flows, sets out both halves of the problem. If the forwarder keeps the original envelope sender, "SPF validation will fail unless the forwarder is an authorized part of the originator's email sending infrastructure". If it rewrites the envelope sender to its own domain, "SPF might pass, but Identifier Alignment with the RFC5322.From header field will fail". Either way, the aligned SPF pass is gone.
| Event in transit | Aligned SPF | Aligned DKIM |
|---|---|---|
| Direct delivery from an IP in your SPF record | Passes | Passes, once custom DKIM is on |
| Server-based forwarding, message unmodified | Breaks — the forwarder IP is not in your SPF record | Survives — the signature travels in the header |
| Forwarder rewrites the envelope sender to its own domain | May pass for the forwarder, but no longer aligns with your From | Survives, still aligned |
| Mailing list prepends a subject tag or appends a body footer | Broken as above | Breaks — the signed header or body hash no longer verifies |
| Security gateway appends a disclaimer | Passes for the gateway, does not align | Breaks — body hash fails |
So DKIM is not universally more resilient — RFC 7960 is careful about this, noting that mailing lists "very commonly modify headers or message content in ways that will cause DKIM to fail". What is true is narrower and still decisive: for the plain forwarding case, where a recipient auto-forwards your mail to another address without altering it, aligned SPF breaks — barring the narrow case RFC 7960 carves out, where the forwarder is itself an authorised part of your sending infrastructure — and aligned DKIM is likely to hold. If DKIM is the only mechanism that can align on that hop and you have not enabled it, every forwarded copy fails DMARC. On a domain at p=reject, that is silent, permanent loss of legitimate mail to any recipient who forwards.
This is also why "SPF passes, we're fine" is a bad place to stop. It is a single-mechanism DMARC pass with a known failure mode, and the fix costs two DNS records.
Why does this matter more for outbound campaigns?
Volume concentrates the failure. Microsoft's DKIM documentation notes that the signature is omitted entirely when sender and recipient are in the same domain, or in domains controlled by the same organisation — so a misconfiguration can sit unnoticed for years behind internal mail. Point the same mailbox at a few hundred external strangers a week, some of whom forward internally, and the missing aligned signature starts showing up as unexplained non-delivery.
It also changes what a sending tool can honestly promise. Decknative sends through the customer's own Microsoft 365 mailbox over delegated Mail.Send rather than through a shared relay, which means the DKIM signature on the message is the one the tenant produces — so if custom DKIM is off, every message goes out unaligned no matter what the tool does. That is not a property of a particular product; it is true of any architecture that sends from your mailbox. Check the tenant before you check the tool.
Fix order, starting from nothing: SPF first because it is one DNS record, then DKIM on every custom domain and subdomain you send from, then DMARC at p=none while you read the aggregate reports, and only then quarantine and reject. Microsoft recommends that sequence, beginning with a low-volume subdomain and saving the parent domain for last. Each sending subdomain needs its own DKIM configuration — unlike DMARC, DKIM and SPF are not inherited.
Common questions
- Does Microsoft 365 set up DKIM for my custom domain automatically?
- No. Microsoft 365 configures DKIM automatically for the initial *.onmicrosoft.com domain only. For a custom domain you have to publish two CNAME records and then enable signing in the Defender portal or with Set-DkimSigningConfig. Until you do, no DKIM signature aligned with your custom domain is produced.
- Why does my mail show dkim=pass but dmarc=fail?
- Because DKIM verification and DMARC alignment are separate checks. A signature can verify perfectly while its d= domain differs from the domain in your From header, and DMARC requires an authenticated identifier that is in alignment. Compare header.d= against header.from= in the Authentication-Results header; if they are different registered domains, DKIM alignment fails.
- Can I publish TXT records instead of CNAMEs for Microsoft 365 DKIM?
- No. Microsoft 365 requires CNAME records at selector1._domainkey and selector2._domainkey; the TXT key record itself is published in a zone Microsoft controls, which is what lets Microsoft rotate keys without you editing DNS. Other DKIM implementations do use TXT records directly, which is a common source of confusion.
- Do I really need both selector1 and selector2?
- Yes. Only one selector is active and signing at any time; the other is dormant and exists so a key rotation has somewhere to go. Rotate-DkimSigningConfig creates new keys and switches to the alternate selector, so a domain with only selector1 published signs mail fine today but cannot be rotated later.
- How long after publishing the CNAMEs can I enable DKIM?
- Microsoft says it takes a few minutes or possibly longer for the new CNAME records to be detected, and detection is the main factor in when signing starts. If enabling fails, the error returns the expected values — check for typos in the dashes, dots and underscores before waiting again. Separately, a key rotation takes four days before the new private key starts signing.
- Will enabling DKIM fix DMARC failures on forwarded mail?
- Often, but not always. Forwarding breaks SPF alignment reliably, and an aligned DKIM signature survives a forward that leaves the message intact. It does not survive a mailing list that adds a subject tag or a body footer, or a gateway that appends a disclaimer, because those invalidate the signature. For those paths the answer is ARC at the intermediary, not DKIM.
- Should I use a 1024-bit or a 2048-bit DKIM key?
- New-DkimSigningConfig defaults to 1024 bits and accepts 2048. Rotate-DkimSigningConfig with -KeySize 2048 upgrades only the selector that is not currently active, so reaching 2048 on both selectors requires running the rotation twice. A 2048-bit key does not fit in a single 255-byte DNS character-string, which is why the published TXT record comes back as multiple quoted strings.
Sources
- Microsoft Learn — How to use DKIM for email in your custom domain
- Microsoft Learn — Set up DMARC to validate email in Microsoft 365
- Microsoft Learn — How email authentication works in Microsoft 365
- Microsoft Learn — Troubleshoot email authentication in Microsoft 365
- Microsoft Learn (archived, 2015) — Exchange Online is rolling out default DKIM-signing to everyone
- Microsoft Learn — Rotate-DkimSigningConfig (Exchange Online PowerShell)
- RFC 1035 — Domain Names: Implementation and Specification
- RFC 6376 — DomainKeys Identified Mail (DKIM) Signatures
- RFC 7489 — Domain-based Message Authentication, Reporting, and Conformance (DMARC)
- RFC 7960 — Interoperability Issues between DMARC and Indirect Email Flows