Publish this TXT record at _dmarc.yourdomain.com once SPF and DKIM are in place:
v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com; fo=1
That is the mechanical answer. The reason it often does not help on a Microsoft 365 tenant is the prerequisite most people skip: by default Microsoft signs outbound mail with your tenant's onmicrosoft.com domain, and that signature does not align with the From address your recipients see. DMARC then has only SPF to work with, and a single forwarding hop takes you to dmarc=fail.
Prerequisites, in order
1. SPF for the tenant, in a single record at your apex:
v=spf1 include:spf.protection.outlook.com -all
One v=spf1 record per domain. Two is a specification violation that makes receivers return PermError and ignore SPF entirely. If other services also send as you, merge their mechanisms into this one record and respect SPF's limit of 10 DNS-querying mechanisms — include:spf.protection.outlook.com consumes several on its own.
2. DKIM for your custom domain, which means two CNAMEs and one switch:
| Type | Host | Points to |
|---|---|---|
| CNAME | selector1._domainkey.yourdomain.com | selector1-yourdomain-com._domainkey.<tenant>.onmicrosoft.com |
| CNAME | selector2._domainkey.yourdomain.com | selector2-yourdomain-com._domainkey.<tenant>.onmicrosoft.com |
Dots in your domain become dashes inside the target. Copy both values from the Microsoft Defender portal rather than constructing them. Then enable signing — in the Defender portal under the DKIM section of the email authentication settings, or:
Connect-ExchangeOnline New-DkimSigningConfig -DomainName yourdomain.com -Enabled $true -KeySize 2048 Get-DkimSigningConfig -Identity yourdomain.com | Format-List
Publish the CNAMEs first; enabling before they resolve is refused.
3. An inventory of every other sender. Microsoft 365 is rarely the only thing sending as your domain. The CRM, the helpdesk, the invoicing system, a marketing platform and a scanner on the office network are all candidates, and each needs its own aligned authentication.
The record, tag by tag
| Tag | Purpose | Values |
|---|---|---|
v | version, must be first | DMARC1 |
p | policy for the domain | none, quarantine, reject |
sp | policy for subdomains | the same three |
rua | aggregate report destination | full mailto: URI |
ruf | failure report destination | rarely sent by large receivers |
fo | when to generate failure reports | 1 reports when either check fails |
adkim | DKIM alignment | r relaxed (default), s strict |
aspf | SPF alignment | r relaxed (default), s strict |
ri | aggregate report interval in seconds | 86400 |
Relaxed alignment accepts any subdomain of the organisational domain; strict demands an exact match. The DMARC revision work that updates the original RFC 7489 specification retires pct and rf, replaces the Public Suffix List with a DNS tree walk for determining the organisational domain, and adds a policy tag for non-existent subdomains — so avoid building a long-term process around pct.
Verify before and after
dig +short TXT yourdomain.com | grep spf1 dig +short CNAME selector1._domainkey.yourdomain.com dig +short TXT selector1._domainkey.yourdomain.com dig +short TXT _dmarc.yourdomain.com
Then send to an external mailbox and read the raw headers:
DKIM-Signature: v=1; a=rsa-sha256; d=yourdomain.com; s=selector1; ... Authentication-Results: mx.google.com; spf=pass smtp.mailfrom=yourdomain.com; dkim=pass header.i=@yourdomain.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=yourdomain.com
d=yourdomain.com is what you are checking. If it still reads <tenant>.onmicrosoft.com, DKIM signing for your custom domain is not active, and raising the policy would be enforcing against a configuration you have not finished.
Troubleshooting
Incorrect syntax. v=DMARC1 must come first; tags are semicolon-separated; rua needs the mailto: scheme, because a bare address silently invalidates the tag. Only one DMARC record may exist at _dmarc — two makes the policy undefined and receivers may ignore both.
SPF and DKIM misalignment. spf=pass with dmarc=fail means the Return-Path domain does not align with header.from. Compare the two headers directly. On plain Microsoft 365 mail both usually align; the failures come from third-party platforms sending with their own bounce domains.
No reports arriving. If rua points at a mailbox on a different domain, that domain must publish v=DMARC1 at yourdomain.com._report._dmarc.<their-domain>. Without it, compliant receivers discard the report rather than send it.
Mail that bypasses Exchange Online. A device, line-of-business application or connector relaying directly to the internet is not signed by Microsoft. Route it through Microsoft 365, give it its own authenticated path, or expect it in your reports as a fail stream.
Forwarded mail failing. Expected: the forwarder is not in your SPF record. Aligned DKIM is what rescues these, which is the practical argument for getting DKIM right rather than relying on SPF.
Subdomains caught by the apex policy. Without sp=, subdomains inherit p=. Set it deliberately:
v=DMARC1; p=reject; sp=quarantine; rua=mailto:dmarc@yourdomain.com; fo=1
The rollout, and parked domains
A week at p=none reading reports, fixes for each sender, a week at p=quarantine, then p=reject. Strict alignment only after that, and only if every sender uses the exact domain.
While you are in DNS: every domain you own but do not send from should carry v=DMARC1; p=reject; sp=reject and v=spf1 -all. Parked and legacy domains are what spoofers reach for, and they cost nothing to lock down.
What not to do
- Do not publish DMARC before DKIM is aligned. You will be monitoring a configuration you already know is wrong.
- Do not rely on the default
onmicrosoft.comsignature. - Do not delete
selector2because nothing appears to use it; rotation needs both. - Do not point
ruaat a mailbox a person reads. The reports are constant and gzipped XML. - Do not jump to
p=reject. Quarantine is reversible and visible; rejection is neither.
MailPilot checks SPF, DKIM and DMARC for each connected mailbox's domain and warms Microsoft 365 and Outlook mailboxes over OAuth, measuring real per-provider inbox placement with a seed-inbox network so an unaligned signature surfaces as a failing check rather than as unexplained filtering.
Ready to reach the inbox every time?
Automated email warmup across real peer mailboxes. Live inbox placement monitoring. Free 7-day trial - no credit card required.
Start free trial