Get incremental changes to messages in a folder

Delta query lets you query for additions, deletions, or updates to messages in a folder, by way of a series of delta function calls. Delta data enables you to maintain and synchronize a local store of a user's messages, without having to fetch the entire set of the user's messages from the server every time.

Delta query supports both full synchronization that retrieves all of the messages in a folder (for example, the user's Inbox), and incremental synchronization that retrieves all of the messages that have changed in that folder since the last synchronization. Typically, you would do an initial full synchronization of all the messages in a folder, and subsequently, get incremental changes to that folder periodically.

Track message changes in a folder

Delta query is a per-folder operation. To track the changes of the messages in a folder hierarchy, you need to track each folder individually.

Tracking message changes in a mail folder typically is a round of one or more GET requests with the delta function. The initial GET request is very much like the way you get messages, except that you include the delta function:

GET https://graph.microsoft.com/v1.0/me/mailFolders/{id}/messages/delta

A GET request with the delta function returns either:

  • A nextLink (that contains a URL with a delta function call and a skipToken), or
  • A deltaLink (that contains a URL with a delta function call and deltaToken).

These tokens are state tokens that are completely opaque to the client. To proceed with a round of change tracking, simply copy and apply the URL returned from the last GET request to the next delta function call for the same folder. A deltaLink returned in a response signifies that the current round of change tracking is complete. You can save and use the deltaLink URL when you begin the next round.

See the example below to learn how to use the nextLink and deltaLink URLs.

Use query parameters in a delta query for messages

  • You can use a $select query parameter as in any GET request to specify only the properties your need for best performance. The id property is always returned.
  • Delta query support $select, $top, and $expand for messages.
  • There is limited support for $filter and $orderby:
    • The only supported $filter expresssions are $filter=receivedDateTime+ge+{value} or $filter=receivedDateTime+gt+{value}.
    • The only supported $orderby expression is $orderby=receivedDateTime+desc. If you do not include an $orderby expression, the return order is not guaranteed.
  • There is no support for $search.

Optional request header

Each delta query GET request returns a collection of one or more messages in the response. You can optionally specify the request header, Prefer: odata.maxpagesize={x}, to set the maximum number of messages in a response.

Example to synchronize messages in a folder

The following example shows a series of 3 requests to synchronize a specific folder which contains 5 messages:

See also what you'll do in the next round.

Sample initial request

In this example, the specified folder is being synchronized for the first time, so the initial sync request does not include any state token. This round will return all the messages in that folder.

The first request specifies the following:

  • A $select parameter to return the Subject and Sender properties for each message in the response.
  • The optional request header, odata.maxpagesize, returning 2 messages at a time.
GET https://graph.microsoft.com/v1.0/me/mailfolders('AQMkADNkNAAAgEMAAAA')/messages/delta?$select=Subject,Sender HTTP/1.1
Prefer: odata.maxpagesize=2

Sample initial response

The response includes two messages and an @odata.nextLink response header. The nextLink URL indicates there are more messages in the folder to get.

{
    "@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(message)",
    "@odata.nextLink":"https://graph.microsoft.com/v1.0/me/mailfolders('AQMkADNkNAAAgEMAAAA')/messages/delta?$skiptoken=GwcBoTmPuoTQWfcsAbkYM",
    "value":[
        {
            "@odata.type":"#microsoft.graph.message",
            "@odata.etag":"W/\"CQAAABYAAAARn2vdzPFjSbaPPxzjlzOTAAASsKZz\"",
            "subject":"Holiday hours update",
            "sender":{
                "emailAddress":{
                    "name":"Dana Swope",
                    "address":"danas@contoso.onmicrosoft.com"
                }
            },
            "id":"AAMkADNkNAAASq35xAAA="
        },
        {
            "@odata.type":"#microsoft.graph.message",
            "@odata.etag":"W/\"CQAAABYAAAARn2vdzPFjSbaPPxzjlzOTAAAEfYB/\"",
            "subject":"Holiday promotion sale",
            "sender":{
                "emailAddress":{
                    "name":"Fanny Downs",
                    "address":"fannyd@contoso.onmicrosoft.com"
                }
            },
            "id":"AQMkADNkNAAAVRMKAAAAA=="
        }
    ]
}

Sample second request

The second request specifies the nextLink URL returned from the previous response. Notice that it no longer has to specify the same $select parameter as in the initial request, as the skipToken in the nextLink URL encodes and includes it.

GET https://graph.microsoft.com/v1.0/me/mailfolders('AQMkADNkNAAAgEMAAAA')/messages/delta?$skiptoken=GwcBoTmPuoTQWfcsAbkYM HTTP/1.1
Prefer: odata.maxpagesize=2

Sample second response

The second response returns the next 2 messages in the folder and another nextLink, indicating there are more messages to get from the folder.

{
    "@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(message)",
    "@odata.nextLink":"https://graph.microsoft.com/v1.0/me/mailfolders('AQMkADNkNAAAgEMAAAA')/messages/delta?$skiptoken=GwcBoTmPKILK4jLH7mAd1lLU",
    "value":[
        {
            "@odata.type":"#microsoft.graph.message",
            "@odata.etag":"W/\"CQAAABYAAAARn2vdzPFjSbaPPxzjlzOTAAAEfYB+\"",
            "subject":"New or modified user account information",
            "sender":{
                "emailAddress":{
                    "name":"Randi Welch",
                    "address":"randiw@contoso.onmicrosoft.com"
                }
            },
            "id":"AQMkADNkNAAAgWJAAAA"
        },
        {
            "@odata.type":"#microsoft.graph.message",
            "@odata.etag":"W/\"CQAAABYAAAARn2vdzPFjSbaPPxzjlzOTAAAEfYB9\"",
            "subject":"New or modified user account information",
            "sender":{
                "emailAddress":{
                    "name":"Randi Welch",
                    "address":"randiw@contoso.onmicrosoft.com"
                }
            },
            "id":"AQMkADNkNAAAgWHAAAA"
        }
    ]
}

Sample third request

The third request continues to use the latest nextLink URL returned from the last sync request.

GET https://graph.microsoft.com/v1.0/me/mailfolders('AQMkADNkNAAAgEMAAAA')/messages/delta?$skiptoken=GwcBoTmPKILK4jLH7mAd1lLU HTTP/1.1
Prefer: odata.maxpagesize=2

Sample third and final response

The third response returns the only remaining message in the folder, and a deltaLink URL which indicates synchronization is complete for the time being for this folder. Save and use the deltaLink URL to synchronize the same folder in the next round.

{
    "@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(message)",
    "@odata.deltaLink":"https://graph.microsoft.com/v1.0/me/mailfolders('AQMkADNkNAAAgEMAAAA')/messages/delta?$deltatoken=GwcBoTmPuoGNlgXgF1nyUNMXY",
    "value":[
        {
            "@odata.type":"#microsoft.graph.message",
            "@odata.etag":"W/\"CQAAABYAAAARn2vdzPFjSbaPPxzjlzOTAAAEfYB8\"",
            "subject":"You've joined the Customer Manager group",
            "sender":{
                "emailAddress":{
                    "name":"Customer Managers team",
                    "address":"customer_managers@contoso.onmicrosoft.com"
                }
            },
            "id":"AQMkADNkNAAAgWFAAAA"
        }
    ]
}

The next round

Using the deltaLink from the last request in the last round, you will be able to get only those messages that have changed (by being added, deleted, or updated) in that folder since then. Your first request in the next round will look like the following, assuming you prefer to keep the same maximum page size in the response:

GET https://graph.microsoft.com/v1.0/me/mailfolders('AQMkADNkNAAAgEMAAAA')/messages/delta?$deltatoken=GwcBoTmPuoGNlgXgF1nyUNMXY HTTP/1.1
Prefer: odata.maxpagesize=2

See also