During a project with one of my customers, I was tasked to look at a non-delivery report (NDR) for a mail message. The bounce error was pretty confusing, but after reviewing the headers, we noticed that the DKIM check had failed. This was a bit of a surprise, because the message was sent from Microsoft Exchange Online. The root cause was that the selector mentioned in de header wasn’t resolving. Apparently, Microsoft did not provide the answer to validate the record.
The situation
The organization uses Microsoft Exchange Online and has setup DKIM signing with the accepted domains listed in the tenant. This particular organization owns 70+ domains. For every accepted domain, they have created the required CNAME records. During the validation, roughly 20 domains had a failed active selector entry.
I raised a case with Microsoft Office 365 Support, which confirmed that is was a bug and resolved the issue for my customer. They also informed the product team of this error.
How to setup DKIM
By default Exchange Online signs outgoing message with a DKIM signature. More information can be found here. The validation information recorded in the header points to one of the following records:
- selector1-[tenantname]-onmicrosoft-com._domainkey.[tenantname].onmicrosoft.com
- selector2-[tenantname]-onmicrosoft-com._domainkey.[tenantname].onmicrosoft.com
To enable DKIM you will also need to setup the following CNAME records in the domain:
- selector1._domainkey
- selector2._domainkey
Using Windows PowerShell, you can get the full value to use for these DNS records. You can retrieve the information through the Exchange Online PowerShell module. The recommended administrative permission is Security Admin.
Follow these steps:
- Connect to Exchange Online using the Exchange Online Powershell module.
- Sign in with your cloud administrator credentials.
- Give the following command for all existing domains:
Get-DkimSigningConfig | FL Identity,Selector1CNAME,Selector2CNAME
- Give the following command for one specific domain:
Get-DkimSigningConfig –identity [domainname]| Format-List Identity,Selector1CNAME,Selector2CNAME
- Register the new CNAME records with the Selector[1/2]Cname as value.
- After succesfully creating the DNS records, you can activate the DKIM signing configuration. This can be done via the following command:
Set-DkimSigningConfig –identity [domainname] –Enabled:$true
Note: If the domain is missing, you can create the DkimSigningConfig entry through this powershell command:
New-DkimSigningConfig -KeySize 2048 –DomainName [domainname] –Enabled:$false
Only one selector returns data
With the initial creation of your DKIM configuration, Microsoft populates both selectors in their DNS. After a while, though, only the active selector will be resolvable and the other selector is not. This is by Microsoft's design. The record should be visible again when the key rotates.
How to validate the existing records
The challenge for my customer was to validate the records for all 70+ domains. We can do this manually, but where it the fun in that!? We decided to do it through PowerShell.
The below Windows PowerShell script requires an active session to Exchange Online through PowerShell. The recommended administrative permissions is Security Admin.
We ran the following script:
$domains = Get-DkimSigningConfig |Where-Object {$_.Enabled -like "True"}
$Datenow = Get-date
$FailedLookupslog = "C:\Temp\FailedDKIMrecords.log"
$CheckDNS = @()
$failed = @()
ForEach($domain in $domains){
$activeSelector1 = $domain.SelectorBeforeRotateOnDate
$activeSelector2 = $domain.SelectorAfterRotateOnDate
If($($domain.RotateOnDate.ToUniversalTime()) -gt $($datenow.ToUniversalTime()) ){
$tempattribute = "$($activeSelector1)Cname"
$CheckDNS += $domain."$tempattribute"
}
else{
$tempattribute = "$($activeSelector2)Cname"
$CheckDNS += $domain."$tempattribute"
}
}
foreach($entry in $CheckDNS){
$works = Resolve-DnsName -Name $entry -Type txt -erroraction 'silentlycontinue'
If($works){}
else{
Write-host "$entry is not working" -ForegroundColor yellow
$Failed += $entry
}
$works = ""
}
"Domain: , selector:" | Out-File -FilePath $FailedLookupslog
Foreach($fail in $failed){
if($fail -like "selector1*"){
$temp = $domains | where{$_.selector1Cname -like $fail}
}
else{
$temp = $domains | where{$_.selector2Cname -like $fail}
}
"$($temp.Domain) , $fail" | Out-File -FilePath $FailedLookupslog -Append
}
The failed active selector entries were listed in the logfile.
Concluding
Organizations that enable the DKIM feature rely on Microsoft to maintain the information and keep it up-to-date. As a consumer of this feature you need to trust, but verify that it’s still works as designed.
By using the script in the blog, you can automate, verify and let it report to your ticketing system for review and follow-up actions.