In this project, we set out to automate a tedious task: forwarding emails from Outlook. Using PowerShell and the Outlook COM API, we created a script that not only forwards emails but also ensures formatting and attachments are preserved — while avoiding common pitfalls like invalid recipients or redundant processing. This project came about when emails were sent to the wrong location and we were not able to use eDiscovery or similar tools to locate the emails due to how they were sent and what they were.
Project Goal
Automate the process of forwarding emails from a specific Outlook folder to the intended recipients. Requirements included:
- Preserving the original sender and full HTML formatting
- Maintaining all attachments
- Skipping or cleaning up invalid email addresses
- Avoiding throttling by pacing email sends
- Moving processed messages into an "AlreadySent" folder
Technical Approach
The project used PowerShell with the Microsoft.Office.Interop.Outlook
COM interface to programmatically access Outlook. Here's a high-level breakdown of what the script does:
- Connects to Outlook and selects a specified folder
- Iterates through each email in that folder
- Forwards the email using the built-in
Forward()
method - Resolves the
To
andCC
fields, filtering out any recipients without valid SMTP addresses - Preserves HTML formatting using
HTMLBody
- Sends the email with a 2-second delay between messages to avoid throttling
- Moves the original email to an "AlreadySent" folder
Handling Edge Cases
A few tricky aspects required special attention:
- Invalid recipients: Exchange addresses that couldn’t be resolved were skipped, and the email was still sent to valid ones
- Preserving HTML: We used
HTMLBody
instead ofBody
to retain formatting - Output control: Suppressed default PowerShell output to prevent verbose metadata (like raw message bodies) from being printed during script execution
Sample Snippet
# Helper function to resolve valid email addresses
function Get-ValidEmailAddress($recipient) {
try {
if ($recipient.AddressEntry.Type -eq "EX") {
return $recipient.AddressEntry.GetExchangeUser().PrimarySmtpAddress
} elseif ($recipient.AddressEntry.Type -eq "SMTP") {
return $recipient.Address
} else {
return $null
}
} catch {
Write-Host "Could not resolve address for recipient: $($recipient.AddressEntry.Name)" -ForegroundColor Yellow
return $null
}
}
Outcome
The final script runs smoothly, forwards messages as intended, and keeps the Outlook mailbox organized by archiving sent messages. It’s a great example of how scripting and automation can reduce repetitive work while handling real-world edge cases.
Most of the pitfalls we ran into were directly related to problems with mailboxes and how we wanted the original sender to be preserved. We opted for sending from a shared mailbox and letting users know that messages may be coming from an internal source they are not used to seeing. Below is the script if you need it!
Leave a Comment