Logo
blank Skip to main content

Developing JavaScript Plugins for Outlook: Practical Example

There are two types of Outlook plugins: COM and JavaScript. In this article, we will try to compare them by looking at both pros and cons of each of them.

We will also provide you with a practical example of the client-side Outlook plugin, written with JavaScript that receives information about attachments and adds it to the body of the email. This can be used to check whether an email has the right files attached and whether it will be sent to the right people.

All and all, with this plugin you will be able to check the following information:

  1. Whether “sent to” field includes any undesirable addressees
  2. What kind of files are attached to the message (in the future, an option to check attachments for viruses may become available)
  3. Add additional properties on sending the message

In this article, we also showed how to use JavaScript plugin to do the following things while sending email:

  1. Adding the “Analyze And Send” button that will call our code for getting the data from an email while trying to send it
  2. Gathering information about attachments (AttachmentId, Name, ContentType, Size, LastModifiedTime)
  3. Adding received information to the email body. We will show how to change the message body with JavaScript in full detail.
  4. Adding custom properties to the email. We will show how to add the necessary property that can be further used by the receiver.
  5. Sending the modified email to specific addressees

Setting up manifestFile

Let’s look at this topic in closer detail. First, we need to configure a manifest file. This file describes where the button, that we want to create, will be located, what will happen when it’s pressed, and what permissions do we need to work with the mailbox. In this example, when the button has been clicked, the function that handles analysis of attachments and sends the emails to addressees will be called. Main things to know about the manifest file:

  1. Access to EWS operations (GetItem and SendItem) received via the mailbox.makeEWSRequestAsync function. These operations require ReadWriteMailbox permissions. Required type of permissions in the manifest:
  2. Plugin works only for outgoing messages. This is why the Analyze and Send button will appear only when creating a new email. For this we need to set a type for ExtensionPoint in a MessageComposeCommandSurface:
XML
<ExtensionPoint xsi:type="MessageComposeCommandSurface">
  1. A function should be called on a button click. Setting the necessary property:
XML
<Action xsi:type="ExecuteFunction">
	<FunctionName>sendEmail</FunctionName>
</Action>

where sendEmail is a function that will be called when the button has been clicked

We also need to specify the path to the html file where the necessary JavaScript file with implemented sendEmail is specified.

XML
<bt:Url id="functionFile" DefaultValue=" YOUR_WEB_SERVER /AppCompose/FunctionFile/AttachmentInfo.html"/>
  1. Change all references of YOUR_WEB SERVER in the manifest file to your server using the HTTPS protocol

Related services

Custom .NET Development Services

Adding Add-in to Web version of Outlook

After the manifest file has been described, we should add Add-in to a Web version of Outlook (outlook.com).

  1. IN the upper right corner click the gear icon. Next, choose the Manage integrations menu (fig. 1)
Outlook plugin integration

 

Fig. 1 Manage integrations menu

  1. In the opened window click the Click here to add a custom add-in button and then select Add from file… menu (Fig. 2)
Adding Outlook plugin

 

Fig. 2 Add from file… menu

  1. Click Install to install an Add-in. If the installation has been completed successfully, Add-in should appear in the My add-ins category (Fig. 3).
Install Outlook add-in

 

Fig. 3. Successfully installed Add-in

Now when creating the new email, you should see a blue button the lower right corner. After clicking the button, an information on attachments will be received, added to the body of message and the email will be sent to addressees.

Add custom Outlook button

 

Fig.4. Custom button

Getting data from the Exchange Server

Now let’s look into more detail into what happens when we click the Analyze and Send button. When clicking the button, we execute the sendEmail function. This function is declared in the Attachementinfo.js file. The path to this file, as well as an information on what function exactly should be called are both described via html in manifest files (which we already covered). sendEmail receives an event that we need to complete. To get the data on attachment, we need to make an EWS request, but in order to do this, we need to receive mail id. When new email is created, this id hasn’t been assigned yet. In order to do this, we need to save the email in the draft by calling the saveAsync function:

C++
Office.context.mailbox.item.saveAsync(saveItemCallBack);

The necessary id will be received in the saveItemCallBack function. Now we need to formulate and make an EWS request to get the data on attachments:

