The Developer's Guide to the Microsoft Exchange APIs (EAS, EWS, and Graph)

The Developer’s Guide to the Microsoft Exchange APIs (EAS, EWS, and Graph)

9 min read

In Exchange’s 20+ year history, Microsoft has created numerous APIs — but with each new API comes a surge in ongoing maintenance and support as developers are forced to rip out the old protocols and implement the new ones.

In this blog, we’ll dive into the three most commonly used protocols to build an integration with Exchange:

  1. EAS (ActiveSync)
  2. EWS (Web Services)
  3. Microsoft Graph
  4. A better way to integrate with Exchange

ActiveSync

EAS, literally “Exchange ActiveSync Services”, was introduced in Exchange 2003 to specifically sync Exchange with mobile clients (high-latency, low-bandwidth connections). It was very innovative at the time and introduced a lightweight, idempotent procedure for data synchronization.

ActiveSync is broadly deployed and supported natively by iOS and Android. In practice, it remains the lowest common denominator for integrating applications with different versions of Exchange. Unfortunately, being a licensed technology, there is no public SDK for ActiveSync. Clients wishing to use it must implement the protocol from spec.

ActiveSync is a proprietary binary protocol, which makes it way harder to interoperate with than SOAP or XML-RPC. An ActiveSync sync loop is typically done in three phases:

  1. An autodiscovery phase which translates the mailbox address to an ActiveSync endpoint
  2. An explicit provisioning step which negotiates the client’s capabilities with the server’s access policies (this step takes place just once)
  3. A recursive folder synchronization procedure. Messages are encoded into something called WBXML – a binarized format not unlike BSON or protocol buffers which defines a state machine and walks through it via a token stream.

In the recursive folder procedure, each token represents either a unit of data (“inline string”) or a transition (“inline string follows”). Outside of the message body, a number of Exchange-specific headers must be added to the HTTP messages. ActiveSync can run over SSL and can authenticate via OAuth or NTLM.

Here’s an example of a decoded ActiveSync message (note the use of a sync key to represent the current/next page of results):

Request:

<?xml version="1.0" encoding="utf-8"?>
<airsync:Sync xmlns:airsync="AirSync">
  <airsync:Collections>
    <airsync:Collection>
      <airsync:SyncKey>866776076</airsync:SyncKey>
      <airsync:CollectionId>7</airsync:CollectionId>
      <airsync:ConversationMode>1</airsync:ConversationMode>
      <airsync:Options>
        <airsyncbase:BodyPreference xmlns:airsyncbase="AirSyncBase">
          <airsyncbase:Type>2</airsyncbase:Type>
          <airsyncbase:TruncationSize>500</airsyncbase:TruncationSize>
          <airsyncbase:Preview>100</airsyncbase:Preview>
        </airsyncbase:BodyPreference>
      </airsync:Options>
    </airsync:Collection>
  </airsync:Collections>
  <airsync:HeartbeatInterval>60</airsync:HeartbeatInterval>
</airsync:Sync>

Response:

<?xml version="1.0" encoding="utf-8"?>
<Sync xmlns="AirSync" xmlns:email="Email" xmlns:airsyncbase="AirSyncBase" xmlns:
email2="Email2">
  <Collections>
    <Collection>
      <SyncKey>1992475662</SyncKey>
      <CollectionId>7</CollectionId>
      <Status>1</Status>
      <Commands>
        <Add>
          <ServerId>7:1</ServerId>
          <ApplicationData>
            <email:To>"Albert Einstein" &lt;al@particletech.com&gt;</email:To>
            <email:From>"Alexander Graham Bell" &lt;alex@bell.com&gt;</email:From
>
            <email:Subject>Test Mail</email:Subject>
            <email:DateReceived>2012-06-20T19:13:48.827Z</email:DateReceived>
            <email:DisplayTo>Albert Einstein</email:DisplayTo>
            <email:ThreadTopic>Nuclear Phones</email:ThreadTopic>
            <email:Importance>1</email:Importance>
            <email:Read>0</email:Read>
            <airsyncbase:Body>
              <airsyncbase:Type>2</airsyncbase:Type>
              <airsyncbase:EstimatedDataSize>319</airsyncbase:EstimatedDataSize>

              <airsyncbase:Data></airsyncbase:Data>
              <airsyncbase:Preview></airsyncbase:Preview>
            </airsyncbase:Body>
          </ApplicationData>
        </Add>
      </Commands>
    </Collection>
  </Collections>
</Sync>

 

Source: Microsoft Docs

ActiveSync was built for mobile phones of the early 2000s, and missing functionality was spread across MAPI-over-HTTP and WebDAV.

Which is why Microsoft ultimately released Exchange Web Services (EWS), which addresses the scattered landscape.

Exchange Web Services (EWS)

EWS is a much more typical XML SOAP service, replete with all the structural formalities and WS-Addressing that you would expect. Unlike ActiveSync, it does not have a provisioning phase to enforce mobile device policies.

EWS-aware applications are typically enabled individually (or as a group) by the Exchange administrator. This means that the authentication procedure is done more or less transparently through the SDK by providing a user’s credentials. Like ActiveSync, EWS also supports SSL, OAuth, and NTLM.

Below is an example of an EWS mail sync message. Like ActiveSync, requests and responses trade a state key. EWS also uses a ChangeKey to represent the current version of an item.

