Microsoft C# Graph SDK: How to handle delta query and token for messages

So I spent two days finding out how to handle delta queries for messages in Microsoft Graph with the C# SDK. The handling of the delta token can be confusing and is not that well documented by Microsoft.

I have found an example of delta queries for Users, but it assumes that you can save both the delta link/token AND the last query’s page.

However, in my case, I want to persist the delta link/token in a database, so that the application doesn’t have to load all messages from scratch at each startup. Given that the last query is a C# object, storing it in a database is not an option, so the approach used above for the user delta query doesn’t work.

Below is a simplified example of my solution, where only the delta token needs to be kept between each refresh of mail messages. As a consequence, the delta token can be easily stored in a database table if required.

// Class to keep track of the delta tokens per folder
// Could be stored in a database to persist across application restarts
public class FolderInfo {
    public string FolderId { get; set; }
    public string MessageQueryODataDeltaLink { get; set; }

// Collection to keep track of delta tokens
private readonly Dictionary<string, FolderInfo> folderInfos = new Dictionary<string, FolderInfo>();

// Gets mail for a specific user and folder
private async Task<List<EmailInfo>> GetEmailInfo(
        GraphServiceClient graphClient,
        MailFolder mailFolder,
        User user,
        CancellationToken cancellationToken = default) {

   var emails = new List<EmailInfo>();

    // retrieve or instantiate FolderInfo for a particular folder
    FolderInfo folderInfo;
    if (!folderInfos.TryGetValue(mailFolder.Id, out folderInfo)) {
        folderInfo = new FolderInfo {
            FolderId = mailFolder.Id
        folderInfos.Add(mailFolder.Id, folderInfo);

    // If the delta token for a previous delta query exists, we add it to the query's options
    var queryOptions = new List<Option>{};
    if (folderInfo.MessageQueryODataDeltaLink != null) {
        queryOptions.Add(new QueryOption("$deltatoken", folderInfo.MessageQueryODataDeltaLink));

    // Create the delta query...
    var messagePage = await graphClient

    // Process all request pages...
    while (true) {

        // Process the messages. In my case, I convert them to my own EmailInfo class.
        foreach (var message in messagePage) {                    
            emails.Add(MessageToEmailInfo(mailFolder, user, message));

        if (messagePage.NextPageRequest != null) {
            messagePage = await messagePage.NextPageRequest
        else {

    // Retrieve and save the delta token to be used in the next delta query
    object oDataDeltaLink;
    if (messagePage.AdditionalData.TryGetValue("@odata.deltaLink", out oDataDeltaLink)) {
        string sDeltaLink                       = oDataDeltaLink.ToString();
        var deltaLinkElements                   = sDeltaLink.Split(new string[] { "$deltatoken=" }, StringSplitOptions.None);
        folderInfo.MessageQueryODataDeltaLink   = deltaLinkElements.Last();

    return emails;

Hope this helps. Good luck!

Leave a Comment

Your email address will not be published. Required fields are marked *