EWS: Sending Email with Attachment

A requirement in an Outlook Web Add-in I am working on required the ability to send an email to an alias with another email as an attachment. I found this a bit challenging as the makeEwsRequestAsync() function limits us to only a handful of EWS functions (EWS operations that add-ins support). This means I was unable to use a lot of the samples I found on the web. However, with the UpdateItem method, I found a way. wlEmoticon-hotsmile.png

First, let me say, I have been asked – why is easyEWS.js not on GitHub. Well, now it is:

https://github.com/davecra/easyEWS

Additionally, you can now reference the latest and greatest in your project at https://raw.githubusercontent.com/davecra/easyEWS/master/easyEws.js.

Next, so I updated the functionality in easeEws via two function:

  • easyEws.getMailItemMimeContent – we use this function to get the MIME content of a specified mail item by the ID.
  • easyEws.sendPlainTextEmailWithAttachment – this function, although a tad more complicated, will create a very simple plain text email and add an attachment send it and save it to the drafts folder.

Here are the two new updates:

    // PUBLIC: creates a new emails message with a single attachment and sends it
    // RETURNS: 'success' is compelted successfully
    easyEws.sendPlainTextEmailWithAttachment = function (subject, body, to, attachmentName, attachmentMime, successCallback, errorCallback) {
        var soap = '<m:CreateItem MessageDisposition="SendAndSaveCopy">' +
                   '    <m:Items>' +
                   '        <t:Message>' +
                   '            <t:Subject>' + subject + '</t:Subject>' +
                   '            <t:Body BodyType="Text">' + body + '</t:Body>' +
                   '            <t:Attachments>' +
                   '                <t:ItemAttachment>' +
                   '                    <t:Name>' + attachmentName + '</t:Name>' +
                   '                    <t:IsInline>false</t:IsInline>' +
                   '                    <t:Message>' +
                   '                        <t:MimeContent CharacterSet="UTF-8">' + attachmentMime + '</t:MimeContent>' +
                   '                    </t:Message>' +
                   '                </t:ItemAttachment>' +
                   '            </t:Attachments>' +
                   '            <t:ToRecipients><t:Mailbox><t:EmailAddress>' + to + '</t:EmailAddress></t:Mailbox></t:ToRecipients>' +
                   '        </t:Message>' +
                   '    </m:Items>' +
                   '</m:CreateItem>';

        soap = getSoapHeader(soap);

        // make the EWS call
        asyncEws(soap, function (xmlDoc) {
            // Get the required response, and if it's NoError then all has succeeded, so tell the user.
            // Otherwise, tell them what the problem was. (E.G. Recipient email addresses might have been
            // entered incorrectly --- try it and see for yourself what happens!!)
            var result = xmlDoc.getElementsByTagName("ResponseCode")[0].textContent;
            if (result == "NoError") {
                successCallback(result);
            }
            else {
                successCallback("The following error code was recieved: " + result);
            }
        }, function (errorDetails) {
            if (errorCallback != null)
                errorCallback(errorDetails);
        });
    };

    // PUBLIC: gets the mail item as raw MIME data
    // RETURNS: the entire email message as a MIME Base64 string
    easyEws.getMailItemMimeContent = function (mailItemId, successCallback, errorCallback) {
        var soap =
            '<m:GetItem>' +
            '    <m:ItemShape>' +
            '        <t:BaseShape>IdOnly</t:BaseShape>' +
            '        <t:IncludeMimeContent>true</t:IncludeMimeContent>' +
            '    </m:ItemShape>' +
            '    <m:ItemIds>' +
            '        <t:ItemId Id="' + mailItemId + '"/>' +
            '    </m:ItemIds>' +
            '</m:GetItem>';
        soap = getSoapHeader(soap);
        // make the EWS call
        asyncEws(soap, function (xmlDoc) {
            //var content = xmlDoc.getElementsByTagName("MimeContent")[0].textContent;
            successCallback(xmlDoc);
        }, function (errorDetails) {
            if (errorCallback != null)
                errorCallback(errorDetails);
        });
    };

Additionally, you no longer need to call initialize on easyEws. And you can simply add a reference to it in your HTML to always get the latest:

<script src=”https://raw.githubusercontent.com/davecra/easyEWS/master/easyEws.js type=”text/javascript”>script>

