How to use Exchange Web Services API in Javascript

How to use Exchange Web Services API in Javascript

Exchange Web Services (EWS) is a set of services that provide access to the data stored on the Exchange server. In order to communicate with those services Microsoft provides an API which can be used to access mailboxes, read or send email messages from the Exchange server, or do tasks like creating, updating, and canceling appointments. This blog post focuses on accessing specific mailboxes, filtering emails, retrieving email body and attachments, and sending email messages using EWS in JavaScript.

Configuring the Exchange Service

First thing we need to do is install the EWS API library ews-javascript-api and a helper library ews-javascript-api-auth to support NTLM (New Technology LAN Manager) authentication.

var ews = require("ews-javascript-api");
var ewsAuth = require("ews-javascript-api-auth");
ews.ConfigurationApi.ConfigureXHR(new ewsAuth.ntlmAuthXhrApi(credentials.username, credentials.password));

Before we can use the EWS API to perform any task, we must create an instance of the ExchangeService class which is targeting the specified Exchange version and is scoped to the system’s current time zone. In our example the specified Exchange version is Exchange2013_SP1.

const service = new ews.ExchangeService(ews.ExchangeVersion.Exchange2013_SP1);

Specifying the Exchange version tells the server which version it should use to process the request and provides access to the properties and methods available in that particular version.

After the instantiation of the ExchangeService object, we need to set the credentials to log in to the Exchange server.

service.Credentials = new ews.WebCredentials(credentials.username, credentials.password);

You could also use the credentials of the user who is currently logged on to Windows by setting:

service.UseDefaultCredentials = true

In the next step we need to specify the EWS URL which is going to be used for communication.

service.Url = new ews.Uri("https://mydomain.com/ews/Exchange.asmx");

Filtering and retrieving emails

This section shows how to use the EWS SearchFilter class  to write a custom filter for retrieving specific emails from the mailbox. In the example below we are looking for an email which was received within specified time and contains „test@interhyp-blog.test“ email address and word „Registrierung“ in its subject.

const searchFilter = new ews.SearchFilter.SearchFilterCollection(ews.LogicalOperator.And, [
    new ews.SearchFilter.IsGreaterThanOrEqualTo(ews.ItemSchema.DateTimeReceived, ews.DateTime.Parse("2021-04-1T13:00:00")),
    new ews.SearchFilter.IsLessThanOrEqualTo(ews.ItemSchema.DateTimeReceived, ews.DateTime.Parse("2021-04-1T14:00:00")),
    new ews.SearchFilter.ContainsSubstring(ews.ItemSchema.Subject, 'test@interhyp-blog.test'),
    new ews.SearchFilter.ContainsSubstring(ews.ItemSchema.Subject, 'Registrierung'),
  ]);

SearchFilter represents the base search filter class. To define search filters, we can use its descendant search filter classes such as SearchFilter.IsEqualTo, SearchFilter.IsGreaterThan, SearchFilter.IsLessThanSearchFilter.ContainsSubstring etc. In order to define complex search filters, SearchFilter class provides SearchFilterCollection descendant class. In the example above SearchFilterCollection class is used to define a collection of search filters linked by a logical operator AND.

The next step is to define the ItemView, which represents the view settings in a search operation, along with a page size which represents the maximum number of elements the search operation should return. The following code initializes an ItemView with a page size of 1 since we expect only one email to be returned.

const itemview = new ews.ItemView(1);

The page size is required to create an ItemView. Other optional parameters are the offset and offsetBasePoint which are used for subsequent paged calls. Parameter offset represents the offset of the view from the base point and offsetBasePoint defines offset’s base point in a paged view which can be either beginning or end.

Optionally, to enhance performance of the search operation, we can set additional properties which we want to be returned in the result set. Property definitions are available as static members from schema classes such as ItemSchema.Subject or AppointmentSchema.Start. The following example shows a property set that includes the item Subject and DateTimeSent.

const foundItems = service.FindItems(ews.WellKnownFolderName.Inbox, searchFilter, itemview);

