What if you have an extensive list of email addresses? And if you must validate them for syntax and check if there’s an email server for that domain? PowerShell is your friend 🙂 In this blog post, I will show you how to import, validate, and export the results of those email addresses.
Why?
I created the script because somebody asked me if there was an easy way to check if a (huge) set of email addresses (Used to register accounts on a system that had no email validation of addresses being entered) were valid. The script should do these two things:
- Check the email address syntax: Was it formatted in the xyz@domain.xyz or wrongly formatted as “xyz.domain.xyz”, “xyz@domain.xyz,” or “fake@maildomain.com”?
- If the email address format was correct, is there an MX server behind that email domain in DNS?
- And is the MX server pingable? (Does it respond to ICMP requests / is it “alive”?)
Note: If the email address and the MX server DNS record are okay and present, and the MX server is pingable, emails sent to that email address could bounce because it doesn’t exist (anymore) on that mail server. But this script should clean up wrongly spelled email addresses.
How does the script work?
The script has three parameters when you run it:
- -DNSServer: Use this to specify a different DNS server than the one used on your client as default. For example, Check-EmailAdresses.ps1 -DNSServer 1.1.1.1 -Inputfile c:\scripts\Emailaddresses.xlsx -Outputfile c:\scripts\emailoutput.csv will check all email addresses inside the Emailaddresses.xlsx file and export the results to emailoutput.csv file using 1.1.1.1 as DNS server for validating MX records.
- -InputFile: Use this to specify the full path to the file containing all the email addresses. This can be either a CSV or XLSX file with an EmailAddresses header. For example, Check-EmailAdresses.ps1 -Inputfile c:\scripts\Emailaddresses.xlsx -Outputfile c:\scripts\emailoutput.csv will check all email addresses inside the Emailaddresses.xlsx file and export the results to emailoutput.csv file.
- -OutputFile: Use this to specify the full path to the file that will be used to report the scan’s results. This can be a CSV or XLSX file; if an XLSX file is specified, the ImportExcel module will automatically be installed if it is not already on your system. For example, Check-EmailAdresses.ps1 -Inputfile c:\scripts\Emailaddresses.csv -Outputfile c:\scripts\emailoutput.xlsx will check all email addresses inside the Emailaddresses.csv file and export the results to emailoutput.xlsx file.
Running the script
Before running the script, please check the input file. The file, with a CSV or XLSX extension, must be formatted like this:
EmailAddresses x@hotmail.com y@gmail.com z@live.com 12213@12123.1212312123asdasd.com 12123@12213.com 12123.adasd 12123.adasd
Below is a sample of the screen output and the report in the specified XLSX file:
Screen output: (You will see the progress of what is being checked and pinged if the MX server is present for the email domain)

XLSX output:

Note: This will take some time when checking large amounts of email addresses because of the DNS resolving and pinging the MX server if found. Validated domains are cached for results to speed things up as much as possible, but it will still take a lot of time. 1000 records in about 9 minutes during my tests.
Wrapping up
In this blog post, I showed you how to check multiple email addresses and create a results report. As mentioned above, this will help identify correctly formatted email addresses and determine if the MX server is reachable… It will not guarantee that emails will be delivered to that address, the mail server might be blacklisted, not respond to emails sent from your server, the mailbox might already be deleted, out of storage, etc. It does, however, help you filter out addresses to ensure you have the best chance of getting emails out to those reported in the OutputFile.
The script
Below are the script’s contents; download and save it to c:\scripts\Check-EmailAddresses.ps1, for example.
param (
[Parameter(Mandatory = $false)][ValidateNotNull()][string]$DNSServer,
[Parameter(Mandatory = $true)][ValidateNotNull()][string]$InputFile,
[Parameter(Mandatory = $true)][ValidateNotNull()][string]$OutputFile
)
#Test if CSV Input File is valid
if ($InputFile) {
If (Test-Path -Path $InputFile) {
Write-Host ("Specified input file {0} is valid, continuing..." -f $InputFile) -ForegroundColor Green
}
else {
Write-Warning ("Specified input file {0} is invalid, exiting..." -f $InputFile)
return
}
}
#Test if output file location is accessible
try {
if (($OutputFile.EndsWith('.csv')) -or ($OutputFile.EndsWith('.xlsx'))) {
New-Item -Path $OutputFile -Force -ErrorAction Stop | Out-Null
Write-Host ("Specified output file location {0} is valid, continuing..." -f $OutputFile) -ForegroundColor Green
Remove-Item -Path $OutputFile -Force -ErrorAction Stop | Out-Null
}
else {
Write-Warning ("Specified output file location {0} has wrong extension, exiting..." -f $OutputFile)
return
}
}
catch {
Write-Warning ("Specified output file location {0} is invalid or inaccessible, exiting..." -f $OutputFile)
return
}
#Import emailaddresses from CSV or XLSX
if ($InputFile.EndsWith('.csv')) {
try {
$EmailAddresses = Import-Csv -Path $InputFile -ErrorAction Stop
Write-Host ("Imported CSV file {0}" -f $InputFile) -ForegroundColor Green
}
catch {
Write-Warning ("Error importing CSV file {0}, check formatting. Exiting...")
return
}
}
if ($InputFile.EndsWith('.xlsx')) {
try {
try {
Import-Module 'ImportExcel' -ErrorAction Stop
}
catch {
Write-Warning ("Required ImportExcel module is not installed, installing now...")
try {
Install-Module -Name ImportExcel -SkipPublisherCheck:$true -Force:$true -ErrorAction Stop
Import-Module -Name ImportExcel
}
catch {
Write-Warning ("Error installing required ImportExcel module, check permissions. Exiting...")
return
}
}
}
finally {
$EmailAddresses = Import-Excel -Path $InputFile -ErrorAction Stop
Write-Host ("Imported Excel file {0}" -f $InputFile) -ForegroundColor Green
}
}
#Continue if emailadresses were imported, and validate if formatted correctly and domain name is valid
#Skip already tested Domains and use $DNSServer is specified, it not the script will use your default DNS server.
if ($null -ne $EmailAddresses) {
$Regex = '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
$ReachableEmailServers = @()
$UnreachableEmailServers = @()
$ProgressPreference = 'SilentlyContinue'
$total = foreach ($EmailAddress in $EmailAddresses | Select-Object emailaddresses -Unique | Sort-Object emailaddresses) {
if (($EmailAddress.emailaddresses -match $Regex) -eq $true) {
Write-Host ("{0} is formatted correctly, checking email server...." -f $EmailAddress.emailaddresses) -ForegroundColor Green
try {
if ($DNSServer) {
$mx = (Resolve-DnsName -Name $EmailAddress.Emailaddresses.Split('@')[1] -Type MX -Server $DNSServer -ErrorAction Stop).NameExchange | Select-Object -First 1
}
else {
$mx = (Resolve-DnsName -Name $EmailAddress.Emailaddresses.Split('@')[1] -Type MX -ErrorAction Stop).NameExchange | Select-Object -First 1
}
if ($null -ne $mx) {
if (($mx -split ',')[0] -in $ReachableEmailServers) {
CorrectlyFormatted = 'True'
EmailAddress = $EmailAddress.Emailaddresses
EmailServer = ($mx -split ',')[0]
PingReply = 'True'
Valid = 'True'
}
if (($mx -split ',')[0] -in $UnreachableEmailServers) {
CorrectlyFormatted = 'True'
EmailAddress = $EmailAddress.Emailaddresses
EmailServer = ($mx -split ',')[0]
PingReply = 'False'
Valid = 'True'
}
if (($mx -split ',')[0] -notin $ReachableEmailServers -and ($mx -split ',')[0] -notin $UnreachableEmailServers ) {
[PSCustomObject]@{
CorrectlyFormatted = 'True'
EmailAddress = $EmailAddress.Emailaddresses
EmailServer = ($mx -split ',')[0]
PingReply = if (Test-NetConnection $mx -InformationLevel Quiet) { "True" ; $ReachableEmailServers += $mx } else { "False" ; $UnreachableEmailServers += $mx }
Valid = 'True'
}
}
}
else {
[PSCustomObject]@{
CorrectlyFormatted = 'True'
EmailAddress = $EmailAddress.Emailaddresses
EmailServer = 'Not found'
PingReply = 'False'
Valid = 'False'
}
}
}
catch {
[PSCustomObject]@{
CorrectlyFormatted = 'True'
EmailAddress = $EmailAddress.Emailaddresses
EmailServer = 'Not found'
PingReply = 'False'
Valid = 'False'
}
}
}
else {
Write-Warning ("{0} is formatted incorrectly" -f $EmailAddress.emailaddresses)
[PSCustomObject]@{
CorrectlyFormatted = 'False'
EmailAddress = $EmailAddress.Emailaddresses
EmailServer = 'Not found'
PingReply = 'False'
Valid = 'False'
}
}
}
#output results to selected $output location
#CSV
if ($OutputFile.EndsWith('.csv')) {
try {
$total | Export-Csv -Delimiter ';' -Encoding UTF8 -NoTypeInformation -Path $OutputFile -Force
Write-Host ("Exported results to {0}" -f $OutputFile) -ForegroundColor Green
}
catch {
Write-Warning ("Error exporting results to {0}, check permissions/is file open? Exiting..." -f $OutputFile)
return
}
}
#Excel
if ($OutputFile.EndsWith('.xlsx')) {
try {
$total | Export-Excel -AutoSize -AutoFilter -Path $OutputFile -ErrorAction Stop
Write-Host ("Exported results to {0}" -f $OutputFile) -ForegroundColor Green
}
catch {
Write-Warning ("Error exporting results to {0}, check permissions/is file open? Exiting..." -f $OutputFile)
return
}
}
}
else {
Write-Warning ("No email adresses were imported, check input file {0}. Exiting..." -f $InputFile)
return
}
Download the script(s) from GitHub here.