Using Exchange Web Services from VBScript: Sending a message with attachment example


With Exchange 2010, CDO and all the other APIs that were commonly used from VBScript (e.g. WebDAV) are no longer supported.  The only scriptable API is EWS.  While it is relatively easy to use EWS using the managed API, this is not possible from VBScript.  However, programming with EWS from VBScript can be done, and isn’t as complex as it may first seem.

To demonstrate, here is an example from a recent case.  The question was how to send an email with attachment from a script, and the only option in this case was to use EWS.  First of all, the process for sending an email with attachment needs to be understood, as with EWS it is a three step process:

1. Create the message and save it to drafts.
2. Add the attachment to the message.
3. Send the complete message

As you can see, to do the above we will need to both send EWS requests and read data from the responses (which we wouldn’t necessarily have to do if we were just sending a basic message).  The easiest way I could think of to implement this was create the EWS requests as template files (XML with replaceable fields), and then implement some functions to make dealing with the templates and SOAP conversations more straight-forward.

The resulting script is below.  I’ve also attached a zip file that contains everything needed to test this example (you’ll have to edit the templates and configuration details in the script to your environment).  It should be quite easy to implement most EWS functionality using this system.

 

'  DISCLAIMER:
'THIS CODE IS SAMPLE CODE. THESE SAMPLES ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
'MICROSOFT FURTHER DISCLAIMS ALL IMPLIED WARRANTIES INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR OF FITNESS FOR
'A PARTICULAR PURPOSE. THE ENTIRE RISK ARISING OUT OF THE USE OR PERFORMANCE OF THE SAMPLES REMAINS WITH YOU. IN NO EVENT SHALL
'MICROSOFT OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
'BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THE
'SAMPLES, EVEN IF MICROSOFT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION
'OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO YOU.


' ---------------------------------------------------------
' CONFIGURATION - change as needed
' ---------------------------------------------------------


const TARGETURL="https://ex1.exch2k7.local/ews/exchange.asmx"
const USERNAME="exch2k7\Administrator"
const PASSWORD="root@1"
const ATTACHMENT="c:\vbstest\Attach.zip"
const TEMPLATEPATH="c:\vbstest\"


' ---------------------------------------------------------
' MAIN SCRIPT
' ---------------------------------------------------------

dim oFSO
set oFSO=CreateObject("Scripting.FileSystemObject") ' We use this globally throughout the script

' Create the message (the template creates a message in the Drafts folder)
set CreateItemResponse=SendSOAP(ReadTemplate("CreateMessage.xml"))

' Check we got a Success response
if not IsResponseSuccess(CreateItemResponse, "m:CreateItemResponseMessage") then
	' Message creation failed
	wscript.echo CreateItemResponse.xml
	wscript.quit
end if

' Now we need to read the ItemId and ChangeKey from the response
ItemId=CreateItemResponse.documentElement.getElementsByTagName("t:ItemId").Item(0).Attributes.getNamedItem("Id").Text
ChangeKey=CreateItemResponse.documentElement.getElementsByTagName("t:ItemId").Item(0).Attributes.getNamedItem("ChangeKey").Text

' Now build the SOAP request to add the attachment
CreateAttachmentSOAP=ReadTemplate("CreateAttachment.xml")
CreateAttachmentSOAP=Replace(CreateAttachmentSOAP, "", ItemId)
CreateAttachmentSOAP=Replace(CreateAttachmentSOAP, "", ChangeKey)

set f=oFSO.GetFile(ATTACHMENT)
CreateAttachmentSOAP=Replace(CreateAttachmentSOAP, "", f.Name)
CreateAttachmentSOAP=Replace(CreateAttachmentSOAP, "", ReadFileAsBase64(ATTACHMENT))

' The SOAP request is now ready, so send it (this adds the attachment to the message in the Drafts folder)
set CreateAttachmentResponse=SendSOAP(CreateAttachmentSOAP)

' Check we got a Success response
if not IsResponseSuccess(CreateAttachmentResponse, "m:CreateAttachmentResponseMessage") then
	' Message creation failed
	wscript.echo CreateAttachmentResponse.xml
	wscript.quit
end if

' Read the ItemId and ChangeKey from the response - the ItemId should be the same, but the ChangeKey will be different
ItemId=CreateAttachmentResponse.documentElement.getElementsByTagName("t:AttachmentId").Item(0).Attributes.getNamedItem("RootItemId").Text
ChangeKey=CreateAttachmentResponse.documentElement.getElementsByTagName("t:AttachmentId").Item(0).Attributes.getNamedItem("RootItemChangeKey").Text