Finally, we can send the request to search the mailbox and get the results. In this example, the search is limited to the user’s Inbox.

const itemPropertySet = new ews.PropertySet(ews.ItemSchema.Subject, ews.ItemSchema.DateTimeSent);
itemview.PropertySet = itemPropertySet;

FindItems method obtains a list of items by searching the contents of a specific folder and results in a call to EWS. In the example above, the method takes 3 parameters:

  • the name of the folder in which to search for items, which is in our case WellKnownFolderName.Inbox,
  • search filter, and
  • the view controlling the number of items returned.

The method returns results of the search operation as a Promise.

Retrieving the email body

Looking at the documentation of the ItemSchema class, you would probably expect that in order to retrieve email body you just need to add ItemSchema.Body to the property set, like this:

const itemPropertySet = new ews.PropertySet(ews.ItemSchema.Body);

However, calling the FindItems method and trying to access the body text of an email would result in an error.

The code required to get the body isn’t as obvious as you might think and the FindItems call doesn’t return all the properties defined in the property set. The reason for that is resource usage minimization. Large binary objects or text properties such as the Body, and calculated properties whose value depends on other properties are not returned in a FindItems call. Even though it is not intuitive, there is a way to retrieve the body – it just involves a few extra steps.

The most efficient way to retrieve the body is to use the LoadPropertiesForItems method which loads the properties of multiple items in a single call to EWS.

service.LoadPropertiesForItems(foundItems.Items, new ews.PropertySet(ews.ItemSchema.Body))

Note that foundItems is the collection returned by FindItems call.

Retrieving the attachments

Similar to the email body, attachments are not returned by a call to FindItems. They can be retrieved using the LoadPropertiesForItems method.

service.LoadPropertiesForItems(foundItems.Items, new ews.PropertySet(ews.ItemSchema.Attachments))

Once the properties are loaded, we can access the attachments and, for example, retrieve the name of a specific attachment with the following code:

service.LoadPropertiesForItems(foundItems.Items, new ews.PropertySet(ews.ItemSchema.Attachments))
        .then(function () {
          console.log(Attachment name: ', foundItems.Items[0].Attachments.Items[0].name);
        }, function (err) {
          console.log(err);
        });

Note that foundItems is the collection returned by FindItems call.

Sending an email message

In order to send an email message first we need to create and configure the message. This can be done using EmailMessage class.

const emailMessage = new ews.EmailMessage(service);

In the next step we can add properties to the created email message.

emailMessage.ToRecipients.Add('test@interhyp-blog.test');
emailMessage.Subject = 'Email sent with EWS API';
const messageBody = new ews.MessageBody();
messageBody.BodyType = ews.BodyType.HTML;
messageBody.Text = 'Test email message with the subject.';
emailMessage.Body = messageBody;

Adding at least one recipient is mandatory and optionally, CC (carbon copy) and BCC (blind carbon copy) can be added as well.

emailMessage.CcRecipients.Add("test1@interhyp-blog.test");
emailMessage.BccRecipients.Add("test2@interhyp-blog.test");

EWS API provides the option to define the type of the body message using BodyType enumeration which can be either HTML or text. Once the message is configured the final step is to send the message. The Send method will send the message without saving its copy.

emailMessage.Send();

And here is how the received email looks like.

Another option to send the message is to use the SendAndSaveCopy method which sends the message and saves its copy to the specified folder.

emailMessage.SendAndSaveCopy(ews.WellKnownFolderName.SentItems);

Summary

In this blog article, I presented examples of how to use the Exchange Web Services API in JavaScript to filter emails, retrieve messages and attachments, and send email messages. While most of these operations were straightforward and easy to implement following the documentation, retrieving the email body turned out to be a bit of a challenge since it is not so intuitive in the documentation.

Besides the services presented in this article, Exchange Web Services provides many other services such as the Exchange calendar API which allows us to create, retrieve, update or delete appointments. For more details check out the EWS JavaScript API documentation.

Schreibe einen Kommentar