Quantcast
Channel: Glen's Exchange and Office 365 Dev Blog
Viewing all articles
Browse latest Browse all 241

EWS Basics : Sending Messages using EWS

$
0
0
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.

functionSend-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

functionSend-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).

SubSendMessage(Subject AsString, Recipient AsString, Body AsString, User AsString, Password AsString)
Dim sReq AsString
Dim xmlMethod AsString
Dim XMLreq AsNew MSXML2.XMLHTTP60
Dim EWSEndPoint AsString
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 =200Then
' Message Sent okay
Else
' Something went Wrong
EndIf
EndSub


Viewing all articles
Browse latest Browse all 241

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>