A deeper look at Immutable Id's in the Microsoft Graph around Email
An ItemId is the critical property (or string) that you need to access any particular item from an Exchange Mailbox via the Graph or any of the Exchange API's. You may hear about a number of different Id’s around Exchange API’s like
Pr_EntryId (or pidTagEntryId)
ewsId
restId
Mid
LongTermEntryId
Pr_SourceKey (or PidTagSourceKey)
Pr_SearchKey
PidLidGlobalObjectId
Some of these Id’s can be used to bind or Get an Exchange Item directly like PR_EntryId in MAPI or ewsId in EWS or the restId/GraphId in the Graph API. One problem with all of these Id properties is if the underlying message is moved in a Mailbox they all change (with the exception of the Pr_SearchKey) so if you have stored them externally in a database for example your item references then becomes invalid.
Objects (Email, Contacts, Meetings, etc) in Exchange are stored in the Exchange Database (EDB - Extensible Storage Engine) in collections of B+ trees (balanced trees). In B-Trees the data (eg the object) is stored in the leaf nodes and these Id’s are basically the way in which the server will navigate to the leaf node and return the object in the most I/O efficient manner. This is a bit of an over simplistic explanation the actually low level mechanics of this aren’t documented (outside of the sysadmin view) and schema’s change (and memory caches) have occurred between exchange versions to make this all more efficient and robust.
What you can say for sure is the Immutable Id's are a way of getting to that Leaf node where the data for the object is stored and these Id’s don’t change as the Item moves through the mailbox. Is there a performance penalty in using Immutable Id's ? this is a good question the id’s themselves are smaller then the equivalent Id in EWS or the Regular Graph restid, but what happens at the I/O level on the Mailbox Server to get the leaf node is a bit opaque.
Looking at the Id itself
If I have a ImmutableId like this in Base64url
AAkALgAAAAAAHYQDEapmEc2byACqAC-EWg0AdRBH-RjqME2dQLFCi6wg0AAJW7_tMQAA
This will look like the following if I convert it to hexadecimal format
0009002e00000000001d840311aa6611cd9bc800aa002f845a0d00751047f918ea304d9d40b1428bac20d000095bbfed310000
If it take the PR_SourceKey property value from the same message and covert that to hex it returns
751047fd18ea304d9d40b1428bac20d000095bbd8e4b
The PidtagSourceKey property is documented and uses the Xid Structure https://learn.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcfxics/49eeaced-e393-46cd-97b1-d31d026e56e6 so in this example
So the “Global Identifier Structure” https://learn.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcdata/eab975da-1ac2-4799-bf34-56030b3154b5 in this example
751047fd18ea304d9d40b1428bac20d0 is the DatabaseGuid (16 bytes) and
00009 is the GlobalCounter (6 bytes)
which means in the Xid Structure
5bbd8e4b is the localId
When you move an Item between folders in a Mailbox the PidtagSourceKey does change but what changes is the localId relative to the folder that you moved the object to.
Another property that uses the same Xid Structure is the pidtagchangekey for an Item which changes when an item is updated. eg the changekey for the same item look like
751047fd18ea304d9d40b1428bac20d0000959597ae1
From this you can see it has the same “Global Identifier Structure” with a different LocalId.
Back to ImmutableId’s if I now pull an ImmutableId for a Mailbox in a different tenant (and a different geographically m365 region) I get
0009002e00000000001d840311aa6611cd9bc800aa002f845a0d00bbf771c7d460da438cc2fc10e7c5594b00042b6295b20000
compare it to the other ImmutableId
0009002e00000000001d840311aa6611cd9bc800aa002f845a0d00751047f918ea304d9d40b1428bac20d000095bbfed310000
You can see that
0009002e00000000001d840311aa6611cd9bc800aa002f845a0d00 is some type of namespace that seems to be always the same and everything after that is Xid Structure (same as the Sourcekey and changekey with the same Global Identifier Structure for the mailbox ) where when you move an item in a Mailbox the LocalId doesn’t change.
Note the last 0000 is just padding
Why is this all important ? when you get into a more deeper forensic type analysis of email its something that could potentially be used in versioning. Eg in the normal course of events the localid should be incremental meaning that newer objects should have a high iteration than older objects and that objects that are around the same age should have globalid’s with a closer proximity. Also if you are going to store this Id’s it good to know a least a little bit more about their format.