Sending Email with PowerShell and the EWS Managed API

by Mike Pfeiffer on April 14, 2010

In this post we'll create a PowerShell advanced function used to send email messages. Instead of using the Send-MailMessage cmdlet or the classes in the System.Net.Mail namespace, we'll use the Exchange Web Services (EWS) Managed API. Using the API to send email is useful because you don't have to relay your messages via smtp – your messages are sent directly through Exchange, and can even be saved in your mailbox sent items folder. We'll also design this function to work with the existing EMS cmdlets so you can pipe in recipient objects and send messages.

The first thing you need to do is download the EWS Managed API. You can download the installer here. Take note of the following requirements before downloading the EWS Managed API:

  • Supported OS: Windows 7, Windows Server 2008, Windows Server 2008 R2, or Windows Vista
  • Requires Microsoft .NET Framework 3.5
  • We'll be using this function from within the Exchange Management Shell, so you'll want to grab the x64 version of the API.

Let's break down the function in a few steps to give you an idea of what is going on.

Creating the Function

We'll start off by creating the function and adding some parameters – we'll call the function Send-EWSMailMessage. We will need to provide parameters for the recipient email address, the subject and the body of the email.

Function Send-EWSMailMessage {
    [CmdletBinding()]
    param(
        [Parameter(Position=0, ValueFromPipelineByPropertyName=$true, Mandatory=$true)]
        [Object]
        $PrimarySmtpAddress,
        [Parameter(Position=1, Mandatory=$true)]
        [System.String]
        $Subject,
        [Parameter(Position=2, Mandatory=$true)]
        [System.String]
        $Body
        )

As you can see, we've defined three parameters; PrimarySmtpAddress, Subject and Body. The PrimarySmtpAddress will provide the address for our email recipient. It will also accept it's value from the pipeline by property name. This means we'll be able to pipe email recipients from the Get-Mailbox and Get-DistributionGroup cmdlets to the Send-EWSEmailMessage function.

The Begin Block

Here we'll import the EWS Managed API assembly and determine the identity of the user running the function. We'll use the email address of the calling user to find an Exchange server using autodiscover and provide the sender address for the message.

begin {
  Add-Type -Path "C:\bin\Microsoft.Exchange.WebServices.dll"
  $sid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
  $user = [ADSI]"LDAP://<SID=$sid>"
}

You can see in the code that the path to the assembly is under c:\bin. By default it is located in C:\Program Files\Microsoft\Exchange\Web Services\1.0. Make sure you update your path if needed.

The Process Block

In the process block, we'll handle each object as it comes across the pipeline. We'll create an EWS service object that will locate Exchange using autodiscover using the credentials and identity of the user running the function. Then we'll create a message and send it to the recipient.

process {
    $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService
    $service.AutodiscoverUrl($user.Properties.mail)

    if($PrimarySmtpAddress.GetType().fullname -eq "Microsoft.Exchange.Data.SmtpAddress") {
        $Recipient = $PrimarySmtpAddress.ToString()
    }
    else {
        $Recipient = $PrimarySmtpAddress
    }
    $mail = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage($service)
    $mail.Subject = $Subject
    $mail.Body = $Body
    [Void] $mail.ToRecipients.Add($Recipient)
    $mail.SendAndSaveCopy()
}

You can see here that we're checking the type of the $PrimarySmtpAddress obejct. This is because depending on how the function was run, it could be a simple string or an object piped from Get-Mailbox or Get-DistributionGroup – if it's piped in as an smtp object, we call the ToString method to get the smtp address. Also notice that we can the SendAndSaveCopy method to send the email, this will leave a copy of the message in the sent items folder in the senders Exchange mailbox.

You can download the finished version of the function here.

Testing it out

Now that we've got the code figured out, we can test the function. First, we'll send a simple message to one user:

$subject = "test"
$body = "this is a test email"
Send-EWSMailMessage administrator@contoso.com $subject $body

Email all users in a specific mailbox database:

Get-Mailbox -Database DB1 | Send-EWSMailMessage -subject $subject -body $body

Send an email to a distribution group:

Get-DistributionGroup Sales | Send-EWSMailMessage -subject $subject -body $body

There's a lot that can be done with the EWS Managed API – I'll be posting more about using it with PowerShell in the future.

Related Posts

{ 4 comments… read them below or add one }

Jeff Guillet April 16, 2010 at 6:38 am

Nice article, Mike! This is quite useful.

Reply

Mike Pfeiffer April 16, 2010 at 6:44 am

Thanks Jeff!

Reply

Oleg June 22, 2011 at 7:27 am

You are the best!

Reply

Mike Pfeiffer June 22, 2011 at 7:32 am

Thanks Oleg, glad it was useful :)

Reply

Leave a Comment

Previous post:

Next post: