Powershell : Email Testing Script (for actual e-mail testing)

In the event you need to change your email provider, or more specifically you are looking to change your public MX record then you need to confirm that the new solution works well, and for this I would  highly recommend you buy of use a test domain so you can test these changes.

Then in this "test" domain you can make the MX record the same, test your internal and external routing updates then switch you "test" domain MX record to see how the non-live performs, each ease will be different, but for argument sake lets say we are moving from mail provider to another in the form of a "Secure Access Gateway" or SEG.

When you do to move your live MX records ensure you drop the TTL down low so that if you need to revert you can do so with relevant ease, however remember that even with a low TTL the Internet DNS replication is far for immediate and even with a low TTL it can take up to the 96 hours (though I have never seen it take this long)

When you have you new domain setup from the current mail provider you need to setup the mail servers to allow relay and delivery from the "test" domain then you need to get some testing of mail flow, now this mail flow will not be like your Production domain levels, but it will give you an indication of how this will perform.

I have chosen the following examples:

  1. Test email contains a single attachment
  2. Test email contains two attachments
  3. Test email contains 10-15 attachments
  4. Test email contains 30-35 attachments

Mail testing with Scripting

This will test the above scenarios with a Powershell script that you can run after specifying certain parameters in the script and this will automatically test those scenarios, you need to ensure you have created a Attachments folder which the script will use to randomly add to the e-mails:


Script : MailTesting.ps1

# Email Testing Configuration Variables
$smtpConfig = @{
    Server = "smtprelay.bear.local"
    Port = 25
    UseSSL = $true  # Toggle SSL on/off
}

# Target mailboxes for testing
$targetMailboxes = @(
    "mailbox1@croucher.cloud",
    "mailbox2@croucher.cloud"
)

# Sender configuration
$senderConfig = @{
    Email = "Mail.Tester@croucher.cloud"
}

# Test configuration
$testConfig = @{
    AttachmentsFolder = "C:\Quarantine\MailTestingScript\Attachments"
    DelayBetweenTests = 2  # 15 seconds between tests
    IterationsPerScenario = 4  # Will run each scenario 10 times
    LogFile = "EmailTest_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"  # Added log file config
}

# Function to write to both console and log file
function Write-OutputAndLog {
    param(
        [string]$Message,
        [string]$ForegroundColor = "White"
    )
    Write-Host $Message -ForegroundColor $ForegroundColor
    Add-Content -Path $testConfig.LogFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'): $Message"
}

# Updated original Write-ColorOutput to use new logging function
function Write-ColorOutput {
    param(
        [string]$Message,
        [string]$ForegroundColor = "White"
    )
    Write-OutputAndLog -Message $Message -ForegroundColor $ForegroundColor
}

# Updated countdown function with logging
function Show-Countdown {
    param(
        [int]$Seconds,
        [string]$Message
    )   
    $endTime = (Get-Date).AddSeconds($Seconds)
    Write-OutputAndLog -Message "$Message - Starting countdown for $Seconds seconds"   
    while ((Get-Date) -lt $endTime) {
        $timeLeft = ($endTime - (Get-Date)).ToString("mm\:ss")
        Write-Host "`r$Message - Time remaining: $timeLeft" -NoNewline
        Start-Sleep -Seconds 1
    }
    Write-OutputAndLog -Message "$Message - Complete!"
}

# Function to get random attachments
function Get-RandomAttachments {
    param(
        [string]$FolderPath,
        [int]$MinCount = 1,
        [int]$MaxCount = 35
    )
    $files = Get-ChildItem -Path $FolderPath -File
    if ($files.Count -eq 0) {
        Write-ColorOutput "No files found in attachments folder" -ForegroundColor Yellow
        return @()
    }
    $count = Get-Random -Minimum $MinCount -Maximum ($MaxCount + 1)
    $count = [Math]::Min($count, $files.Count)
    return $files | Get-Random -Count $count
}