C++
function getItemDataRequest(itemId) {
    var soapToGetItemData = '<?xml version="1.0" encoding="utf-8"?>' +
                    '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
                    '               xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"' +
                    '               xmlns:xsd="http://www.w3.org/2001/XMLSchema"' +
                    '               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' +
                    '               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
                    '  <soap:Header>' +
                    '    <RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />' +
                    '  </soap:Header>' +
                    '  <soap:Body>' +
                    '    <GetItem' +
                    '                xmlns="http://schemas.microsoft.com/exchange/services/2006/messages"' +
                    '                xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
                    '      <ItemShape>' +
                    '        <t:BaseShape>IdOnly</t:BaseShape>' +
                    '        <t:AdditionalProperties>' +
                    '            <t:FieldURI FieldURI="item:Attachments" /> ' +
                    '        </t:AdditionalProperties> ' +
                    '      </ItemShape>' +
                    '      <ItemIds>' +
                    '        <t:ItemId Id="' + itemId + '"/>' +
                    '      </ItemIds>' +
                    '    </GetItem>' +
                    '  </soap:Body>' +
                    '</soap:Envelope>';
    return soapToGetItemData;
}
Office.context.mailbox.makeEwsRequestAsync(soapToGetItemData, itemDataCallback);

Related services

Data Management Solutions

Getting data on attachments

If the request is correct and there are no errors, then through an itemDataCallback we will start receiving data on attachments.

C++
function buildAttachmentsInfo(xmlDoc) {
    var attachmentsInfo = "You have no any attachments.";
    if ($('HasAttachments', xmlDoc).length == 0) {
        return attachmentsInfo;
    }
    var attachSeparator = "--------------------------------------------- 
";
    if ($('HasAttachments', xmlDoc)[0].textContent == "true") {
        attachmentsInfo = "";
        var childNodes = $('Attachments', xmlDoc)[0].childNodes;
        childNodes.forEach(function (fileAttachmentItem, fileAttachmentIndex) {
            fileAttachmentItem.childNodes.forEach(function (item, index) {
                if (item.tagName.includes("AttachmentId")) {
                    attachmentsInfo = attachmentsInfo.concat(item.tagName.replace("t:", "") + ': ' + item.getAttribute("Id") + "<br>");
                    return;
                }
                attachmentsInfo = attachmentsInfo.concat(item.tagName.replace("t:", "") + ': ' + item.textContent + "<br>");
            });
            attachmentsInfo = attachmentsInfo.concat(attachSeparator);
        });
    }
    return attachmentsInfo;
}

Read also:
Mail Server Security: Potential Vulnerabilities and Protection Methods

Adding additional properties to email

JavaScript API also allows to add custom properties to an email. Here’s an example of how it can be done:

C++
Office.context.mailbox.item.loadCustomPropertiesAsync(function (asyncResult) {
        var customProps = asyncResult.value;
        customProps.set("myProp", "value");
        customProps.saveAsync(function (asyncResult) {...});
});

Modifying the body of an email

When all the necessary properties are received and added, then we can add the information into the body of an email. In order to do this we need to receive the whole text that is contained in the email and replace it fully with the new one. In this case, we will use the setAsync function, and not the setSelectedDataAsync, because setSelectedDataAsync add the position of the cursor or replaces selected text. Example:

