DMARC Engine
Home/Blog/How to add DMARC, SPF and DKIM records on Azure DNS
Blog

How to add DMARC, SPF and DKIM records on Azure DNS

An Azure DNS-specific walkthrough of publishing TXT and CNAME records for DMARC, SPF and DKIM, covering record sets, the @ apex, TXT chunking, the CLI add-record trap, Alias records and why delegation must be set at the registrar.

22 June 2026 · 6 min read

How to add DMARC, SPF and DKIM records on Azure DNS

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 _dmarc produces _dmarc.example.com. Typing _dmarc.example.com produces _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:
DNS record
v=spf1 include:spf.protection.outlook.com -all

Or with the CLI:

DNS record
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:

DNS record
v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com
DNS record
az 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:

Example
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.microsoft

Microsoft 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:

Example
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

  1. Confirm the registrar uses this zone's four name servers, and that it is the public zone.
  2. Lower the TTL to 300 seconds on record sets you are about to change.
  3. Publish SPF at @, one value only.
  4. Publish each DKIM selector.
  5. Publish DMARC at _dmarc with p=none.
  6. Check the live result with the checkers, not the portal.
  7. Raise the TTL again once records are stable.
  8. Read your aggregate reports, then move to p=quarantine and p=reject. The current DMARC standard, RFC 9989, removed the old pct= tag; use t=y for 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.

Share

See where your domain stands today

Run a free DMARC scan, then let us take you to enforced p=reject with no email outage.