# Updated Send-TestEmail with enhanced logging
function Send-TestEmail {
    param(
        [string]$RecipientEmail,
        [string]$Subject,
        [string]$Body,
        [System.IO.FileInfo[]]$Attachments
    )
    try {
        Write-OutputAndLog "Attempting to send email to $RecipientEmail with ${$Attachments.Count} attachments"
       $msg = New-Object System.Net.Mail.MailMessage
        $msg.From = $senderConfig.Email
        $msg.To.Add($RecipientEmail)
        $msg.Subject = $Subject
        $msg.Body = $Body
        foreach ($attachment in $Attachments) {
            $msg.Attachments.Add([System.Net.Mail.Attachment]::new($attachment.FullName))
            Write-OutputAndLog "Added attachment: $($attachment.Name)"
        }
        $smtp = New-Object System.Net.Mail.SmtpClient($smtpConfig.Server, $smtpConfig.Port)
        $smtp.EnableSsl = $smtpConfig.UseSSL       
        $smtp.Send($msg)
        Write-ColorOutput "Successfully sent email to $RecipientEmail" -ForegroundColor Green
        return $true
    }
    catch {
        Write-ColorOutput "Failed to send email to $RecipientEmail : $_" -ForegroundColor Red
        return $false
    }
    finally {
        if ($null -ne $msg) {
            $msg.Dispose()
        }
        if ($null -ne $smtp) {
            $smtp.Dispose()
        }
    }
}

# Main test execution function
function Start-EmailTestSuite {
    # Initialize log file
    $null = New-Item -Path $testConfig.LogFile -ItemType File -Force
    Write-OutputAndLog "Starting Email Test Suite - $(Get-Date)" -ForegroundColor Cyan   
    # Test scenarios
    $testScenarios = @(
        @{
            Name = "Single Attachment Test"
            Subject = "Test: Single Attachment"
            Body = "This email contains a single attachment."
            MinAttachments = 1
            MaxAttachments = 1
        },
        @{
            Name = "Double Attachment Test"
            Subject = "Test: Two Attachments"
            Body = "This email contains two attachments."
            MinAttachments = 2
            MaxAttachments = 2
        },
        @{
            Name = "Medium Attachment Count Test"
            Subject = "Test: 10-15 Attachments"
            Body = "This email contains 10-15 attachments."
            MinAttachments = 10
            MaxAttachments = 15
        },
        @{
            Name = "Large Attachment Count Test"
            Subject = "Test: 30-35 Attachments"
            Body = "This email contains 30-35 attachments."
            MinAttachments = 30
            MaxAttachments = 35
        }
    )

    # Calculate total tests
    $totalTests = $targetMailboxes.Count * $testScenarios.Count * $testConfig.IterationsPerScenario   

    # Initialize results
    $results = @{}
    $testCount = 0  

    # Start test suite
    Clear-Host
    Write-ColorOutput "Email Testing Suite" -ForegroundColor Cyan
    Write-ColorOutput "==================" -ForegroundColor Cyan
    Write-ColorOutput "SMTP Configuration:" -ForegroundColor Yellow
    Write-ColorOutput "Server: $($smtpConfig.Server)" -ForegroundColor White
    Write-ColorOutput "Port: $($smtpConfig.Port)" -ForegroundColor White
    Write-ColorOutput "SSL Enabled: $($smtpConfig.UseSSL)" -ForegroundColor White
    Write-ColorOutput "Target Mailboxes: $($targetMailboxes.Count)" -ForegroundColor White
    Write-ColorOutput "Iterations per scenario: $($testConfig.IterationsPerScenario)" -ForegroundColor White
    Write-ColorOutput "Total tests to run: $totalTests" -ForegroundColor White
    Write-ColorOutput "Delay Between Tests: $($testConfig.DelayBetweenTests) seconds" ForegroundColor White
    Write-ColorOutput "Log File: $($testConfig.LogFile)" -ForegroundColor White
    foreach ($inbox in $targetMailboxes) {
        $results[$inbox] = @()       
        foreach ($scenario in $testScenarios) {
            for ($i = 1; $i -le $testConfig.IterationsPerScenario; $i++) {
                $testCount++               
                Write-ColorOutput "Current Test ($testCount/$totalTests):" -ForegroundColor Green
                Write-ColorOutput "Scenario: $($scenario.Name) - Iteration $i of $($testConfig.IterationsPerScenario)" -ForegroundColor White
                Write-ColorOutput "Target: $inbox" -ForegroundColor White               
                $attachments = Get-RandomAttachments -FolderPath $testConfig.AttachmentsFolder `
                    -MinCount $scenario.MinAttachments `
                    -MaxCount $scenario.MaxAttachments               
                $success = Send-TestEmail `
                    -RecipientEmail $inbox `
                    -Subject "$($scenario.Subject) - Test $i" `
                    -Body "$($scenario.Body)Test iteration: $i of $($testConfig.IterationsPerScenario)" `
                    -Attachments $attachments               
                $results[$inbox] += @{
                    Scenario = $scenario.Name
                    Iteration = $i
                    Success = $success
                    AttachmentCount = $attachments.Count
                    Timestamp = Get-Date
                }                

                if ($testCount -lt $totalTests) {
                    Show-Countdown -Seconds $testConfig.DelayBetweenTests -Message "Waiting for next test"
                }
            }
        }
    }

    # Display final results
    Write-ColorOutput "Test Results Summary" -ForegroundColor Green
    Write-ColorOutput "==================" -ForegroundColor Green   
    foreach ($inbox in $targetMailboxes) {
        Write-ColorOutput "Inbox: $inbox" -ForegroundColor Cyan
        $inboxResults = $results[$inbox]       
        if ($null -eq $inboxResults -or $inboxResults.Count -eq 0) {
            Write-ColorOutput "No results recorded for this inbox" -ForegroundColor Yellow
            continue
        }
       $successfulTests = $inboxResults | Where-Object { $_.Success -eq $true }
        $successCount = if ($successfulTests) { $successfulTests.Count } else { 0 }       
        Write-ColorOutput "Tests passed: $successCount/$($inboxResults.Count)" -ForegroundColor White       
        if ($successCount -gt 0) {
            $totalAttachments = ($successfulTests | ForEach-Object { $_.AttachmentCount } | Measure-Object -Sum).Sum
            if ($null -ne $totalAttachments) {
                $avgAttachments = [math]::Round($totalAttachments / $successCount, 1)
                Write-ColorOutput "Average attachments per successful email: $avgAttachments" -ForegroundColor White
            }
        }
    }   
    Write-ColorOutput "Test suite completed. Log file saved to: $($testConfig.LogFile)" -ForegroundColor Green
}