' Finally, we need to send the message
SendItemSOAP=ReadTemplate("SendItem.xml")
SendItemSOAP=Replace(SendItemSOAP, "", ItemId)
SendItemSOAP=Replace(SendItemSOAP, "", ChangeKey)
set SendItemResponse=SendSOAP(SendItemSOAP)

' Check we got a Success response
if not IsResponseSuccess(SendItemResponse, "m:SendItemResponseMessage") then
	' Message creation failed
	wscript.echo SendItemResponse.xml
	wscript.quit
end if

wscript.echo "Message was sent successfully."


' ---------------------------------------------------------
' HELPER FUNCTIONS
' ---------------------------------------------------------


function ReadBytes(SourceFile)
	' Read the file into a stream
	set oStream=CreateObject("ADODB.Stream")
	oStream.Open
	oStream.Type=1 ' Binary
	oStream.LoadFromFile(SourceFile)
	ReadBytes=oStream.Read()
end function

function ReadFileAsBase64(SourceFile)
	' Read a file and return the contents Base64 encoded
	FileBinary=ReadBytes(SourceFile)
	set oXML=CreateObject("MSXML2.DOMDocument")
	set oNode=oXML.CreateElement("base64")
	oNode.DataType="bin.base64"
	oNode.NodeTypedValue=FileBinary
	ReadFileAsBase64=oNode.Text
end function


function SendSOAP(SOAP)
	' Send the SOAP request, and return the response
	
	set oXMLHTTP=CreateObject("MSXML2.XMLHTTP")
	set oXML=CreateObject("MSXML2.DOMDocument")
	
	' Send the request
	oXMLHTTP.Open "POST", TARGETURL, false, USERNAME, PASSWORD
	oXMLHTTP.SetRequestHeader "Content-Type", "text/xml"
	oXMLHTTP.Send SOAP
	
	if oXMLHTTP.Status="200" then
		' Get response
		if oXML.LoadXML(oXMLHTTP.ResponseText) then
			set SendSOAP=oXML
		end if
	else
		wscript.echo "Response status: " & oXMLHTTP.Status
	end if
end function

function ReadTemplate(ByVal TemplateFile)
	' Read the given template and return it
	
	if not oFSO.FileExists(TemplateFile) then TemplateFile=TEMPLATEPATH & TemplateFile
	set oTS=oFSO.OpenTextFile(TemplateFile)
	sTemplate=""
	while not oTS.AtEndOfStream
		sTemplate=sTemplate & oTS.ReadLine
	wend
	oTS.Close
	ReadTemplate=sTemplate
end function

function IsResponseSuccess(Response, ResponseMessageTag)
	on error resume next
	IsResponseSuccess=true
	if Response.documentElement.getElementsByTagName(ResponseMessageTag).Item(0).Attributes.getNamedItem("ResponseClass").Text<>"Success" then
		if Err.Number<>0 then
			wscript.echo "Error reading response: " & Err.Description
		end if
		IsResponseSuccess=false
	end if
	on error goto 0
end function

Send message with attachment.zip

