One of the most basic things you might want to do with EWS is Send a Message, while its may sound easy sending messages programmatically can be at times confusing.
But first lets take one step back for a second from EWS and look at the different ways you could send Email programmatically on Exchange.
SMTP : (Simple Mail Transfer Protocol) SMTP is the backbone protocol for Email and is how most Email is transferred between servers on the Internet. Its also the protocol POP and IMAP clients use to send email. Because SMTP is a protocol (meaning its a set of rules defined in a RFC) rather then an API to use it you need to use a library that will give you some objects that you can code against that will then generated the necessary communication that follows the protocol rules. Some example of these are CDOSys, and System.NET.Mail. From an Exchange technical point of view when you submit a message via SMTP your submitting it directly into the Transport Pipeline so it doesn't going through Mailbox Store.
Pickup and Replay Directories : These are special directories on the Transport server that you can place Messages into https://technet.microsoft.com/en-us/library/bb124230(v=exchg.150).aspx typically used by specialized applications like foreign connectors https://technet.microsoft.com/en-us/library/aa996779(v=exchg.150).aspx
Mailbox API's : These are the specific API's that Microsoft has made available to access a Mailbox which are MAPI, EWS Managed API and for Office365 the new REST api. (ActiveSync could also be used but is a more specialized protocol) . When you send a Message via one of these Mailbox API's you first have to talk to the Mailbox role server (via the CAS ) and the message is submitted to Exchange Store which will then send it through into the transport pipeline. As part of that process you may choose to save a copy of the message your sending into the sentItems folder of the user who is sending the message. As you are sending via the Store you can also assert the SendOnBehalf rights if you send a message on behalf of a delegate.
EWS : To Send a Message using EWS you use the SendItem operation https://msdn.microsoft.com/en-us/library/office/aa580238(v=exchg.150).aspx you can also use the CreateItem Operation and set the SendDisposition to Send or SendAndSaveCopy. Depending on if your sending a message with Attachments you may need to make multiple requests to the server to create a draft message and then add attachments. In the EWS Managed API this complexity is implemented in the API so you don't have to worry about it. eg the following is a basic function for sending a message using EWS in PowerShell.
One other way of sending a Message in EWS is you can use the MIMEContent that maybe generated by another library or maybe a message that was exported or saved eg
Both of these functions come from the following github script https://github.com/gscales/Powershell-Scripts/blob/master/EWSSend.ps1
Sending Options : To Send a Message as another user (eg other then the current user being used to authenticate) you need to have been granted the SendAs permission on a Mailbox (which is a separate permission from the Mailbox rights granted via Add-MailboxPermission). The other option in EWS is that you can use EWS impersonation which would give the caller the same rights as the Mailbox owner, the script I've posted on GitHub has an option to use EWS Impersonation.
Both of these example functions save a copy of the message being sent into the SentItemFolder of the Mailbox passed into the Function. This is controlled via the
$EmailMessage.SendAndSaveCopy($SentItems.Id)
line if you didn't want to save a copy to the SentItem folder you can use the Send Method instead eg
$EmailMessage.Send()
This will set the necessary MessageDispostion value in the SOAP request.
EWS only allows you to send using one body format eg you need to choose between HTML or Text if you do want to use the more advanced body types allowed in MIME look to use the MIME Content option to send a message. There is also an example of sending an encrypted message using the MIME content https://blogs.msdn.microsoft.com/emeamsgdev/2015/08/10/ews-how-to-send-signed-email-using-the-ews-managed-api/
Using VBA or VB6 : If your still enjoying the retro Programing languages like VBA or VB6 its still possible to use EWS to send a message from your code by manually constructing the SOAP message involved. This maybe helpfully where your enviorment has been migrated to the cloud and your CDOsys code that was using SMTP to send messages no longer works. As a work around you can use a simple function like this to do a Send using EWS in Office365 (or change the URL to you OnPrem EWS endpoint).
But first lets take one step back for a second from EWS and look at the different ways you could send Email programmatically on Exchange.
SMTP : (Simple Mail Transfer Protocol) SMTP is the backbone protocol for Email and is how most Email is transferred between servers on the Internet. Its also the protocol POP and IMAP clients use to send email. Because SMTP is a protocol (meaning its a set of rules defined in a RFC) rather then an API to use it you need to use a library that will give you some objects that you can code against that will then generated the necessary communication that follows the protocol rules. Some example of these are CDOSys, and System.NET.Mail. From an Exchange technical point of view when you submit a message via SMTP your submitting it directly into the Transport Pipeline so it doesn't going through Mailbox Store.
Pickup and Replay Directories : These are special directories on the Transport server that you can place Messages into https://technet.microsoft.com/en-us/library/bb124230(v=exchg.150).aspx typically used by specialized applications like foreign connectors https://technet.microsoft.com/en-us/library/aa996779(v=exchg.150).aspx
Mailbox API's : These are the specific API's that Microsoft has made available to access a Mailbox which are MAPI, EWS Managed API and for Office365 the new REST api. (ActiveSync could also be used but is a more specialized protocol) . When you send a Message via one of these Mailbox API's you first have to talk to the Mailbox role server (via the CAS ) and the message is submitted to Exchange Store which will then send it through into the transport pipeline. As part of that process you may choose to save a copy of the message your sending into the sentItems folder of the user who is sending the message. As you are sending via the Store you can also assert the SendOnBehalf rights if you send a message on behalf of a delegate.
EWS : To Send a Message using EWS you use the SendItem operation https://msdn.microsoft.com/en-us/library/office/aa580238(v=exchg.150).aspx you can also use the CreateItem Operation and set the SendDisposition to Send or SendAndSaveCopy. Depending on if your sending a message with Attachments you may need to make multiple requests to the server to create a draft message and then add attachments. In the EWS Managed API this complexity is implemented in the API so you don't have to worry about it. eg the following is a basic function for sending a message using EWS in PowerShell.
function Send-EWSMessage { param( [Parameter(Position=0, Mandatory=$true)] [string]$MailboxName, [Parameter(Mandatory=$true)] [System.Management.Automation.PSCredential]$Credentials, [Parameter(Position=2, Mandatory=$false)] [switch]$useImpersonation, [Parameter(Position=3, Mandatory=$false)] [string]$url, [Parameter(Position=6, Mandatory=$true)] [String]$To, [Parameter(Position=7, Mandatory=$true)] [String]$Subject, [Parameter(Position=8, Mandatory=$true)] [String]$Body, [Parameter(Position=9, Mandatory=$false)] [String]$Attachment ) Begin { if($url){ $service = Connect-Exchange -MailboxName $MailboxName -Credentials $Credentials -url $url } else{ $service = Connect-Exchange -MailboxName $MailboxName -Credentials $Credentials } if($useImpersonation.IsPresent){ $service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName) } $folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::SentItems,$MailboxName) $SentItems = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid) $EmailMessage = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage -ArgumentList $service $EmailMessage.Subject = $Subject #Add Recipients $EmailMessage.ToRecipients.Add($To) $EmailMessage.Body = New-Object Microsoft.Exchange.WebServices.Data.MessageBody $EmailMessage.Body.BodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::HTML $EmailMessage.Body.Text = "Body" $EmailMessage.From = $MailboxName if($Attachment) { $EmailMessage.Attachments.AddFileAttachment($Attachment) } $EmailMessage.SendAndSaveCopy($SentItems.Id) } }
One other way of sending a Message in EWS is you can use the MIMEContent that maybe generated by another library or maybe a message that was exported or saved eg
function Send-MimeMessage { param( [Parameter(Position=0, Mandatory=$true)] [string]$MailboxName, [Parameter(Mandatory=$true)] [System.Management.Automation.PSCredential]$Credentials, [Parameter(Position=2, Mandatory=$false)] [switch]$useImpersonation, [Parameter(Position=3, Mandatory=$false)] [String]$MimeMessage ) Begin { if($url){ $service = Connect-Exchange -MailboxName $MailboxName -Credentials $Credentials -url $url } else{ $service = Connect-Exchange -MailboxName $MailboxName -Credentials $Credentials } if($useImpersonation.IsPresent){ $service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName) } $folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::SentItems,$MailboxName) $EmailMessage = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage -ArgumentList $service [byte[]]$bdBinaryData1 = [System.IO.File]::ReadAllBytes($MimeMessage) $EmailMessage.MimeContent = new-object Microsoft.Exchange.WebServices.Data.MimeContent("UTF-8", $bdBinaryData1) $EmailMessage.SendAndSaveCopy($SentItems.Id) } }
Both of these functions come from the following github script https://github.com/gscales/Powershell-Scripts/blob/master/EWSSend.ps1
Sending Options : To Send a Message as another user (eg other then the current user being used to authenticate) you need to have been granted the SendAs permission on a Mailbox (which is a separate permission from the Mailbox rights granted via Add-MailboxPermission). The other option in EWS is that you can use EWS impersonation which would give the caller the same rights as the Mailbox owner, the script I've posted on GitHub has an option to use EWS Impersonation.
Both of these example functions save a copy of the message being sent into the SentItemFolder of the Mailbox passed into the Function. This is controlled via the
$EmailMessage.SendAndSaveCopy($SentItems.Id)
line if you didn't want to save a copy to the SentItem folder you can use the Send Method instead eg
$EmailMessage.Send()
This will set the necessary MessageDispostion value in the SOAP request.
EWS only allows you to send using one body format eg you need to choose between HTML or Text if you do want to use the more advanced body types allowed in MIME look to use the MIME Content option to send a message. There is also an example of sending an encrypted message using the MIME content https://blogs.msdn.microsoft.com/emeamsgdev/2015/08/10/ews-how-to-send-signed-email-using-the-ews-managed-api/
Using VBA or VB6 : If your still enjoying the retro Programing languages like VBA or VB6 its still possible to use EWS to send a message from your code by manually constructing the SOAP message involved. This maybe helpfully where your enviorment has been migrated to the cloud and your CDOsys code that was using SMTP to send messages no longer works. As a work around you can use a simple function like this to do a Send using EWS in Office365 (or change the URL to you OnPrem EWS endpoint).
Sub SendMessage(Subject As String, Recipient As String, Body As String, User As String, Password As String) Dim sReq As String Dim xmlMethod As String Dim XMLreq As New MSXML2.XMLHTTP60 Dim EWSEndPoint As String EWSEndPoint = "https://outlook.office365.com/EWS/Exchange.asmx" sReq = "<?xml version=""1.0"" encoding=""UTF-8""?>" & vbCrLf sReq = sReq & "<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:t=""http://schemas.microsoft.com/exchange/services/2006/types"">" & vbCrLf sReq = sReq & "<soap:Header>" & vbCrLf sReq = sReq & "<t:RequestServerVersion Version=""Exchange2010""/>" & vbCrLf sReq = sReq & "</soap:Header>" & vbCrLf sReq = sReq & "<soap:Body>" & vbCrLf sReq = sReq & "<CreateItem MessageDisposition=""SendAndSaveCopy"" xmlns=""http://schemas.microsoft.com/exchange/services/2006/messages"">" & vbCrLf sReq = sReq & "<SavedItemFolderId>" & vbCrLf sReq = sReq & "<t:DistinguishedFolderId Id=""sentitems"" />" & vbCrLf sReq = sReq & "</SavedItemFolderId>" & vbCrLf sReq = sReq & "<Items>" & vbCrLf sReq = sReq & "<t:Message>" & vbCrLf sReq = sReq & "<t:ItemClass>IPM.Note</t:ItemClass>" & vbCrLf sReq = sReq & "<t:Subject>" & Subject & "</t:Subject>" & vbCrLf sReq = sReq & "<t:Body BodyType=""Text"">" & Body & "</t:Body>" & vbCrLf sReq = sReq & "<t:ToRecipients>" & vbCrLf sReq = sReq & " <t:Mailbox>" & vbCrLf sReq = sReq & " <t:EmailAddress>" & Recipient & "</t:EmailAddress>" & vbCrLf sReq = sReq & " </t:Mailbox>" & vbCrLf sReq = sReq & "</t:ToRecipients>" & vbCrLf sReq = sReq & "</t:Message>" & vbCrLf sReq = sReq & "</Items>" & vbCrLf sReq = sReq & "</CreateItem>" & vbCrLf sReq = sReq & "</soap:Body>" & vbCrLf sReq = sReq & "</soap:Envelope>" & vbCrLf xmlMethod = "POST" XMLreq.Open xmlMethod, EWSEndPoint, False, User, Password XMLreq.setRequestHeader "Content-Type", "text/xml; charset=""UTF-8""" XMLreq.setRequestHeader "Translate", "F" XMLreq.setRequestHeader "User-Agent", "VBAEWSSender" XMLreq.send sReq If XMLreq.Status = 200 Then ' Message Sent okay Else ' Something went Wrong End If End Sub