C++
Office.context.mailbox.item.body.getAsync("html", { asyncContext: "This is passed to the callback" }, function (result) {
        var newText = result.value + "<br>" + attachmentsInfo;
        Office.context.mailbox.item.body.setAsync(newText, { coercionType: Office.CoercionType.Html }, function (asyncResult) {…};
});

Read also:
Testing JavaScript with Jasmine

Sending an email

Everything is complete. Now we can send our email to addressees. To do this, we need to form and execute EWS request to send the message:

C++
function getSendItemRequest(itemId, changeKey) {
    var soapSendItemRequest = '<?xml version="1.0" encoding="utf-8"?>' +
                            '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
                            '               xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"' +
                            '               xmlns:xsd="http://www.w3.org/2001/XMLSchema"' +
                            '               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' +
                            '               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
                            '  <soap:Header>' +
                            '    <RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />' +
                            '  </soap:Header>' +
                            '  <soap:Body> ' +
                            '    <SendItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" ' +
                            '              SaveItemToFolder="true"> ' +
                            '      <ItemIds> ' +
                            '        <t:ItemId Id="' + itemId + '" ChangeKey="' + changeKey + '" /> ' +
                            '      </ItemIds> ' +
                            '      <m:SavedItemFolderId>' +
                            '         <t:DistinguishedFolderId Id="sentitems" />' +
                            '      </m:SavedItemFolderId>' +
                            '    </SendItem> ' +
                            '  </soap:Body> ' +
                            '</soap:Envelope> ';
    return soapSendItemRequest;
}
Office.context.mailbox.makeEwsRequestAsync(soapToGetItemData, function (asyncResult){…});

This function will receive two parameters: itemId and changeKey. ItemId can be received by saving the email in the draft folder (as described above), while changeKey can be received in response to the request. It looks like we’re all set, but not quite. Because we changed the content of the email, we need to save it again in order to receive the new changeKey in response to the request:

C++

Office.context.mailbox.item.saveAsync(function (result) {
                var soapToGetItemData = getItemDataRequest(result.value);
                Office.context.mailbox.makeEwsRequestAsync(soapToGetItemData, function (asyncResult) {
                    if (asyncResult.error != null) {
                        updateAndComplete("EWS Status: " + asyncResult.error.message);
                        return;
                    }
                    var xmlDoc = getXMLDocParser(asyncResult.value);
                    var changeKey = $('ItemId', xmlDoc)[0].getAttribute("ChangeKey");
                    var soapToSendItem = getSendItemRequest(result.value, changeKey);
                    Office.context.mailbox.makeEwsRequestAsync(soapToSendItem, function (asyncResult) {
                        if (asyncResult.error != null) {
                            statusUpdate("EWS Status: " + asyncResult.error.message);
                            return;
                        }
                        Office.context.mailbox.item.close();
                        clickEvent.completed();
                    });
                });

If everything went well, then modified email will be sent to the addressees. An example of an email before and after delivery:

Outlook JavaScript add-on sample work

 

Fig.5 Email before sending

Javascript plugin for Outlook work

 

Fig. 6 Email after delivery

Read also:
Fileless Malware: Specifics, Detection, and Protection Tips

Advantages and disadvantages of using COM and JavaScript API

Main disadvantages of JS plugin

  1. Cannot run Add-in without user input
  2. Works only with Exchange accounts (Exchange Server 2013 and newer). Also, doesn’t support IMAP and POP protocols
  3. Very limited functionality when sending messages (Compose mode)

Main advantages of JS plugin

  1. Existing platform to publish Add-ins for end-users (office store).
  2. Plugin is cross-platform, and available for Wen, Windows, MacOS, and iOS.

COM Add-in soles some problems from JS Add-in, but has its own set of disadvantages.

Main advantages of COM plugin over JS:

  1. Can work in the background. User does not required to press any buttons
  2. There are no limitations for accounts. Plugin can work in Oulook for all accounts
  3. Can receive attachment content when sending an email

Main disadvantages of COM plugin:

  1. Works only on Windows desktops
  2. Plugin cannot be distributed through office store
  3. If you need a plugin to work with, for example, both Outlook 2007 and Outlook 2016, then you need to create an individual plugin for each version.

Sadly, when sending message there is no way to get the content of the attachment. Because of this, for example, we can’t use third-party tools to check for viruses. Also, you can create the Send Email button click event that would allow you to analyze attachments automatically without any user input. Instead, you need to make a separate button that needs to be clicked. Maybe in the future Microsoft will add such ability.

Read also:
Analyzing Network Activities with Bro IDS and Intel Critical Stack

References

https://dev.outlook.com/reference/add-ins/Body.html#setSelectedDataAsync
https://dev.office.com/docs/add-ins/overview/add-in-manifests?product=outlook
https://dev.outlook.com/samples/addins

Track the sample source code at our GitHub page

Tell us about your project

Send us a request for proposal! We’ll get back to you with details and estimations.

By clicking Send you give consent to processing your data

Book an Exploratory Call

Do not have any specific task for us in mind but our skills seem interesting?

Get a quick Apriorit intro to better understand our team capabilities.

Book time slot

Contact us