# Run the test suite
Start-EmailTestSuite

When run it should look like this:


You should then see those e-mails in the destination inbox as this is the test:



You will also get an log file that logs all the testing complete as shown below:


Testing with External Sources

If you wish to test externally with this script then you will almost certainly need to use TLS with your SMTP connection and that is usually on TCP:587 but can also be on TCP:25 - in this example it is TCP:587 and you will need to support "Basic" authentication for the testing, so first you need to update the configuration with these settings as below:

# Email Testing Configuration Variables
$smtpConfig = @{
    Server = "<public_mail_service>"
    Port = 587
    UseSSL = $true  # Toggle SSL on/off
    Username = "<email_sender>"  # Add your username here
    Password = "<email_password>"  # Add your password here
}

# Convert password to secure string
$securePassword = ConvertTo-SecureString $smtpConfig.Password -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential($smtpConfig.Username, $securePassword)

Then you will need to update the Send-TestEmail function to include these credentials as below:

# Updated Send-TestEmail with authentication
function Send-TestEmail {
    param(
        [string]$RecipientEmail,
        [string]$Subject,
        [string]$Body,
        [System.IO.FileInfo[]]$Attachments
    )

    try {
        Write-OutputAndLog "Attempting to send email to $RecipientEmail with ${$Attachments.Count} attachments"
        
        $msg = New-Object System.Net.Mail.MailMessage
        $msg.From = $senderConfig.Email
        $msg.To.Add($RecipientEmail)
        $msg.Subject = $Subject
        $msg.Body = $Body

        foreach ($attachment in $Attachments) {
            $msg.Attachments.Add([System.Net.Mail.Attachment]::new($attachment.FullName))
            Write-OutputAndLog "Added attachment: $($attachment.Name)"
        }

        $smtp = New-Object System.Net.Mail.SmtpClient($smtpConfig.Server, $smtpConfig.Port)
        $smtp.EnableSsl = $smtpConfig.UseSSL
        $smtp.Credentials = $credentials  # Add credentials for authentication
        
        $smtp.Send($msg)
        Write-ColorOutput "Successfully sent email to $RecipientEmail" -ForegroundColor Green
        return $true
    }
    catch {
        Write-ColorOutput "Failed to send email to $RecipientEmail : $_" -ForegroundColor Red
        return $false
    }
    finally {
        if ($null -ne $msg) {
            $msg.Dispose()
        }
        if ($null -ne $smtp) {
            $smtp.Dispose()
        }
    }
}