Request:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages"
               xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types"
               xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
      <t:RequestServerVersion Version="Exchange2010_SP2" />
  </soap:Header>
  <soap:Body>
    <m:SyncFolderItems>
      <m:ItemShape>
        <t:BaseShape>AllProperties</t:BaseShape>
      </m:ItemShape>
      <m:SyncFolderId>
        <t:DistinguishedFolderId Id="inbox" />
      </m:SyncFolderId>
      <m:SyncState>H4sIAAA==</m:SyncState>
      <m:MaxChangesReturned>10</m:MaxChangesReturned>
      <m:SyncScope>NormalItems</m:SyncScope>
    </m:SyncFolderItems>
  </soap:Body>
</soap:Envelope>

Response:

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:ServerVersionInfo MajorVersion="15" MinorVersion="0" MajorBuildNumber="731" MinorBuildNumber="10" Version="V2_3"
                 xmlns:h="https://schemas.microsoft.com/exchange/services/2006/types"
                 xmlns="https://schemas.microsoft.com/exchange/services/2006/types"
                 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <m:SyncFolderItemsResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:SyncFolderItemsResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:SyncState>H4sIAAAAAAAEAO29B2AcSZY==</m:SyncState>
          <m:IncludesLastItemInRange>true</m:IncludesLastItemInRange>
          <m:Changes>
            <t:Update>
                <t:Message>
                  <t:ItemId Id="q04QAAAA==" ChangeKey="CQAAABYAAADZGACZQpSgSpyNkexYe2b7AAAAird/" />
                  <t:ParentFolderId Id=" AgENAAAA" ChangeKey="AQAAAA==" />
                  <t:ItemClass>IPM.Note</t:ItemClass>
                  <t:Subject>RE: Company Soccer Team</t:Subject>
                  <t:Sensitivity>Normal</t:Sensitivity>
                  <t:DateTimeReceived>2013-08-29T15:22:10Z</t:DateTimeReceived>
                  <t:Size>23110</t:Size>
                  <t:Importance>Normal</t:Importance>
                  <t:From>
                    <t:Mailbox>
                      <t:Name>Albert Einstein</t:Name>
                      <t:EmailAddress>al@particletech.com</t:EmailAddress>
                      <t:RoutingType>SMTP</t:RoutingType>
                      <t:MailboxType>Mailbox</t:MailboxType>
                    </t:Mailbox>
                  </t:From>
          </m:Changes>
        </m:SyncFolderItemsResponseMessage>
      </m:ResponseMessages>
    </m:SyncFolderItemsResponse>
  </s:Body>
</s:Envelope>

Source: Microsoft Docs

Microsoft Graph

Microsoft Graph is a fairly new service meant to unify all Office APIs (like Excel and OneDrive) and has officially preempted EWS. Therefore, Graph’s schema is organized not by product but data type (like the Mail API, Calendar API, Notifications API, etc.). This represents a convenient abstraction over the inner workings of Outlook and Excel but represents a major migration from the EWS API.

It should also be noted that not all features have been ported over – for example, [free/busy] is still in beta. Also, Graph cannot be used with on-premise deployments of Exchange. Support for hybrid deployments is currently in beta.

With Graph, authentication is typically done via OAuth and is segmented into scopes with access tokens. Being an Exchange 365 product, applications must register via the Azure active directory service, as opposed to with Exchange itself.

Below is an example of a Graph mail call:

https://graph.microsoft.com/v1.0/me/messages

{
    “@odata.context”: “https://graph.microsoft.com/v1.0/$metadata#users(‘48d31887-5fad-4d73-a9f5-3c356e68a038’)/messages”,
    “@odata.nextLink”: “https://graph.microsoft.com/v1.0/me/messages?$skip=12”,
    “value”: [
        {
            “@odata.etag”: “W/\”CQAAABYAAAAiIsqMbYjsT5e/T7KzowPTAAEMTBu8\””,
            ...
            “sender”: {
                “emailAddress”: {
                    “name”: “MyAnalytics”,
                    “address”: “no-reply@microsoft.com”
                }
            },
            “from”: {
                “emailAddress”: {
                    “name”: “MyAnalytics”,
                    “address”: “no-reply@microsoft.com”
                }
            },
            ...

Source: Microsoft Docs

A Better Way to Integrate with the Microsoft Exchange API

Integrating with EAS can take as long as 6 months or more, and the ongoing maintenance and support costs increase over time as your platform scales.

We built the Nylas Email API to provide a simpler way to integrate with the Exchange, Gmail, Outlook, and every other email provider in the world. With Nylas, you can build full CRUD and bi-directional sync between your app and 100% of email service providers in the world.

The Nylas API is built for developers first. We support three major SDK languages to help make your EAS integration as simple as possible.

Try the Nylas API today – create an account and sync up to 5 accounts for free here!

Related resources

How to create and read Google Webhooks using Ruby

Create and read your Google webhooks using Ruby and Sinatra, and publish them using Koyeb. Here’s the full guide.

Nylas’ 2024 predictions: Navigating AI, connectivity, and the future of work

Explore the transformative impact of AI, the evolution of global connectivity, and the reshaping of workplace culture in the digital era in Nylas’ 2024 predictions.

Grouping email threads with Ruby and Nylas

Use the Nylas Email API and Ruby to group email threads into a single view, and easily access complete conversations within your app.