In this post, we will be making use of EWS to connect to an exchange server, impersonate a system maibox, download the emails and parsing the email body to extract the bounced email recipient.
References:
https://goodworkaround.com/2015/01/29/powershell-and-ews-managed-api/
https://msdn.microsoft.com/en-us/library/office/jj900168(v=exchg.150).aspx
https://www.linkedin.com/pulse/how-use-date-range-search-query-ews-managed-api-using-sunil-chauhan
What you need:
Microsoft Exchange Web Services API (download from nuget)
If you do not know which version of Exchange server your outlook profile is hosted on, refer to this article:
Example: in my email sending script (vbs sample here), I embed a header field
With Flds
' Set custom header so that the email can be easily read from bounce back addresses
.Item("urn:schemas:mailheader:x-CustomHdr") = strRecipientEmail
.Update
End With
Full source code:
# Load the EWS Managed API
Add-Type -Path "C:\Microsoft.Exchange.WebServices.2.2\lib\40\Microsoft.Exchange.WebServices.dll"
#---------------------------------------------------------------------------------
# Functions
#---------------------------------------------------------------------------------
function Clear-DeletedItems
{
param(
$exchangeService
)
$deletedItems = [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::DeletedItems
$deletedItemsFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($exchangeService,$deletedItems)
# 1000 items at a time
$itemView = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ItemView -ArgumentList 10
$dateTimeItem = [Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived
$timeLapse = (Get-Date).AddDays(-30)
$searchFilter = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThanOrEqualTo -ArgumentList $dateTimeItem,$timeLapse
$foundItems = $exchangeService.FindItems($deletedItemsFolder.Id, $searchFilter, $itemView)
Foreach($e in $foundItems){
write-host "deleting " $e.Subject
$e.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
}
}
function Parse-Emails
{
param($mailboxName,
$smtpServerName,
$username,
$domain,
$password,
$batchSize = 1000,
$clearDeletedItems = $false,
$emailFrom = "test@test.com",
$emailTo = "test@test.com"
)
try
{
$Exchange2007SP1 = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1
$Exchange2010 = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010
$Exchange2010SP1 = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1
$Exchange2010SP2 = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
$Exchange2013 = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013
$Exchange2013SP1 = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1
# create EWS Service object for the target mailbox name
$cred = New-Object System.Net.NetworkCredential($username, $password, $domain);
$exchangeService = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList $Exchange2010SP2
# Use this line if running as logged in user
# $exchangeService.UseDefaultCredentials = $true
$exchangeService.Credentials = $cred
$exchangeService.AutodiscoverUrl($mailboxName)
# Optional. remove deleted items > 30 days
if ($clearDeletedItems) {
Clear-DeletedItems -exchangeService $exchangeService
}
# bind to the Inbox folder of the target mailbox
$inboxFolderName = [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox
$inboxFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($exchangeService,$inboxFolderName)
# Optional: reduce the query overhead by viewing the inbox 1000 items at a time
$itemView = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ItemView -ArgumentList $batchSize
# search the mailbox for messages based on time
#$dateTimeItem = [Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived
#$timeLapse = (Get-Date).AddDays(-30) #(Get-Date).AddMinutes(-15)
#$searchFilter = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThanOrEqualTo -ArgumentList $dateTimeItem,$timeLapse
# search the mailbox for the subject containing "Undeliverable:"
#$subjectItem = [Microsoft.Exchange.WebServices.Data.ItemSchema]::Subject
#$filterString = "Undeliverable:"
#$searchFilter = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+ContainsSubstring -ArgumentList $subjectItem, $filterString
# with filter
#$foundItems = $exchangeService.FindItems($inboxFolder.Id, $searchFilter, $itemView)
# without filter
$foundItems = $exchangeService.FindItems($inboxFolder.Id, $itemView)
Foreach($e in $foundItems)
{
write-host $e.Subject -foregroundcolor Yellow
# First you have to load the mail item. Only entries are loaded at this point
$e.Load()
$body = $e.Body.Text
if ($body -like "*Delivery has failed to these recipients*") {
write-host "failed delivery detected" -ForegroundColor Cyan
# look for lines like this: x-CustomHdr: test@email.com
# x-CustomHdr is a custom header only found in FACTS
$regex = '\sx-CustomHdr:\s*([\w_.+-]+@[\w-]+\.[\w-.]+)\s'
$found = $body -match $regex
if ($found) {
$emailAddr = $matches[1]
write-host $emailAddr
# do something here
}
}
$e.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::MoveToDeletedItems)
# Or delete permanently
# $e.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
}
}
catch
{
$entryType = "Error"
$subject = "Error in mailbox monitor script"
$messageBody = "{0}`r`n{1}" -f $_.Exception.Message,$_.InvocationInfo.PositionMessage
Write-EventLog -LogName "Application" -Source "Application" -EventId 1 -Category 4 -EntryType $entryType -Message $messageBody
$smtpClient = New-Object -TypeName Net.Mail.SmtpClient -ArgumentList $smtpServerName
$smtpClient.Send($emailFrom, $emailTo, $subject, $messageBody)
}
}
$mailbox = "sender@test.com"
$smtpServerName = "smtp.testserver.com"
$username = "username"
$domain = "DOMAIN"
$password = ("password" | ConvertTo-SecureString -asPlainText -Force)
Parse-Emails -smtpServerName $smtp -mailboxName $mailbox -username $username -domain $domain -password $password -clearDeletedItems $true -batchSize 1000
No comments:
Post a Comment