Testing External mail sources

If you run in to trouble with using SSL over SMTP then you can use this script to diagnose where the issue is located, this will attempt to send a test email and then when you get an error you can diagnose from there.

Script : Test-SSLSMTP.ps1

# Email Testing Configuration Variables
$smtpConfig = @{
    Server = "<public_mail_service>"
    Port = 587
    UseSSL = $true  # Toggle SSL on/off
    Username = "<email_sender>"  # Add your username here
    Password = "<email_password>"  # Add your password here
}

# Convert password to secure string
$securePassword = ConvertTo-SecureString $smtpConfig.Password -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential($smtpConfig.Username, $securePassword)

Write-Host "Starting SMTP Connection Tests..." -ForegroundColor Cyan

# Test 1: Basic Network Connectivity
Write-Host "`nTest 1: Testing basic network connectivity..." -ForegroundColor Yellow
try {
    $testConnection = Test-NetConnection -ComputerName $smtpConfig.Server -Port $smtpConfig.Port -WarningAction SilentlyContinue
    Write-Host "TCP Test Succeeded: $($testConnection.TcpTestSucceeded)" -ForegroundColor Green
    Write-Host "Ping Succeeded: $($testConnection.PingSucceeded)" -ForegroundColor Green
} catch {
    Write-Host "Connection test failed: $_" -ForegroundColor Red
}

# Test 2: Simple Email Send
Write-Host "`nTest 2: Attempting to send a test email..." -ForegroundColor Yellow
try {
    $smtp = New-Object System.Net.Mail.SmtpClient($smtpConfig.Server, $smtpConfig.Port)
    $smtp.EnableSsl = $smtpConfig.UseSSL
    $smtp.Credentials = $credentials
    
    # Enable TLS 1.2
    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
    
    $msg = New-Object System.Net.Mail.MailMessage
    $msg.From = "Mail.Tester@croucher.cloud"
    $msg.To.Add("<Test.amilbox_address>")
    $msg.Subject = "SMTP Test"
    $msg.Body = "This is a test email."
    
    Write-Host "Sending test email..." -ForegroundColor Yellow
    $smtp.Send($msg)
    Write-Host "Test email sent successfully!" -ForegroundColor Green
} catch {
    Write-Host "Email send failed!" -ForegroundColor Red
    Write-Host "Error Message: $_" -ForegroundColor Red
    Write-Host "Error Type: $($_.Exception.GetType().FullName)" -ForegroundColor Red
    if ($_.Exception.InnerException) {
        Write-Host "Inner Exception: $($_.Exception.InnerException.Message)" -ForegroundColor Red
    }
} finally {
    if ($null -ne $msg) { $msg.Dispose() }
    if ($null -ne $smtp) { $smtp.Dispose() }
}

Write-Host "`nTests completed. Press any key to exit..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

In this example you can see that the domain used was not authorised to send emails so it failed:

Previous Post Next Post

نموذج الاتصال