Share via

Intermittent ErrorItemNotFound on message/attachment GET after change notifications (async)

Ganesh 0 Reputation points
2026-04-15T11:37:12.2733333+00:00

We use Microsoft Graph to read Outlook messages and attachments in an async integration (processing runs after Microsoft Graph change notifications, e.g. AWS Lambda / SQS).

We resolve the message and attachments roughly like this:

// After we receive a notification with a resource id, we fetch the message:
var message = await graphClient.Users[userEmail].Messages[messageId].GetAsync();

// We list attachments, then fetch a specific attachment:
var attachments = await graphClient.Users[userEmail].Messages[messageId].Attachments.GetAsync();
var attachment = await graphClient.Users[userEmail].Messages[messageId].Attachments[attachmentId].GetAsync();

Equivalent REST calls:

GET /v1.0/users/{id}/messages/{message-id}
GET /v1.0/users/{id}/messages/{message-id}/attachments/{attachment-id}

The issue is

We obtain messageId (and attachmentId when listing attachments) from Graph during processing. Intermittently, a later GET returns ErrorItemNotFound for that same id. The same request may succeed in Graph Explorer or on retry after a delay, which does not match stable “store this id forever” behavior for async jobs.

Additionally: a customer may copy an attachment id from Graph Explorer, but CloudWatch logs for our pipeline often show a different attachment id (or no attachment id) for the same message — messageId may align, attachmentId may not — so we cannot reconcile Explorer vs our logs.

Expected behavior

messageId and attachmentId returned by Graph should remain valid for GET for long enough or Microsoft should document when ids can change and what async integrators must persist instead (e.g. refetch, internetMessageId, or other supported pattern).

How to reproduce

Intermittent.

References (optional) Stack Overflow: MS Graph message API attachment id changed Stack Overflow: Item ids and attachment ids that change

SDK Version Microsoft.Graph: 5.5.6/5.5.7

Microsoft Security | Microsoft Graph

1 answer

Sort by: Most helpful
  1. AI answer

    2026-04-15T11:37:33.17+00:00

    Microsoft Graph does not guarantee that message or attachment IDs remain stable and immediately resolvable in all scenarios, especially around recent changes and synchronization.

    From the provided context, the supported and documented pattern for reliably accessing attachments is:

    1. Ensure the item is saved and fully available in the mailbox store.
      • For compose scenarios, the item must be saved first to obtain a valid item ID:
             Office.context.mailbox.item.saveAsync((result) => {
                 if (result.status === Office.AsyncResultStatus.Failed) {
                     console.error(result.error.message);
                     return;
                 }
             
                 const itemId = result.value;
             });
        
      • When Outlook is in cached mode, there can be a delay before the saved item is synced to the server. Until the item is synced, using the item ID can return an error:

        If your Outlook client is in cached mode, it may take some time for the saved item to sync to the server. Until the item is synced, using the item ID will return an error.

      The same principle applies to async processing triggered by change notifications: immediately after a change, the item or its attachments may not yet be fully available in the backend store that serves Graph, which can result in intermittent ErrorItemNotFound. A later retry can succeed once synchronization completes.
    2. Use the message and attachment IDs with Microsoft Graph only after they are available.
      • Once a valid item ID is obtained and the item is synced, attachments can be retrieved via Microsoft Graph using the documented GET patterns, for example:
             GET https://graph.microsoft.com/v1.0/me/messages/{message-id}/attachments/{attachment-id}
        
      • The same pattern is used across SDKs (C#, Java, JavaScript, Python, PowerShell) as shown in the Get attachment examples:
             var result = await graphClient.Me.Messages["{message-id}"].Attachments["{attachment-id}"].GetAsync();
        
             let attachment = await client
               .api('/me/messages/AAMkAGUzY5QKjAAA=/attachments/AAMkAGUzY5QKjAAABEgAQAMkpJI_X-LBFgvrv1PlZYd8=')
               .get();
        
    3. For on-premises Exchange, use the callback token and EWS to fetch attachments.
      • In Exchange on-premises environments, the recommended pattern is:
        1. Get a callback token from Exchange.
        2. Send the callback token and attachment information to a remote service.
        3. Use ExchangeService.GetAttachments or the GetAttachment operation to retrieve attachments.

    Given the above, for an async pipeline that processes change notifications:

    • Intermittent ErrorItemNotFound after a notification is consistent with the documented behavior that items may not yet be fully synced/available when first accessed.
    • A robust integration must:
      • Implement retry with backoff when ErrorItemNotFound is returned for a message or attachment just after a change notification.
      • Treat message and attachment IDs as valid only once the underlying item is fully available; immediate use after notification can fail transiently.

    The context does not provide an alternative identifier (such as internetMessageId) or a different persistence pattern beyond using the item ID once the item is synced. The supported guidance is to:

    • Obtain the item ID from Outlook/Exchange once the item is saved.
    • Allow for synchronization delay (especially with cached mode or shortly after changes).
    • Use the documented Graph GET endpoints and implement retries for transient ItemNotFound errors.

    References:

    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.