Converting item and folder IDs via the Graph API

In the Exchange world, items (and folders) can be represented by several different identifiers, depending on the interface used. As detailed in the documentation, those unique-valued identifiers include:

  • EwsId – the identifier returned in operations performed via the EWS API. For example, when you do a search for messages or enumerate folders in a mailbox, the object returned will return this value in the Id (UniqueId) property. Here’s how a sample value looks like:
    AAMkADQxMTViNmEzLWViNWYtNGYxNy1iNmQ2LTZmNDVhN2Q5ZDI0NQAuAAAAAABCOIqaOs9mS5duvcGwkHhzAQAg/oCKFU2uQqU6r5NcDVwAAACcapkwAAA=

    Another place where you will find the EwsId is as part of the URL when opening messages in OWA, for example:

    https://outlook.office.com/owa/sharednew@michev.info/?viewmodel=ReadMessageItem&ItemID=AAMkADQxMTViNmEzLWViNWYtNGYxNy1iNmQ2LTZmNDVhN2Q5ZDI0NQBGAAAAAABCOIqaOs9mS5duvcGwkHhzBwAg%2foCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg%2foCKFU2uQqU6r5NcDVwAAAKtgxPpAAA%3d
  • EntryId – the MAPI identifier for the item/folder, corresponding to the binary PR_ENTRYID property. The value is Base64-encoded and looks something like this:
    AAAAAEI4ipo6z2ZLl269wbCQeHMBACD+gIoVTa5CpTqvk1wNXAAAAAAAAQwAAA==
  • HexEntryId – the hex-encoded representation of the EntryID. Here’s a sample value:
    0000000042388A9A3ACF664B976EBDC1B0907873010020FE808A154DAE42A53AAF935C0D5C0000000000010C0000
  • StoreId – the Exchange store identifier, which you can find for example in the output of Get-MailboxFolderStatistics cmdlet. Among other things, this value is used for generating folder IDs for use with the targeted collection Content search functionality. Here’s a sample value:
    LgAAAABCOIqaOs9mS5duvcGwkHhzAQAg/oCKFU2uQqU6r5NcDVwAAAAAAAEMAAAB
  • OwaId – as the name suggests, used by the web client. Basically an URL-safe representation of the StoreId. A sample value looks like this:
    LgAAAABCOIqaOs9mS5duvcGwkHhzAQAg%2FoCKFU2uQqU6r5NcDVwAAAAAAAEMAAAB
  • RestId – the default format used by the Graph API. Basically an URL-safe representation of the EntryId. Here’s an example:
    AAMkADQxMTViNmEzLWViNWYtNGYxNy1iNmQ2LTZmNDVhN2Q5ZDI0NQBGAAAAAABCOIqaOs9mS5duvcGwkHhzBwAg-oCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg-oCKFU2uQqU6r5NcDVwAAAKtgxPpAAA=
  • RestImmutableEntryId – the ImmutableID format used by the Graph API. Sample string below:
    AAkALgAAAAAAHYQDEapmEc2byACqAC-EWg0AIP6AihVNrkKlOq_TXA1cAAACrYM5GAAA
  • EwsLegacyId – used by the initial EWS version and only added for completeness.

Whenever you need to convert between those values, the ConvertId method comes to help. For example, the below EWS code will convert the EwsId of an item returned via the search operation ($fiItems[0].Items[0].Id.UniqueId) to all the other Id types:

$aiItem = New-Object Microsoft.Exchange.WebServices.Data.AlternateId
$aiItem.Mailbox = "sharednew@michev.info"
$aiItem.UniqueId = $fiItems[0].Items[0].Id.UniqueId
$aiItem.Format = [Microsoft.Exchange.WebServices.Data.IdFormat]::EWSId

$aiItem.UniqueId
$exchangeService.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::EntryId)
$exchangeService.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::HexEntryId)
$exchangeService.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::StoreId)
$exchangeService.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::OwaId)

AAMkADQxMTViNmEzLWViNWYtNGYxNy1iNmQ2LTZmNDVhN2Q5ZDI0NQBGAAAAAABCOIqaOs9mS5duvcGwkHhzBwAg/oCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg/oCKFU2uQqU6r5NcDVwAAAKtgxPpAAA=


UniqueId                                                                                                                                     Mailbox               IsArchive     Format
--------                                                                                                                                     -------               ---------     ------
AAAAAEI4ipo6z2ZLl269wbCQeHMHACD+gIoVTa5CpTqvk1wNXAAAAAAAAQwAACD+gIoVTa5CpTqvk1wNXAAAAq2DE+kAAA==                                             sharednew@michev.info     False    EntryId
0000000042388A9A3ACF664B976EBDC1B0907873070020FE808A154DAE42A53AAF935C0D5C0000000000010C000020FE808A154DAE42A53AAF935C0D5C000002AD8313E90000 sharednew@michev.info     False HexEntryId
RgAAAABCOIqaOs9mS5duvcGwkHhzBwAg/oCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg/oCKFU2uQqU6r5NcDVwAAAKtgxPpAAAA                                             sharednew@michev.info     False    StoreId
RgAAAABCOIqaOs9mS5duvcGwkHhzBwAg%2FoCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg%2FoCKFU2uQqU6r5NcDVwAAAKtgxPpAAAA                                         sharednew@michev.info     False      OwaId