Once added, you can use EasyEWS.js on your projects. In my particular project, I used the following code, which does the following:

  • Gets the current mail item (entirely) as a base64 encoded string. This is the full MIME representation of the message.
  • It then creates a new mail item and sends it with a comment from the user to the email address specified with an attachment (which is the base64 string we got in the first step).

This is all done with EWS and because of easyEWS.js, it is done in very few lines of code:

    // Loads the form items to attach to events
    function loadForm() {
        $("#forward-button").click(function () {
            getCurrentMessage();
        });
    }

    // This function handles the click event of the sendNow button.
    // It retrieves the current mail item, so that we can get its itemId property
    // ans also get the MIME content
    // It also retrieves the mailbox, so that we can make an EWS request
    // to get more properties of the item.
    function getCurrentMessage() {
        var item = Office.context.mailbox.item;
        itemId = item.itemId;
        mailbox = Office.context.mailbox;
        try{
            easyEws.getMailItemMimeContent(itemId, sendMessageCallback, showErrorCallback);
        } catch (error) {
            showNotification("Unspecified error.", err.Message);
        }
    }

    // This function is the callback for the getMailItemMimeContent method
    // in the getCurrentMessage function.
    // In brief, it first checks for an error repsonse, but if all is OK
    // t:ItemId element.
    // Recieves: mail message content as a Base64 MIME string
    function sendMessageCallback(content) {
        var toAddress = "bob@contoso.com";
        var comment = $("#forward-comment").val();
        if (comment == null || comment == '') {
            comment = "[user provided no comment]";
        }
        try{
            easyEws.sendPlainTextEmailWithAttachment("Message with Item Attachment",
                                                     comment,
                                                     toAddress,
                                                     "Email Attachment",
                                                     content,
                                                     successCallback,
                                                     showErrorCallback);
        }
        catch (error) {
            showNotification("Unspecified error.", err.Message);
        }
    }

    // This function is the callback for the easyEws sendPlainTextEmailWithAttachment
	// Recieves: a message that the result was successful.
    function successCallback(result) {
        showNotification("Success", result);
    }

    // This function will display errors that occur
    // we use this as a callback for errors in easyEws
    function showErrorCallback(error) {
        showNotification("Error", error);// .error.message);
    }

easyEWS.js for Outlook Add-ins

If you have done any work with Outlook Add-ins using the Office JavaScript API’s, you might have found a nifty function that allows you to poll the Exchange Server using EWS calls. The function: makeEwsRequestAsync(). However, this function is not the easiest thing to use. You have to formulate an EWS SOAP message that you send to the service. Getting those correct, writing the code for them, and processing the results are a real beast. But, even worse is finding exactly how to formulate the SOAP message from the existing documentation. It is something I personally did NOT look forward to as I was working on my customers solutions.

My frustration is your benefit (I hope). I created a JavaScript class called easyEws, that makes certain calls very easy. I posted the project on GitHub (previously, I had posted this on CodePlex):

https://github.com/davecra/easyEWS

I have attempted to make the functions a lot easier to use. Here are a few examples:

This code will get you the folder ID for the Drafts folder:

easyEws.getFolderId(&quot;drafts&quot;, function (value) {
	app.showNotification(&quot;Drafts folder ID: &quot; + value);
});

Or, this example which will connect to the Inbox and tell you how many items are there:

easyEws.getFolderId(&quot;inbox&quot;, function (folderId) {
	easyEws.getFolderItemIds(folderId, function (arrayOfIDs) {
		app.showNotification(&quot;There are &quot; + arrayOfIDs.length + &quot; items.&quot;);
	});
});

easyEWS has the following commands that encapsulates the makeEwsRequestAsync() calls and the SOAP messages:

  • expandGroup: one dimensional expansion of a group (does not do groups within group expansions).
  • findConversationItems: returns a list of mail items that all share the same conversationId.
  • getEwsHeaders: gets a list of X-Headers in the mail message.
  • getFolderId: returns the folder ID for a named folder, like “Drafts”, “Inbox”, etc.
  • getFolderItemIds: returns a list of mail item IDs in a given folder.
  • getFolderProperty: gets a named property from a folder.
  • getMailItem: returns a mail item from the given Id.
  • updateEwsHeader: Updated the named x-header in the message.
  • updateFolderProperty: Updates the property of a folder by the given ID.