Skip to content

Publish SPF and turn on DKIM signing for every domain that sends mail

Control
EX03
Area
Email authentication (SPF, DKIM, DMARC)
Priority
Highest
Effort
3 h
Last reviewed

Licence and role

Any Exchange Online plan. DNS changes at your registrar or DNS host.

Why it matters

Receiving servers, Microsoft 365 included, use SPF and DKIM to decide whether mail that claims to be from your domain is real. DMARC (EX04) needs at least one of them to pass and align. Microsoft recommends -all in the SPF record and DKIM signing with your own domain so the signing domain matches the From address.

Steps

  1. List every accepted domain and every service that sends as it (Microsoft 365, CRM, marketing, ticketing, scanners). Move bulk senders to a subdomain where you can.
  2. Publish one SPF TXT record per sending domain, for example v=spf1 include:spf.protection.outlook.com -all plus the other senders. Stay under 10 DNS lookups. Domains that never send mail get v=spf1 -all.
  3. For each custom domain: copy Selector1CNAME and Selector2CNAME from Get-DkimSigningConfig, publish both CNAME records (selector1._domainkey, selector2._domainkey), then turn on signing in the Defender portal (Email authentication settings > DKIM).
  4. Rotate 1024-bit keys to 2048 with Rotate-DkimSigningConfig -KeySize 2048 (takes effect after 96 hours; rotate a second time to move the other selector).

Impact on users

None for users if every sending service is listed. A service missing from SPF and not DKIM-signing will start failing once DMARC moves past p=none.

Rollback

DKIM: turn signing off for the domain (Microsoft then signs with the onmicrosoft domain). SPF: restore the previous TXT record (keep a copy before you change it).

Read-only check

Reads settings only. It changes nothing in your tenant or on the device.

Modules, connection and role
Requires: ExchangeOnlineManagement module (3.x). DNS checks use Resolve-DnsName (Windows PowerShell 5.1 or PowerShell 7 on Windows).
Connect first:
Connect-ExchangeOnline
Connect-IPPSSession   # only for the alert policy check (EX20)
Role: Global Reader, Security Reader or View-Only Organization Management is enough for these reads.
Get-DkimSigningConfig | ForEach-Object { "$($_.Name) | Enabled: $($_.Enabled) | Status: $($_.Status) | key bits: $($_.Selector1KeySize)/$($_.Selector2KeySize)" }
foreach ($d in (Get-AcceptedDomain).DomainName) { $t = (Resolve-DnsName -Type TXT -Name $d -ErrorAction SilentlyContinue | Where-Object { $_.Strings -match '^v=spf1' }).Strings -join ' '; "SPF $d : $(if ($t) { $t } else { 'NO SPF RECORD' })" }

How to verify

Every custom sending domain has exactly one SPF record ending in -all and DKIM Enabled True with Status Valid; a test message shows spf=pass and dkim=pass with header.d=<your domain> in Authentication-Results.

Sources

This control is in the Exchange Online Protection Kit

The free Top 5 has this control with its Jira import, Excel project plan, tracker CSV and the read-only PowerShell script. The Complete kit has all 20 controls.

Download the free Top 5 See the kit