22 June 2026 · 6 min read
Azure DNS stores SPF and DMARC as TXT record sets and most DKIM as CNAME record sets. Use relative names (@ for the root, _dmarc for DMARC, selector1._domainkey for DKIM), paste each TXT value as one string and let Azure split it into 255-character pieces, and keep exactly one SPF value at @. This guide covers the Azure portal and the az network dns CLI, and the Azure habits that make a record look saved but not work.
First, check Azure DNS is authoritative
Creating a zone in Azure DNS does not make the internet use it. Your zone's overview lists four assigned name servers, such as ns1-08.azure-dns.com., ns2-08.azure-dns.net., ns3-08.azure-dns.org. and ns4-08.azure-dns.info., and those exact four must be set at your registrar.
Two Azure-specific traps:
- Duplicate zones. Microsoft's zones and records overview explains that the same zone name can exist in different resource groups or subscriptions, and each copy gets different name servers. Only the copy your registrar points at is live, so check the resource group before editing.
- Private zones. An Azure Private DNS zone only answers inside your virtual networks. Email records must go in the public zone.
The DNS record checker shows what public DNS returns, which is what mail receivers see.
How Azure names records
- Names are relative. In the zone
example.com, the name_dmarcproduces_dmarc.example.com. Typing_dmarc.example.comproduces_dmarc.example.com.example.com, which nothing queries. @is the root of the zone, where SPF lives.- A record set is one name plus one type, holding one or more records that share a TTL. A TXT record set can hold several records; a CNAME record set can hold only one.
- TTL is set per record set, in seconds.
Long TXT values
DNS limits each TXT string to 255 characters, and a record can contain several strings that receivers join back together. Microsoft's documentation says that in the portal, PowerShell and the CLI you should give a single string per record, and Azure divides it into 255-character segments automatically. A TXT record set can hold up to 4,096 characters across all its records.
So paste a long DKIM key as one value. Do not split it yourself, and do not add it as several records: separate records in the same set are separate TXT records, which breaks a DKIM key and, for SPF, creates two v=spf1 records.
SPF: one TXT value at @
In the portal, open the zone and click + Record set:
- Name:
@ - Type:
TXT - Value: your SPF record, for example for Microsoft 365:
v=spf1 include:spf.protection.outlook.com -allOr with the CLI:
az network dns record-set txt add-record \
--resource-group my-rg --zone-name example.com \
--record-set-name "@" \
--value "v=spf1 include:spf.protection.outlook.com -all"add-record adds a record to the set. If an SPF value already exists at @, running it again creates a second SPF record and SPF fails with a permanent error for every sender. To change SPF, edit the existing value; with the CLI, remove the old record (remove-record) before adding the new one.
Other TXT values at @, such as domain verification tokens, can sit in the same record set; only one may start with v=spf1. SPF also fails after ten DNS lookups, and Azure does not check that for you. The SPF checker counts them, as described in RFC 7208.
DMARC: TXT at _dmarc
+ Record set with Name _dmarc, Type TXT, and a monitoring policy as the value:
v=DMARC1; p=none; rua=mailto:dmarc-reports@example.comaz network dns record-set txt add-record \
--resource-group my-rg --zone-name example.com \
--record-set-name "_dmarc" \
--value "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"Keep one DMARC record. Build it with the DMARC generator and confirm it with the DMARC checker.
DKIM: usually CNAME records
Most providers, including Microsoft 365, give you CNAME records. Microsoft 365 uses two selectors:
selector1._domainkey CNAME selector1-example-com._domainkey.example.n-v1.dkim.mail.microsoft
selector2._domainkey CNAME selector2-example-com._domainkey.example.n-v1.dkim.mail.microsoftMicrosoft changed this target format for custom domains added from May 2025; domains configured earlier keep a target ending in .onmicrosoft.com. Copy the exact values from the Defender portal. DMARC for Microsoft 365 covers the Microsoft side.
In the portal, create one record set per selector: Name selector1._domainkey, Type CNAME, and the target as the alias. Microsoft's DKIM guidance notes that Azure DNS does not need a trailing dot on CNAME targets and handles the formatting itself, so do not add one.
With the CLI, CNAMEs use set-record, because a CNAME record set holds only one target:
az network dns record-set cname set-record \
--resource-group my-rg --zone-name example.com \
--record-set-name "selector1._domainkey" \
--cname "selector1-example-com._domainkey.example.n-v1.dkim.mail.microsoft"Publish every selector your provider gives you. Check each one with the DKIM checker.
If a provider gives you a TXT public key instead, create a TXT record set at the selector name and paste the whole v=DKIM1; k=rsa; p=... value as one string. Azure splits it automatically.
Alias records are not for DKIM
Azure Alias record sets can only point at Azure resources, such as a public IP address, a Traffic Manager profile or another record set in the same zone. They cannot target an external hostname like a provider's DKIM host, so DKIM needs an ordinary CNAME record set. SPF and DMARC are TXT records and need neither. You also cannot create a CNAME at @, because the zone apex already holds the NS and SOA records.
Order of work
- Confirm the registrar uses this zone's four name servers, and that it is the public zone.
- Lower the TTL to 300 seconds on record sets you are about to change.
- Publish SPF at
@, one value only. - Publish each DKIM selector.
- Publish DMARC at
_dmarcwithp=none. - Check the live result with the checkers, not the portal.
- Raise the TTL again once records are stable.
- Read your aggregate reports, then move to
p=quarantineandp=reject. The current DMARC standard, RFC 9989, removed the oldpct=tag; uset=yfor a trial step.
p=none vs quarantine vs reject explains the policy stages, and the same records on Google's platform are covered in Google Cloud DNS: add DMARC, SPF and DKIM records. If you would rather not maintain these by hand, hosted DMARC publishes and stages the DMARC record for you.