Tuesday 4 May 2021

Reading Emails from O365 Mailbox with Powershell

Here is a script you can use to connect to an Office 365 (O365) mailbox to read/parse email messages. After the message has been read it is then moved to a specific folder within the mailbox. The full script is included first, and I will then break it down section by section afterwards

#Enable Exchange/O365 cmdlets
add-pssnapin *exchange* -erroraction SilentlyContinue
Import-Module MSOnline -ErrorAction SilentlyContinue

#Credentials
$email = email@domain.com
$password = "password"
$emaildomain = domain.com

#Connect to Mailbox
[void][Reflection.Assembly]::LoadFile("C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll")
$s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)
$s.Credentials = New-Object Net.NetworkCredential($email, $password, $emaildomain)
$s.Url = new-object Uri("https://outlook.office365.com/EWS/Exchange.asmx");
$inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($s,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)

#Setup folder and folder view (to move completed messages to)
$fv = new-object Microsoft.Exchange.WebServices.Data.FolderView(30)
$fv.Traversal = "Deep"
$folders = $s.findFolders([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$fv)
$processedfolder = $folders | where {$_.displayname -eq "ProcessedEmails"}

#Get unread messages
$msgs = $null
$iv = new-object Microsoft.Exchange.WebServices.Data.ItemView(50)
$inboxfilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And)
$ifisread = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::IsRead,$false)
$inboxfilter.add($ifisread)
$msgs = $s.FindItems($inbox.Id, $inboxfilter, $iv)

#If unread message(s) found, do stuff
if ($msgs.totalcount -ne 0)
    {
    $psPropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
    $psPropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text;
    $s.LoadPropertiesForItems($msgs,$psPropertySet)
    $msgs = $msgs.items
    }

#Move Message to Processed Folder
$msg.Move($processedfolder.Id)


The #Enable Exchange/O365 Cmdlets section as the comment suggests is to enable the Microsoft Exchange & Office 365 cmdlets

add-pssnapin *exchange* -erroraction SilentlyContinue
Import-Module MSOnline -ErrorAction SilentlyContinue

The #Credentials section is where you enter the details (username, password and email domain) used to connect to the mailbox

#Credentials
$email = email@domain.com
$password = "password"
$emaildomain = domain.com

Next, we will connect to the mailbox (and look at the Inbox folder specifically), using the credentials specified above and Microsoft Exchange Web Services. If you don't already have the Exchange Web Services files installed you will need to install them

#Connect to Mailbox
[void][Reflection.Assembly]::LoadFile("C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll")
$s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)
$s.Credentials = New-Object Net.NetworkCredential($email, $password, $emaildomain)
$s.Url = new-object Uri("https://outlook.office365.com/EWS/Exchange.asmx");
$inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($s,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)

Now, a folder view is setup to obtain the list of all the folders in the mailbox. All the list of available folders are stored in the $folders variable. We then look for a folder called "ProcessedTickets" and set this folder to be the $processedfolder variable. We use this variable (folder) later on to move processed emails into. You can of course change this folder name to be anything you like.

#Setup folder and folder view (to move completed messages to)
$fv = new-object Microsoft.Exchange.WebServices.Data.FolderView(30)
$fv.Traversal = "Deep"
$folders = $s.findFolders([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$fv)
$processedfolder = $folders | where {$_.displayname -eq "ProcessedEmails"}

Now we will retrieve any unread messages within the mailbox - filters are set using the $inboxfilter and $ifisread variables. All messages matching the search criteria are stored in the $msgs variable

#Get unread messages
$msgs = $null
$iv = new-object Microsoft.Exchange.WebServices.Data.ItemView(50)
$inboxfilter = new-object
Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And)
$ifisread = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::IsRead,$false)
$inboxfilter.add($ifisread)
$msgs = $s.FindItems($inbox.Id, $inboxfilter, $iv)

If messages are found in the $msgs variable, the properties for those messages are then loaded back into the $msgs variable

#If unread message(s) found, do stuff
if ($msgs.totalcount -ne 0)
    {
    $psPropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
    $psPropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text;
    $s.LoadPropertiesForItems($msgs,$psPropertySet)
    $msgs = $msgs.items
    }

If you look at the $msgs variable at this point, it should contain the properties of all mail messages found in the inbox that are unread. You can then use a foreach loop to cycle through each message and action accordingly.

Properties such as subject, body text, from address are all available and can be used to further filter entries

Once you've actioned the email and done what you need, you can then move the email into the processedfolders folder we previously specified

#Move Message to Processed Folder
$msg.Move($processedfolder.Id)


No comments:

Post a Comment