Share via

Microsoft Graph (Outlook mail): `createReply` flips source `isRead` to `true` after a recent application `PATCH`

Pablo Castro 40 Reputation points
2026-05-22T17:58:11.1633333+00:00

Hi,

I have observed an undocumented server-side state change in Microsoft Graph on the Outlook mail API that I would like to understand or get clarified.

What I see

When I POST to /me/messages/{id}/createReply (or createReplyAll, or createForward) on a source message whose isRead is false, the server flips isRead to true on the source message, provided the source has been PATCHed by an application (Graph application) within roughly the previous 10 minutes. If the source has not been PATCHed recently, isRead is left unchanged.

I do not write isRead anywhere in my flow. The flip is server-side and is visible to all clients that subsequently GET the message, not just the one issuing createReply. The new draft created by createReply is independent and behaves as expected; the issue is the state of the source message.

Minimal reproducer

Setup: any Outlook mailbox; an application with Mail.ReadWrite delegated permission. Graph Explorer (https://developer.microsoft.com/en-us/graph/graph-explorer) is sufficient to reproduce.

  1. Send the mailbox a fresh test message from any sender. Wait for arrival.
  2. PATCH /me/messages/{id} with body {"categories": ["TestCat"]}. Returns 200. Source state: isRead=false, categories=["TestCat"].
  3. POST /me/messages/{id}/createReply with body {}. Returns 201, new draft created.
  4. GET /me/messages/{id}. Observed: isRead=true. Expected: isRead=false.

I did not write isRead in any of the three calls.

The flip is reproducible with createReplyAll and createForward as well. It does not happen when the second leg is move, copy, or a generic POST to /me/messages. It does not happen if createReply is called on a source that has not been PATCHed in the last ~10 minutes.

I have also reproduced this via Graph Explorer (i.e. not an artifact of my own application code). I can share Microsoft Graph client-request-id values from the response headers on request.

A similar flip happens when the recent mutation on the source is an Outlook inbox-rule action (a rule that adds a categories value, for instance) instead of an application PATCH. The decay window for inbox-rule-triggered mutations is shorter (~2 to 3.5 minutes) than for application PATCHes (≥10 minutes), but the pattern is otherwise identical.

My workaround

After every reply-family POST on a source with isRead=false, I issue a follow-up PATCH /me/messages/{id} with body {"isRead": false} to restore the unread state. This works reliably (confirmed via 30s and longer follow-up GETs). But it is one extra Graph roundtrip per reply, and I am not sure it is the intended pattern.

Questions

  1. Is this documented behavior of createReply / createReplyAll / createForward with respect to the source message's isRead state, and if so, is the follow-up restore PATCH the recommended pattern? I could not find this side effect documented in the reference for these endpoints (https://dotnet.territoriali.olinfo.it/en-us/graph/api/message-createreply etc.).
  2. Is there a request header or Prefer value I can set to opt out of this server-side state change? (I checked the standard Prefer: outlook.body-content-type, Prefer: IdType, etc. and none seemed relevant.)

Happy to provide client-request-id values or further repros. Thanks!

Microsoft 365 and Office | Development | Other
0 comments No comments

Answer accepted by question author

Hin-V 14,925 Reputation points Microsoft External Staff Moderator
2026-05-22T20:12:41.63+00:00

Hi @Pablo Castro

Thank you for reaching out. 

First, I’d like to clarify that this is a user‑to‑user support forum. Moderators participating here do not have access to backend systems, nor can we directly intervene in Microsoft product functionality. Our role is limited to providing technical guidance and sharing best‑practice recommendations based on reported issues, requests, and scenarios.      

Currently, I have not identified any official documentation that explains this behavior yet. Based on my current understanding, the isRead property appears to be updated as a result of internal server-side processing within Exchange Online, rather than through any direct modification in the API request.

In this scenario, when a message is recently modified, it may be temporarily treated by the service as an item that has been actively processed or engaged with. If a reply action (such as, createReply, createReplyAll, or createForward) is performed shortly afterward, the service may interpret this as user interaction with the message and automatically update its state to read. 

Additionally, there is currently no request header or Prefer option available in Microsoft Graph to avoid this behavior. As far as I know, the supported Prefer headers (such as outlook.body-content-type, IdType, etc.) are limited to controlling response formatting and representation, and do not influence message state properties like isRead.  Since the isRead update in this case appears to be part of internal Exchange Online processing, it might not be controlled or disabled through request headers. 

Please note that this summary is based on my own findings and may not fully address your concerns. To help you reach your goal more effectively, I recommend engaging with [GitHub Community Forum] for a deeper technical dive or to connect with individuals who have relevant experience and expertise. Some approaches may behave differently or be restricted depending on your specific environment and configuration. These forums include many experienced developers and Microsoft specialists who can assist with troubleshooting and guidance.     

I hope this helps. 

If you have any additional concerns, feel free to comment below. I would be more than happy to assist. 


Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread. 

Was this answer helpful?

1 person found this answer helpful.

Answer accepted by question author

AI answer

2026-05-22T17:58:36.3366667+00:00

The behavior described is not documented in the provided references for createReply, createReplyAll, createForward, or reply, and there is no mention of any server-side change to the source message’s isRead property when these APIs are called.

From the available documentation:

  • message: createReply and message: createReplyAll are documented as operations that create a draft reply or reply-all message. They:
    • Require Mail.ReadWrite permission.
    • Do not require a request body (unless using MIME content).
    • Return a new message draft with 201 Created.
    • Do not list any side effects on the source message’s properties, including isRead.
  • message: reply is documented as an operation that sends a reply and requires Mail.Send. It also does not document any change to the source message’s isRead state.
  • The known issues section for Mail and for createReply/createReplyAll only calls out that the comment parameter is not part of the response draft body; there is no mention of isRead changes or any opt-out header.

Based on the provided context, the following can be stated:

  1. There is no documentation here that createReply, createReplyAll, or createForward change the source message’s isRead property, nor that such behavior is conditional on a recent PATCH or rule-triggered mutation.
  2. No header or Prefer value is documented that controls or disables any change to isRead for these APIs.
  3. The workaround of issuing a follow-up PATCH /me/messages/{id} with {"isRead": false} is consistent with the documented capabilities of the message resource and Mail.ReadWrite permission, but it is not described as a recommended or required pattern in the referenced documentation.

Because the provided material does not describe this isRead flip, it cannot be confirmed as intended or supported behavior, and no official opt-out mechanism is documented in the referenced content.


References:

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

Was this answer helpful?

1 person found this answer helpful.

0 additional answers

Sort by: Most 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.