Comments (4)

  1. Francesco Dotti says:

    Very useful

    Thanks a lot !

  2. Yann says:

    Hi,

    Great code, it works good.

    The only problem I have is that the html body of the mail is sent as us-ascii and not utf-8.

    Any idea ?

    Thanks

  3. yporters says:

    Hello,

    Thx for the code. It works and it was really helpfull.
    My problem is that I want to do the opposite, I want to read mails and save their file attachments to a folder.
    I’m not able to get the content of the file attachments.

    The following code is not working (file attachments are saved but the content is corrupt):

    ‘ /// 3a. Get the Mail Attachments (returns mail subject, To, From + all attachment Ids, attachment names and attachment types)
    sXMLGetMailAttachmentsIdsSOAP = Replace(sXMLGetMailAttachmentsIdsSOAP, ““, sItemId)
    set oGetMailAttachmentsIdsResponse = SendSOAP(sXMLGetMailAttachmentsIdsSOAP)
    Call Logdata (oGetMailAttachmentsIdsResponse.xml)

    ‘ /// 3b.Check if response from EWS is successful
    If not IsResponseSuccess(oGetMailAttachmentsIdsResponse, “m:GetItemResponseMessage”) then
    ‘ Find Item failed
    wscript.echo oGetMailAttachmentsIdsResponse.xml
    wscript.quit
    End if

    sSubject = oGetMailAttachmentsIdsResponse.documentElement.getElementsByTagName(“t:Subject”).Item(0).Text
    sNameTo = oGetMailAttachmentsIdsResponse.documentElement.getElementsByTagName(“t:ToRecipients/t:Mailbox/t:EmailAddress”).Item(0).Text
    sNameFrom = oGetMailAttachmentsIdsResponse.documentElement.getElementsByTagName(“t:From/t:Mailbox/t:EmailAddress”).Item(0).Text

    For each oAttachment in oGetMailAttachmentsIdsResponse.SelectNodes(“//t:FileAttachment”)

    sAttachmentId = oAttachment.getElementsByTagName(“t:AttachmentId”).Item(0).Attributes.getNamedItem(“Id”).Text
    sAttachmentName = oAttachment.getElementsByTagName(“t:Name”).Item(0).text
    ‘sMailAttachmentsContent = oAttachment.getElementsByTagName(“t:MimeContent”).Item(0).text

    msgbox sAttachmentName & ” / ” & sAttachmentId
    ‘——————————————-

    ‘ /// 4a. Get the content for each attachment
    sXMLGetAttachmentsContentSOAP = Replace(sXMLGetAttachmentsContentSOAP, ““, sAttachmentId)
    set oGetAttachmentsContentResponse = SendSOAP(sXMLGetAttachmentsContentSOAP)
    call logdata (oGetAttachmentsContentResponse.xml)

    ‘ /// 3b.Check if response from EWS is successful
    If not IsResponseSuccess(oGetAttachmentsContentResponse, “m:GetAttachmentResponseMessage”) then
    ‘ Find Item failed
    wscript.echo oGetAttachmentsContentResponse.xml
    wscript.quit
    End if

    ‘/// Get attachment content from XML response
    sMailAttachmentsContent = oGetAttachmentsContentResponse.getElementsByTagName(“t:Content”).Item(0).text

    ‘/// Decode attachement content and save to filesystem
    Call DecodeBase64ToFile(oGetAttachmentsContentResponse.getElementsByTagName(“t:Content”).Item(0).text, ATTACHMENTSPATH & sAttachmentName)

    Next

  4. yporters says:

    ‘ /// 3a. Get the Mail Attachments (returns mail subject, To, From + all attachment Ids, attachment names and attachment types)
    sXMLGetMailAttachmentsIdsSOAP = Replace(sXMLGetMailAttachmentsIdsSOAP, ““, sItemId)
    set oGetMailAttachmentsIdsResponse = SendSOAP(sXMLGetMailAttachmentsIdsSOAP)
    Call Logdata (oGetMailAttachmentsIdsResponse.xml)

    ‘ /// 3b.Check if response from EWS is successful
    If not IsResponseSuccess(oGetMailAttachmentsIdsResponse, “m:GetItemResponseMessage”) then
    ‘ Find Item failed
    wscript.echo oGetMailAttachmentsIdsResponse.xml
    wscript.quit
    End if

    sSubject = oGetMailAttachmentsIdsResponse.documentElement.getElementsByTagName(“t:Subject”).Item(0).Text
    sNameTo = oGetMailAttachmentsIdsResponse.documentElement.getElementsByTagName(“t:ToRecipients/t:Mailbox/t:EmailAddress”).Item(0).Text
    sNameFrom = oGetMailAttachmentsIdsResponse.documentElement.getElementsByTagName(“t:From/t:Mailbox/t:EmailAddress”).Item(0).Text

    For each oAttachment in oGetMailAttachmentsIdsResponse.SelectNodes(“//t:FileAttachment”)

    sAttachmentId = oAttachment.getElementsByTagName(“t:AttachmentId”).Item(0).Attributes.getNamedItem(“Id”).Text
    sAttachmentName = oAttachment.getElementsByTagName(“t:Name”).Item(0).text
    ‘sMailAttachmentsContent = oAttachment.getElementsByTagName(“t:MimeContent”).Item(0).text

    msgbox sAttachmentName & ” / ” & sAttachmentId
    ‘——————————————-

    ‘ /// 4a. Get the content for each attachment
    sXMLGetAttachmentsContentSOAP = Replace(sXMLGetAttachmentsContentSOAP, ““, sAttachmentId)
    set oGetAttachmentsContentResponse = SendSOAP(sXMLGetAttachmentsContentSOAP)
    call logdata (oGetAttachmentsContentResponse.xml)

    ‘ /// 3b.Check if response from EWS is successful
    If not IsResponseSuccess(oGetAttachmentsContentResponse, “m:GetAttachmentResponseMessage”) then
    ‘ Find Item failed
    wscript.echo oGetAttachmentsContentResponse.xml
    wscript.quit
    End if

    ‘/// Get attachment content from XML response
    sMailAttachmentsContent = oGetAttachmentsContentResponse.getElementsByTagName(“t:Content”).Item(0).text

    ‘/// Decode attachement content and save to filesystem
    Call DecodeBase64ToFile(oGetAttachmentsContentResponse.getElementsByTagName(“t:Content”).Item(0).text, ATTACHMENTSPATH & sAttachmentName)

    Next

Skip to main content