Now, this is all very well known. The reason for writing an article on this is the recently introduced Graph API endpoint that allows you to perform the same operation via the Graph, and in addition allows the conversion to RestId. That, and the fact that it actually helps me remember stuff, once I put it in a blog post 🙂

As with any other Graph operations, you need to run the request against the corresponding endpoint, namely /translateExchangeIds. You will need to provide a collection of identifiers to convert, and the types between the conversion should happen. Even if you have a single identifier to convert, you must provide a collection, otherwise you will get a Bad request error, so remember that. One other important thing to remember is that the Graph uses URL-safe encoding, so if you are providing an EwsId, EntryId or StoreId, you need to prepare the strings correspondingly. Finally you put it all together in as a JSON-formatted string in a POST request.

The below example takes the EntryId of the same item we used for the EWS ConvertId operation, and asks the Graph to return the EwsId. Comparing the two examples shows the exact same value, so the operation was a success. We then ask to return the ImmutableEntryId:

#Graph uses URL-safe encoding, work around it
$sourceID = ("AAAAAEI4ipo6z2ZLl269wbCQeHMHACD+gIoVTa5CpTqvk1wNXAAAAAAAAQwAACD+gIoVTa5CpTqvk1wNXAAAAq2DE+kAAA==" -replace "\+","-") -replace "/","_"
$countToReplace = ($sourceID.ToCharArray() | ? {$_ -eq "="}).Count
$sourceID = $sourceID.TrimEnd("=") + $countToReplace

$body = @{
"inputIds"= @($sourceID)
"sourceIdType"= "entryId"
"targetIdType"= "ewsId"
} | ConvertTo-Json
$res = Invoke-RestMethod -Method Post -Uri "https://graph.microsoft.com/v1.0/users/sharednew@Michev.info/translateExchangeIds" -Headers $authHeader -Verbose -ContentType "application/json" -Body $body
$res.value.targetId

$body = @{
"inputIds"= @($sourceID)
"sourceIdType"= "entryId"
"targetIdType"= "immutableEntryId"
} | ConvertTo-Json
$res = Invoke-RestMethod -Method Post -Uri "https://graph.microsoft.com/v1.0/users/sharednew@Michev.info/translateExchangeIds" -Headers $authHeader -Verbose -ContentType "application/json" -Body $body
$res.value.targetId

AAMkADQxMTViNmEzLWViNWYtNGYxNy1iNmQ2LTZmNDVhN2Q5ZDI0NQBGAAAAAABCOIqaOs9mS5duvcGwkHhzBwAg/oCKFU2uQqU6r5NcDVwAAAAAAAEMAAAg/oCKFU2uQqU6r5NcDVwAAAKtgxPpAAA=

AAAAAB2EAxGqZhHNm8gAqgAvxFoNACD-gIoVTa5CpTqvk1wNXAAAAq2DORgAAA2

As with any other Graph code, you need to provide authentication headers, the corresponding operations are skipped in the above examples. For additional details, check out the official documentation.

As a last remark, the ImmutableEntryId and RestImmutableEntryId don’t seem to be supported for Folder objects, but you should be able to run other conversion operations against folders as well.

7 thoughts on “Converting item and folder IDs via the Graph API

  1. Bruce Kao says:

    Dear Sir,
    Then, how about message-ID? Can I use Message ID to locate email? Since I want get message-ID in outlook (not OWA). And then open the email in Chrome through OWA url.

    Reply
    1. Vasil Michev says:

      Afaik that’s only available as part of the headers, so not directly exposed.

      Reply
  2. Armin Fleischmann says:

    Hi Vasil Michel

    Do you know a way to convert a HexEntryId to RestId by Graph-API without using EWS?
    I think this is missing.
    I have to convert HexEntryIds of calendar appointments provided by MAPI from Outlook to RestId to Outlook 365.

    Do you have any idea.

    Thanks for your response.

    Armin

    Reply
    1. Daniel Bäuerlein says:

      Hi Armin,

      hast du eine Möglichkeit gefunden, HexEntryIds zu RestIds ohne EWS zu konvertieren?

      Did you find a possibility to convert HexEntryIds to RestIds without the use of EWS?

      Viele Grüße / Best regards

      Daniel

      Reply
  3. SpacePope says:

    Great post!

    Wondering if it is possible to use a storeId with the translateExchangeIds endpoint. That is, use the output of Get-mailboxfolderstatistics which shows the folderID (aka storeId) and convert it to graph’s restId. Any idea if this is possible? I’ve tried several attempts but doesn’t seem storeId is supported.

    Reply
  4. Stéphane Bazin says:

    Hi Vasil Michel,

    Can you help me to solve this situation ?
    My goal is to use the datasource odata into Excel to establish a permanent connection between my excel sheet, and an Outlook folder contact.
    The connection work well for my default contact with the Ms graph URL : “https://graph.microsoft.com/v1.0/me/contacts”

    But, my goal is to target another Contacts Folder. The graph URL would become :
    “https://graph.microsoft.com/v1.0/me/contactFolder/{id}/childFolders/{id}/…/contacts”

    I got the EntryId of this folder through an Outlook VBA.
    But the datasource odata through excel doesn’t work.

    Should be a question of ID format ?
    How can I solve it ?

    Many thanks for your response.

    Stephane

    Reply

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.