Try Using Graph to solve both problems.
Get only the new text
Ask Graph for uniqueBody, not body. Outlook computes it for you.
Endpoint
GET https://graph.microsoft.com/v1.0/me/messages/{message-id}?$select=uniqueBody
Add header: Prefer: outlook.body-content-type="text" (or "html").
In Power Automate: after the trigger, use HTTP with OAuth to call the endpoint above. Store uniqueBody.content.
Get IDs of previous messages in the same thread
Use these fields:
internetMessageId: the RFC 5322 Message-ID of the current email.
internetMessageHeaders: contains In-Reply-To and References which list parent and ancestor Message-IDs.
conversationId: a single thread ID. Useful to group, not to order.
conversationIndex (extended property): encodes the thread tree and order.
Practical calls
Current message basics + headers:
GET /v1.0/me/messages/{message-id}
?$select=internetMessageId,conversationId,createdDateTime
&$expand=internetMessageHeaders
Parse headers:
In-Reply-To: parent Message-ID (one value)
References: space-separated list of ancestor Message-IDs
Add conversationIndex via extended properties:
GET /v1.0/me/messages/{message-id}
?$select=internetMessageId,conversationId,createdDateTime
&$expand=singleValueExtendedProperties($filter=id eq 'Binary 0x0071')
Binary 0x0071 = MAPI PidTagConversationIndex.
How to use them
To check if a prior mail exists in your DB:
Read In-Reply-To and References.
Look up each Message-ID.
To get all messages in the same conversation:
Query GET /v1.0/me/messages?$filter=conversationId eq '{convId}'&$select=id,internetMessageId,receivedDateTime
Optionally also fetch conversationIndex for ordering.
conversationIndex: what it is and why it helps
Binary value built at the root message, then extended by each reply.
First 22 bytes identify the root. Each reply appends a 5-byte “node” with a time delta.
Messages in the same conversation share the same 22-byte prefix. Branches (sub-threads) diverge where their indices first differ.
Sorting by conversationIndex gives parent-before-child ordering without scanning headers.
Distinguishing sub-threads: messages that share the same prefix length are on the same path; when the prefix differs at some node, they belong to different branches.
You do not have to decode the binary to use it:
For ordering: sort lexicographically by the base64 string that Graph returns for Binary 0x0071.
For branch detection: compare common prefix length of the base64 strings.
Power Automate wiring (outline)
Trigger: When a new email arrives (V3) → gives you the Graph message-id (the Outlook item id).
Action: HTTP (use the Outlook connection token)
Call #1: .../messages/{id}?$select=uniqueBody → save uniqueBody.content.
Call #2: .../messages/{id}?$select=internetMessageId,conversationId&$expand=internetMessageHeaders,singleValueExtendedProperties($filter=id eq 'Binary 0x0071')
Parse:
internetMessageId → store as your primary key.
From internetMessageHeaders, extract In-Reply-To and References → check DB for ancestors.
From singleValueExtendedProperties[0].value (base64) → store as conversationIndex for ordering/branching.
Optional: fetch siblings in the same conversationId if you need to reconcile missing ancestors.
Notes
conversationId groups a whole conversation but does not distinguish sub-threads by itself. Use conversationIndex or headers to separate branches.
uniqueBody exists only on Outlook/Exchange messages. If mail was forwarded across systems, Outlook still computes it in most cases.
If you must store HTML and text, request both using two calls with different Prefer headers.
This setup yields:
Latest body only → uniqueBody.
Parent and ancestor IDs → In-Reply-To and References.
Reliable ordering and sub-thread detection → conversationIndex + headers.