PowerShell Script for SPF, DKIM and DMARC validation
To protect your email domain against cybercriminals it’s important that you configure SPF, DKIM, DMARC, BIMI, and CAA DNS records on your email domain, it’s also recommended to enable DNSSEC and configure MTA-STS along with RPT-TLS. As a Cybersecurity Specialist, I’ve configured many of these DNS records for my customers. Before starting any configuration work, I first needed situational awareness of what was already in place. Since some customers had hundreds of domain names, checking each one individually for proper SPF, DKIM, and DMARC records wasn’t practical, so I built a PowerShell script to check them all at once. Over time, I’ve configured dozens of SPF, DKIM, DMARC, BIMI, and CAA records, along with MTA-STS and TLS-RPT, and enabled DNSSEC. Along the way, my Invoke-SpfDkimDmarc function grew into the DomainHealthChecker module, which now has over 100,000 downloads in 2026. I started the module in 2021 and I’m still actively maintaining it.
Getting Started
The DomainHealthChecker module offers cross-platform support with PowerShell Core. On Linux and macOS, where the Resolve-DnsName cmdlet isn’t available, dig is used instead. The module automatically detects which platform you’re running on and checks whether it’s supported. If it can’t determine the platform, it defaults to Windows. When it detects Linux or macOS as platform, it will also check if dig is available. Below a brief explanation of the protocols used by the PowerShell Module.
SPF (Sender Policy Framework)
The SPF is placed as a DNS entry in the public DNS of the domain. This protocol is an authentication protocol, which includes a list of IP addresses and hostnames of email servers that are allowed to send email messages on behalf of the email domain. To protect to domain from improper use, such as spoofing, etc.
DKIM (DomainKeys Identified Mail)
After an email message is sent by the sender, the receiving email server can verify that the sender is who it claims to be by checking the DKIM signature placed in the header of the email message and comparing it to the public DKIM key placed on the public DNS of the sender email domain.
DMARC (Domain-based Message Authentication, Reporting and Conformance)
The DMARC protocol is a policy protocol (sometimes it is also called a verification protocol). In my humble opinion, this protocol is the most important link in the chain to prevent abuse of an email domain. DMARC works closely with SPF and DKIM, it is very important to configure SPF and DKIM first.
A DMARC record is placed in the public DNS of an email domain. This protocol can define the policy on how strictly SPF and DKIM should be adhered to. For example, if an email message has an SPF(no-alignment), should the email message be allowed to pass or should it be blocked? And to which email address should notification be sent if someone tries to abuse your email domain. In most cases, an SPF HardFail occurs which allows the receiving email server to block the message and via the DMARC record (ruf-tag) to find out to which email address a report of possible abuse should be sent.
For more information about DMARC, I refer to https://dmarcian.com/why-dmarc/.
BIMI (Brand Indicators for Message Identification)
BIMI is an email standard that lets organizations display their verified logo next to their emails in supporting inboxes, like Gmail or Yahoo. It works by publishing a BIMI DNS record that points to your logo, typically hosted as an SVG file. To qualify, a domain must already have strong email authentication in place — specifically DMARC enforced at a quarantine or reject policy, built on top of SPF and DKIM. Some providers also require a Verified Mark Certificate (VMC), which is essentially a trademark-backed certificate proving you own the logo. When set up correctly, recipients see your brand’s logo as the sender avatar, which boosts recognition and trust. This also acts as a subtle anti-phishing signal, since attackers spoofing your domain won’t be able to display the same verified logo. BIMI doesn’t improve deliverability or security on its own — it’s a visual trust layer that sits on top of an already secure email setup. Adoption is growing but still inconsistent across email clients. For any organization serious about brand protection, BIMI is a natural next step once DMARC enforcement is stable.
CAA (Certification Authority Authorization)
CAA is a DNS record that specifies which certificate authorities (CAs) are allowed to issue SSL/TLS certificates for your domain. Without a CAA record, any public CA can issue a certificate for your domain, even without your knowledge or consent. By publishing a CAA record, you explicitly restrict certificate issuance to trusted CAs, such as Let’s Encrypt or DigiCert. This significantly reduces the risk of mis-issued or fraudulent certificates being used in phishing or man-in-the-middle attacks. CAA records can also specify an email address or URL to notify if an unauthorized issuance request is attempted. It’s a lightweight, low-effort control that adds a real layer of defense to your domain’s certificate lifecycle. Most major CAs check CAA records before issuing a certificate, in compliance with CA/Browser Forum rules. Setting one up takes just a few minutes but closes off an entire attack vector. For any domain handling sensitive data, CAA is a simple and effective safeguard worth implementing.
MTA-STS (Mail Transfer Agent Strict Transport Security)
MTA-STS is a standard that enforces encrypted, authenticated SMTP connections for incoming email to your domain. It works by publishing a policy file over HTTPS along with a DNS TXT record, telling other mail servers that your domain requires TLS when delivering mail. Without MTA-STS, an attacker performing a downgrade or man-in-the-middle attack can force email to be delivered unencrypted, or intercept it using a spoofed certificate. With MTA-STS enforced, sending servers will refuse to deliver mail if a secure, verified TLS connection can’t be established. This closes a long-standing gap in SMTP, which historically fell back to plaintext delivery if TLS wasn’t available. MTA-STS has three policy modes: none, testing, and enforce, allowing organizations to roll it out gradually. It’s especially valuable for domains handling sensitive communications, since it protects mail in transit rather than just at rest. Setting it up requires hosting a policy file and publishing the corresponding DNS record correctly.
TLS-RPT (TLS Reporting)
When MTA-STS combined with TLS-RPT (TLS Reporting), MTA-STS becomes even more powerful. TLS-RPT is a companion standard that lets other mail servers send you regular reports about TLS connection failures when delivering mail to your domain. On its own, MTA-STS enforces security but gives you no visibility into what’s happening — if legitimate mail servers are failing to connect, you’d have no way of knowing. TLS-RPT closes that blind spot by providing aggregated feedback on delivery issues, misconfigurations, or potential attacks. Together, MTA-STS and TLS-RPT give you both enforcement and monitoring: one protects the connection, the other tells you if something is going wrong. This combination is considered best practice, since deploying MTA-STS without TLS-RPT leaves you enforcing a policy blind.
DNSSEC (Domain Name System Security Extensions)
DNSSEC (Domain Name System Security Extensions) is a set of protocols that adds a layer of authentication to the DNS. Normal DNS was designed decades (1983) ago without security in mind. When your browser asks “what’s the IP address for binsec.nl?”, there’s no built-in way to verify that the answer actually came from the real domain owner and wasn’t tampered with along the way.
DNSSEC fixes this by adding digital signatures to DNS records. Each DNS zone gets a cryptographic key pair, and every response is signed. When a DNSSEC-aware resolver receives an answer, it can verify the signature against a chain of trust that runs all the way up to the DNS root — confirming the data is authentic and hasn’t been altered in transit.
How To: DomainHealthChecker
Let’s jump into the main topic of this article! I’ve written a PowerShell module that checks the SPF, DKIM, and DMARC records of a domain, or multiple domains at once. Beyond these core email authentication protocols, the module also covers BIMI, CAA, MTA-STS, TLS-RPT, and DNSSEC, giving a fuller picture of a domain’s overall security posture. It’s split into multiple functions, all of which come together in the DomainHealthChecker module.
Install module
Run the command below to install the DomainHealthChecker module directly from the PowerShell Gallery.
1
C:\> Install-Module DomainHealthChecker
Get-SPFRecord
The Get-SPFRecord cmdlet query for the SPF record which is associated with the specified domain. This function will also check if there are one or multiple SPF records. According to this protocol is not supporting multiple SPF records. Only on SPF record may exist per domain. Currently, this function isn’t checking how many DNS Lookups an SPF record holds. This feature will be added in the near future. (See also issue #16 on Github).
The Get-SPFRecord cmdlet queries the SPF record associated with the specified domain. It also checks whether one or multiple SPF records exist. Although only one SPF record is allowed per domain, you can configure a separate SPF record for each subdomain. This function also checks how many characters the SPF record contains. An individual string in a DNS TXT record is limited to 255 characters, but a single TXT record can hold longer total lengths (up to several thousand characters) by combining multiple strings together. It’s recommended to limit the TXT record length to a maximum of 255 characters. An important limitation of an SPF record to keep in mind is that it cannot contain more than 10 DNS lookups. This cmdlet also checks the maximum DNS lookups.
1
2
3
4
5
6
7
PS C:\> Get-SPFRecord -Name security.nl
Name : security.nl
SPFRecord : v=spf1 mx include:_spf.security.nl -all
SPFRecordLength : 39
SPFRecordDnsLookupCount : 3/10 (OK)
SPFAdvisory : An SPF-record is configured and the policy is sufficiently strict.
This function is supporting the following parameters:
-Name: This parameter is mandatory and is used to check the SPF record for a single domain or multiple domains in comma seperated format.-Server: This parameter is optional and can be used in a split DNS environment. The specified DNS server will be queried.-Path: This parameter is optional and can be used to retrieve a list of domains from a specified file.
Get-DKIMRecord
The Get-DKIMRecord cmdlet retrieves the DKIM record(s) for a specified domain or multiple domains. By default, this function checks the DKIM record against a preset list of 87 known, commonly used DKIM selectors, and attempts to detect multiple DKIM records across that list. With the -DkimSelector parameter, you can specify your own custom selector instead.
The preset list of known, commenly used DKIM selectors that the module use:
| Selector | Vendor |
|---|---|
a1 |
unknown / generic |
amazonses |
Amazon SES |
aweber_key_a |
AWeber |
aweber_key_b |
AWeber |
aweber_key_c |
AWeber |
barracuda |
Barracuda |
ces |
Cisco Email Security |
cm |
Campaign Monitor |
clab1 |
Contactlab |
ctct1 |
Constant Contact |
ctct2 |
Constant Contact |
default |
GoDaddy / secureserver.net |
dk |
unknown / generic |
dkim |
Hetzner |
dkim1024 |
Unknown / generic |
dkim1 |
Mailchimp / Mandrill / cPanel / Exim |
dkim2 |
Mailchimp / Mandrill |
e2ma-k1 |
Emma |
e2ma-k2 |
Emma |
e2ma-k3 |
Emma |
ecm1 |
Mapp Digital (former BlueHornet) |
email |
unknown / generic |
everlytickey1 |
Everlytic |
everlytickey2 |
Everlytic |
eversrv |
Everlytic OLD selector |
fm1 |
Fastmail |
fm2 |
Fastmail |
google |
Google Workspace |
hs1 |
HubSpot |
hs2 |
HubSpot |
k1 |
Mailchimp / Mandrill |
k2 |
Mailchimp / Mandrill |
k3 |
Mailchimp / Mandrill |
key1 |
unknown / generic |
key2 |
unknown / generic |
kl |
Klaviyo |
kl1 |
Klaviyo |
kl2 |
Klaviyo |
km1 |
Klaviyo |
km2 |
Klaviyo |
kt1 |
Klaviyo |
kt2 |
Klaviyo |
litesrv |
MailerLite |
m101 |
MailUp |
m102 |
MailUp |
mandrill |
Mailchimp / Mandrill |
mail |
unknown / generic |
mailgun |
Mailgun |
mailjet |
Mailjet |
mailin |
Sendinblue (legacy) |
mailpoet1 |
MailPoet |
mailpoet2 |
MailPoet |
mimecast |
Mimecast |
mte1 |
Mailchimp / Mandrill |
mte2 |
Mailchimp / Mandrill |
mxvault |
Global Micro |
nce2048 |
Netcore Cloud / Netcore Email |
opentext |
OpenText |
plesk |
Plesk |
pm |
Postmark |
pp |
Proofpoint |
protonmail |
ProtonMail |
protonmail2 |
ProtonMail |
protonmail3 |
ProtonMail |
sable |
SableMail |
s1 |
Sendgrid / NationBuilder |
s2 |
Sendgrid / NationBuilder |
selector1 |
Microsoft |
selector2 |
Microsoft |
sfdc |
Salesforce |
sib |
Sendinblue / Brevo |
sig1 |
iCloud |
sm |
Blackbaud, eTapestry |
sm1 |
Blackbaud, eTapestry |
sm2 |
Blackbaud, eTapestry |
smtp |
smtp.com |
smtpcustomer |
smtp.com |
smtpkey |
smtp.com |
sophos |
Sophos Email |
sparkpost |
SparkPost |
spop1024 |
IBM |
resend |
Resend |
yandex |
Yandex Mail |
zendesk1 |
Zendesk |
zendesk2 |
Zendesk |
zoho |
Zoho Mail / Campaigns |
zohomail |
Zoho Mail |
1
2
3
4
5
6
7
8
9
PS C:\> Get-DKIMRecord -Name bbc.com
Name : bbc.com
DkimSelectorsDetected : k1
DkimSelector-1 : k1
DkimRecord-1 : k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDbNrX2cY/GUKIFx2G/1I00ftdAj713WP9AQ1xir85i89sA2guU0t
a4UX1Xzm06XIU6iBP41VwmPwBGRNofhBVR+e6WHUoNyIR4Bn84LVcfZE20rmDeXQblIupNWBqLXM1Q+VieI/eZu/7k9/vOkLSaQ
Qdml4Cv8lb3PcnluMVIhQIDAQAB;
DkimAdvisory-1 : DKIM-record found for selector k1.
-Name: This parameter is mandatory and is used to check the DKIM record for a single domain or multiple domains in comma seperated format.-Server: This parameter is optional and can be used in a split DNS environment. The specified DNS server will be queried.-DkimSelector: This parameter can be used to retrieve the DKIM record for a specific selector.
Get-DMARCRecord
The Get-DMARCRecord cmdlet retrieves the DMARC record for the specified domain or multiple domains.
1
2
3
4
5
PS C:\> Get-DMARCRecord -Name binsec.nl
Name DmarcRecord DmarcAdvisory
---- ----------- -------------
binsec.nl v=DMARC1; p=reject; pct=100 Domain has a DMARC record and your DMARC policy will prevent abuse of your domain by phishers and spammers.
This cmdlet supports the following parameters:
-Name: This parameter is mandatory and is used to check the DMARC record for a single domain or multiple domains in comma seperated format.-Server: This parameter is optional and can be used in a split DNS environment. The specified DNS server will be queried.
Invoke-MtaSts
The Invoke-MtaSts cmdlet retrieves the MTA-STS record, and checks the configuration file.
1
2
3
4
5
PS C:\> Invoke-MtaSts -Name binsec.nl
Name mtaRecord mtaAdvisory
---- --------- -----------
binsec.nl v=STSv1; id=174448744429Z; The MTA-STS max age configured in the file should be greater than 604800 seconds and less than 31557600 seconds.
This cmdlet supports the following parameters:
-Name: This parameter is mandatory and is used to check the MTA-STS configuration for a single domain or multiple domains in comma seperated format.-Server: This parameter is optional and can be used in a split DNS environment. The specified DNS server will be queried.
Get-TlsRpt
The Get-TlsRpt cmdlet retrieves the TLS-RPT record, and checks whether the rua field is configured for reporting.
1
2
3
4
5
PS C:\> Get-TlsRpt -Name binsec.nl
Name TlsRptRecord TlsRptAdvisory
---- ------------ --------------
binsec.nl v=TLSRPTv1; rua=mailto:mailcheck-mta-sts@binsec.nl TLS-RPT Record found. The 'rua' field is configured.
This cmdlet supports the following parameters:
-Name: This parameter is mandatory and is used to check the MTA-STS configuration for a single domain or multiple domains in comma seperated format.-Server: This parameter is optional and can be used in a split DNS environment. The specified DNS server will be queried.
Get-BIMIRecord
The Get-BIMIRecord cmdlet checks whether BIMI is configured for the domain. By default, it checks the default selector. If BIMI is configured with a custom selector on the domain, you can use the -Selector parameter to check that specific selector.
1
2
3
4
5
PS C:\> Get-BIMIRecord -Name binsec.nl | fl *
Name : binsec.nl
BimiRecord : v=BIMI1;l=https://app.powerbimi.com/25028/71cc0f58-a4b0-4ddb-a927-2166ba431984.svg;
BimiAdvisory : DMARC policy is set to p=reject, which is the best policy for BIMI to function. No 'a=' (VMC) tag found, it's recommended to include a VMC certificate.
This cmdlet supports the following parameters:
-Name: This parameter is mandatory and is used to check the MTA-STS configuration for a single domain or multiple domains in comma seperated format.-Selector: This parameter is optional and can be used to check a specific selector rather than the default selector.-Server: This parameter is optional and can be used in a split DNS environment. The specified DNS server will be queried.
Get-CAARecord
The Get-CAARecord cmdlet checks whether the DNS CAA record is present and which CAs are authorized to issue an SSL certificate. The Resolve-DnsName in PowerShell does not natively support the CAA type. In the DomainHealthChecker module, we implemented a workaround and use DNS-over-HTTPS to check the CAA record via Cloudflare.
1
2
3
4
5
PS C:\> Get-CAARecord -Name binsec.nl | fl *
Name : binsec.nl
CAARecord : CAA record found, allowed CAs: comodoca.com, digicert.com, letsencrypt.org.
CAAAdvisory : CAA record found and IODEF not configured. Consider adding an IODEF contact to the CAA record to receive notifications.
This cmdlet supports the following parameters:
-Name: This parameter is mandatory and is used to check the MTA-STS configuration for a single domain or multiple domains in comma seperated format.
Invoke-SpfDkimDmarc
This is the main function of the module. Here, all the cmdlets mentioned above come together for the specified domain(s) in one go. You can, for example, use this function together with Export-Csv to organize the output and analyze it conveniently.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
PS C:\> Invoke-SpfDkimDmarc -Name binsec.nl
Name : binsec.nl
SpfRecord : v=spf1 -all
SpfAdvisory : An SPF-record is configured and the policy is sufficiently strict.
SPFRecordLength : 11
SPFRecordDnsLookupCount : 0/10 (OK)
DmarcRecord : v=DMARC1; p=reject; adkim=s; aspf=s; rua=mailto:rac3n92qqi@rua.powerdmarc.com; ruf=mailto:rac3n92qqi@ruf.powerdmarc.com; pct=100;
DmarcAdvisory : Domain has a DMARC record and your DMARC policy will prevent abuse of your domain by phishers and spammers.
DkimSelector : zohomail
DkimRecord : No DKIM-record found.
DkimAdvisory : We couldn't find a DKIM record associated with your domain.
MtaRecord : No MTA-STS DNS record found.
MtaAdvisory : The MTA-STS DNS record doesn't exist.
BimiRecord : v=BIMI1;l=https://app.powerbimi.com/25028/71cc0f58-a4b0-4ddb-a927-2166ba431984.svg
BimiAdvisory : DMARC policy is set to p=reject, which is the best policy for BIMI to function. No 'a=' (VMC) tag found, it's recommended to include a VMC certificate.
DnsSec : Domain is DNSSEC signed.
DnsSecAdvisory : Great! DNSSEC is enabled on your domain.
TlsRptRecord : No TLS-RPT Record found.
TlsRptAdvisory : No TLS-RPT Record found. Consider configuring a TLS-RPT record for this domain, to receive reports.
CaaRecord : CAA record found, allowed CAs: comodoca.com, digicert.com, letsencrypt.org
sl.com, comodoca.com, digicert.com; cansignhttpexchanges=yes, letsencrypt.org, pki.goog; cansignhttpexchanges=yes, ssl.com.
CaaAdvisory : CAA record found and IODEF not configured. Consider adding an IODEF contact to the CAA record to receive notifications.
This function is supporting the following parameters:
-Name: This parameter is mandatory and is used to check the SPF, DKIM, and DMARC records for a single domain.-DkimSelector: This parameter is optional and is used to retrieve the DKIM record with the corresponding selector.-Server: This parameter is optional and can be used in a split DNS environment. The specified DNS server will be queried.-Path: This parameter is optional and can be used to retrieve a list of domains from a specified file.-SkipUpdateCheck: TheDomainHealthCheckermodule automatic checks whether a new version is available on PowerShell Gallery. With this parameter you can skip this check.
Do you have any questions or additions regarding this module, please let me know!
