Introduction to Sending Emails with PowerShell
PowerShell is an indispensable tool for task automation, configuration management, system monitoring and querying data. But you can also send email with PowerShell. For instance, PowerShell scripts can monitor systems and post email alerts for specific events, resource constraints or completed tasks. However, it’s critical to ensure that emails are sent in a secure manner. Let’s dive into why the old PowerShell Send-MailMessage cmdlet has been deprecated and explore how to send email from PowerShell using modern alternatives like Microsoft Graph API, MailKit and PnPOnline.
Why PowerShell Send-MailMessage Is Obsolete
The Send-MailMessage cmdlet in PowerShell was historically used to send emails. It provided a straightforward way for administrators to integrate email notifications into scripts. However, due to its inability to guarantee secure connections to SMTP servers and its lack of support for modern email authentication protocols like DKIM and SPF, it was officially marked as obsolete in PowerShell 7.0 and has since been deprecated by Microsoft. Instead, Microsoft suggests using the Send-MgUserMail cmdlet or secure tools such as Mailkit.
Here is a basic example of how administrators used to use PowerShell to send email to someone’s email address. Note that $PSEmailServer is a preference variable that sets the default SMTP server for the current PowerShell session.
$PSEmailServer = 'smtp.server.local'
Send-MailMessage -From 'sender@netwrix.com' -To 'recipient@netwrix.com' -Subject 'Test' -Body 'This is a test email'
Modern Methods for Sending Mail Messages in PowerShell
With the deprecation of the Send-MailMessage cmdlet, modern, secure options for sending emails in PowerShell have emerged to replace it, including Microsoft Graph API, MailKit and PnPOnline.
Using Microsoft Graph API for Email Management
One popular example is Microsoft Graph API, which uses the Send-MgUserMail cmdlet from the Microsoft Graph PowerShell SDK. Microsoft Graph API offers extensive functionality for email management, including sending messages via Office 365 accounts. Some of its features include:
- Enhanced security with modern authentication protocols
- Integration with Microsoft 365 services
- Support for advanced email features like rich text formatting, attachments and dynamic recipient lists
- Improved error handling and logging capabilities
Here is an example:
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Mail.Send"
# Prepare email parameters
$params = @{
Message = @{
Subject = "Test Email"
Body = @{
ContentType = "Text"
Content = "This is a test email sent using Microsoft Graph API."
}
ToRecipients = @(
@{
EmailAddress = @{
Address = "recipient@example.com"
}
}
)
}
SaveToSentItems = $true
}
# Send the email
Send-MgUserMail -UserId "sender@example.com" -BodyParameter $params
Using MailKit for Email Automation
Another secure alternative is MailKit, a cross-platform email library for .NET. Here are some of the benefits it offers:
- Support for modern encryption protocols and authentication methods
- Cross-platform compatibility across different operating systems
- Comprehensive support for MIME, IMAP, POP3 and SMTP protocols
- Regular updates to address security concerns and add new features
- Fine-grained control over email composition and sending
Below is an example:
# Install MailKit if not already installed
Install-Module -Name MailKit -Force
# Import the module
Import-Module MailKit
# Email configuration
$smtpServer = "smtp.example.com"
$smtpPort = 587
$senderEmail = "sender@example.com"
$senderName = "Sender Name"
$recipientEmail = "recipient@example.com"
$subject = "Test Email from MailKit"
$body = "This is a test email sent using MailKit in PowerShell."
# Create a new MimeMessage
$message = New-Object MimeKit.MimeMessage
$message.From.Add((New-Object MimeKit.MailboxAddress($senderName, $senderEmail)))
$message.To.Add((New-Object MimeKit.MailboxAddress($recipientEmail)))
$message.Subject = $subject
$message.Body = New-Object MimeKit.TextPart("plain") { Text = $body }
# Create SmtpClient object
$smtp = New-Object MailKit.Net.Smtp.SmtpClient
try {
# Connect to SMTP server
$smtp.Connect($smtpServer, $smtpPort, [MailKit.Security.SecureSocketOptions]::StartTls)
# Authenticate (if required)
$smtp.Authenticate($senderEmail, "YourPassword")
# Send the email
$smtp.Send($message)
Write-Host "Email sent successfully!"
}
catch {
Write-Host "An error occurred: $($_.Exception.Message)"
}
finally {
# Disconnect from SMTP server
$smtp.Disconnect($true)
$smtp.Dispose()
}
Using PnPOnline to Send Emails
PnPOnline is part of the PnP PowerShell library, making it a convenient tool for system administrators. It can be used to send emails within SharePoint and Microsoft 365 environments; emails are sent from the SharePoint Online “no-reply” address. However, it is limited to internal recipients within the same tenant.
This method offers the following benefits for single-tenant environments:
- Works natively within Microsoft 365 environments
- Minimal setup compared to external libraries because it leverages the administrator’s existing connection to Microsoft 365
- Can send emails to multiple recipients within the same tenant
- Utilizes SharePoint’s built-in email functionality
An example is shown below:
# Connect to SharePoint site
Connect-PnPOnline -Url "https://yourtenant.sharepoint.com/sites/yoursite" -Interactive
# Define email properties
$recipients = @("recipient1@yourtenant.com", "recipient2@yourtenant.com")
$subject = "New SharePoint Site Created"
$body = @"
Hello Tenant Owner
"@
# Send the email
Send-PnPMail -To $recipients -Subject $subject -Body $body
# Disconnect from SharePoint
Disconnect-PnPOnline
Detailed Examples of Sending Emails in PowerShell
Note that while you cannot use the Send-MailMessage cmdlet in combination with Exchange Online and other email providers, you can still use it to send SMTP emails to any servers that don’t require a secure connection. We’ll use it in the examples below.
Basic SMTP Email Example
To send an email using SMTP with credentials, use -Credential, as shown in this simple script:
# Define sender and recipient details
$From = "sender@netwrix.com"
$To = "recipient@netwrix.com"
$Subject = "Test Email"
$Body = "This is a test email sent using PowerShell."
# Define SMTP server details
$SMTPServer = "smtp.netwrix.com"
$Port = 587
# Specify credentials
$Password = ConvertTo-SecureString "YourPassword" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($From, $Password)
# Send the email
Send-MailMessage -From $From -To $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Port $Port -UseSsl -Credential $Credential
Sending Emails with Attachments
Now let’s expand that example and send an email with an attachment by using -Attachments:
# SMTP Server and Port
$smtpServer = "smtp.example.com"
$smtpPort = 587
# Email details
$from = "sender@netwrix.com"
$to = "recipient_email@netwrix.com"
$subject = "Subject: Email with Attachment"
$body = "This email contains an attachment."
# Path to the attachment
$attachment = "C:\path\to\your\file.txt"
# Authentication credentials
$username = "your_email@example.com"
$password = "your_password"
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($username, $securePassword)
# Send the email
Send-MailMessage -From $from -To $to -Subject $subject -Body $body `
-SmtpServer $smtpServer -Port $smtpPort -Credential $credential `
-UseSsl -Attachments $attachment
HTML-Formatted Emails in PowerShell
There are many instances when sending emails in plain text won’t suffice. HTML formatting allows for richer content presentation, as you can include different styles, images and links within the email body to enhance the email’s visual appeal and functionality. This can be useful for automated notifications, newsletters or alerts where formatting can significantly improve user engagement.
To send HTML-formatted emails, set -BodyAsHtml to $false as shown below:
# Install PnP PowerShell module if not already installed
# Install-Module -Name PnP.PowerShell
# Connect to the Microsoft 365 environment
Connect-PnPOnline -Url https://yourtenant-admin.sharepoint.com -UseWebLogin
# Define email parameters
$To = "recipient@netwrix.com"
$Subject = "PnPOnline Email Example"
$Body = "This is a test email sent using PnPOnline in Microsoft 365."
# Send the email
Send-PnPMail -To $To -Subject $Subject -Body $Body -BodyAsHtml $false
# Disconnect from the session
Disconnect-PnPOnline
Comprehensive Comparison of PowerShell Email Options
Feature | Send-MailMessage | Microsoft Graph API | MailKit |
Security | Limited security with no built-in modern authentication support | Supports modern authentication (OAuth2), secure token handling and multifactor authentication (MFA). | Supports TLS, SSL and OAuth2 (modern authentication) |
Ease of Use | Has straightforward parameters for sending emails, making it suitable for users with basic PowerShell knowledge | Slightly more complex because it requires setup of OAuth2 or Azure authentication | User-friendly but may have a learning curve for complex tasks like handling attachments |
Performance | Suitable for simple tasks, but less so for large-scale email operations or complex automation | High performance for large-scale applications; optimized for Microsoft 365 environments | High performance with support for complex email structures and large volumes |
Recommended Use Cases | Best for small scripts, basic email notifications and administrative tasks in PowerShell environments | Best for integrating deeply with Microsoft 365 applications, large-scale automation and SaaS applications | Best for .NET applications, complex email workflows and email processing |
Troubleshooting Common Errors
When you send emails via PowerShell, you are bound to run into issues. Here are some common errors you may encounter and how you can resolve them.
SMTP Server Errors
- Error: “Unable to connect to the remote server”
Solution: Verify the SMTP server address and port, and ensure connectivity. - Error: “The SMTP server requires a secure connection or the client was not authenticated”
Solution: Enable SSL/TLS encryption and provide correct credentials.
Credential Issues
- Error: “The SMTP server rejected the sender address”
Solution: Verify that the sender’s email address is correct and authorized to send emails. - Error: “Authentication failed”
Solution: Check the username and password and ensure the account has the necessary permissions.
Connection Timeouts
- Error: “Operation timed out”
Solution: Check network connectivity. Increase the timeout value in your script.
Best Practices
To help prevent issues, be sure to implement these security best practices:
- Keep PowerShell and related modules updated to benefit from the latest security patches.
- Always use the -UseSsl parameter with Send-MailMessage or its equivalent in other methods.
- Store credentials securely using Windows Credential Manager or modern encryption.
Testing and Debugging Email Scripts
There are some great resources available to help you debug email scripts. One example is Mailtrap, which provides a safe, isolated environment to debug scripts, analyze email content and optimize for deliverability. For instance, Mailtrap enables you to:
- Test emails without sending them to actual recipients.
- Review how emails will appear across different devices and email clients.
- Evaluate emails for spam triggers and improve deliverability.
- Identify and resolve errors or misconfigurations in email-sending scripts.
Essentially, Mailtrap is a virtual email inbox designed specifically for testing. Simply make a Mailtrap account and configure the SMTP settings. Then you can use a script like the one below:
# Mailtrap SMTP settings
$SMTPServer = "smtp.mailtrap.io"
$Port = 587
$Username = "your_mailtrap_username"
$Password = "your_mailtrap_password"
# Email details
$From = "sender@example.com"
$To = "recipient@example.com"
$Subject = "Test Email"
$Body = "This is a test email sent to Mailtrap."
# Securely create credentials
$Credential = New-Object System.Management.Automation.PSCredential($Username, (ConvertTo-SecureString $Password -AsPlainText -Force))
# Send email
try {
Send-MailMessage -From $From -To $To -Subject $Subject `
-Body $Body -SmtpServer $SMTPServer -Port $Port `
-UseSsl -Credential $Credential
Write-Host "Email sent successfully to Mailtrap."
} catch {
Write-Error "Failed to send email. Error: $_"
}
Conclusion
As you can see it is quite easy to make a PowerShell script to send email. However, you must ensure that you do so securely, since SMTP communication is a prime target for hackers and cybercriminals. Remember that the Send-MailMessage cmdlet has been deprecated by Microsoft, so make sure to use a modern tool like Microsoft Graph API, MailKit or PnPOnline to send email from PowerShell. These modern tools offer enhanced security features, better performance and improved compatibility with current email standards. By adopting these alternatives, you can ensure that your PowerShell email scripts are not only functional but also align with best practices in cybersecurity, adding value to your organization.