OfficeDev / office-js-docs-reference

Microsoft Office JavaScript API Reference
https://learn.microsoft.com/javascript/api/overview
MIT License
105 stars 63 forks source link

Incomplete and incorrect information on new `inReplyTo` property of `Office.MessageCompose` #1985

Open cut2run opened 2 days ago

cut2run commented 2 days ago

We are trying to use the new inReplyTo property of Office.MessageCompose interface. While the documentation describes it as ...

Gets the message ID of the original message being replied to by the current message.

It is absolutely unclear for a reader that the "message ID" is NOT the itemId of the original message the user is replying to. We all use to operate with itemId under Office.js API and this is what comes into mind when you read the description. We have to put efforts into investigating what exactly inReplyTo property holds related to the "original message". And this is one more unclear piece. When you read the description of the provided example, you have the mentioned ...

gets the ID of the message being replied to by the current message (PR_IN_REPLY_TO_ID)

But why would I care about PR_IN_REPLY_TO_ID in the current message if most of the time ppl need to get their hands on the "original message", for example, check if the "original message" has an attachment and do something to newly compose message? To make such a discovery you would use inReplyTo property value as the search for the original message. How would you do this? Ah, actually you have to use PR_INTERNET_MESSAGE_ID_W (0x1035001F) of the "original message" and there is nothing about it in the documentation, not even mention. What if some developer doesn't have OutlookSpy to look at all this information? In this case, this developer never will figure out how to use this ID. I don't want to tell you what to write, but as the reader of the documentation I would have less questions if the description at least mention that the inReplyTo property holds "internet message ID of the original message" and to find out information on the original message you require find EWS request for named PR_INTERNET_MESSAGE_ID_W property or Graph request with filter on internetMessageId, similar to ...

https://graph.microsoft.com/v1.0/me/messages?$filter=internetMessageId eq '<333333333333333333@333333333.PROD.OUTLOOK.COM>'

Next, the documentation stated ...

The inReplyTo property returns null for new or forwarded messages.

When I do forward on a message and check inReplyTo property, its still holds the internet message ID of the original message. I have tested it only on Outlook Web. Is this statement correct?

And finally, this is not related to the documentation, but maybe at least you will be able to clarify what I can do with inReplyTo property value. As I mentioned we would like to get our hands on the original message during the reply event. We've got this ID, but by definition it is not unique and when we make the search on the original item we may get more than one message in return (for example when the user includes himself and has the message in "sent items" and "Inbox" folders). How would I know which message the user is composing the reply for? From "Inbox" or from "Sent Items"? It is not clear what was your use case for the property and why did you settle on "internet message ID", which is not unique vs. itemId of the message the user is replying to?

Thanks.

AlexJerabek commented 2 days ago

Hi @cut2run,

Thanks for raising these design questions. Let me assign @samantharamon to help address them.

samantharamon commented 2 days ago

Hi @cut2run,

Thanks for reaching out about the inReplyTo property.

I created PR #69976 to correct the scenarios where null is returned.

Regarding your other queries, I'll discuss this further with the team, so that we can clarify our documentation. I'll let you know once I have more information to share.

cut2run commented 1 day ago

Thanks @samantharamon for looking at this matter. While you mentioned you will be talking to the team, I have one more question to clarify. I mentioned in the description that we can use the value of the property in the Graph request with the filter, and the example I have provided would return the messages with this "internet message ID" through the entire Mailbox, After I have to figure out somehow what message the user really composing reply to. This is unknown and I am not sure what to do with this yet. At the same time, if I use EWS find request, things are much worth, I MUST specify the folder name in the request. There is no find for the entire Mailbox. This becomes complicated on its own. So I have to use the inReplyTo property in the find EWS request, but before that, I have to make an additional request to find out about Mailbox folders tree, triverse through them to get the name and type each of them and after use them with my find request. The user may have hundreds of folders where the incoming messages are going by the rules, so I need to get all those folders, including "well known" before even creating the find EWS request. Our add-on is still based on EWS requests (we didn't move yet to Graph and this work is just scheduled for us in a year or so) so EWS is exactly our case. The question is, maybe I missed something and there is a simple way I can approach with? The solution I described is based on @GlenScales recommendations I found through my R&D and he is probably the most knowledgeable in EWS world who offers help to the community time to time. But I might be wrong and would like you at least to confirm that this was the intentional use case for inReplyTo property; this is how you designed to use this property value.

gscales commented 1 day ago

There is no find for the entire Mailbox.

For this there is one approach you could use, there is an AllItems search folder (which is pretty much what /messages is in the Graph) that will allow you to search across all folders in a mailbox. It is a DistinguishedFolderId/wellknowfolder but not documented or included in the EWS Managed API but you can get it like eg

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

AllProperties
cut2run commented 16 hours ago

Thanks, @gscales and finally nice to meet you. Always use your suggestions from many years back and finally the direct answer on my own question. I can confirm the find query works with <t:DistinguishedFolderId Id="allitems"/>. A bit scary "it is not documented", but I believe it will work, at least till the moment we will make our move to Graph. So my EWS query becomes more elegant ...

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2010"/>
  </soap:Header>
  <soap:Body>
    <FindItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages"
               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
              Traversal="Shallow">
      <ItemShape>
        <t:BaseShape>IdOnly</t:BaseShape>
      </ItemShape>
<Restriction>
<t:IsEqualTo>
<t:FieldURI FieldURI="message:InternetMessageId" />
<t:FieldURIOrConstant>
<t:Constant Value="&lt;333333333333333@33333333333333333.OUTLOOK.COM&gt;" />
</t:FieldURIOrConstant>
</t:IsEqualTo>
</Restriction>
      <ParentFolderIds>
        <t:DistinguishedFolderId Id="allitems"/>
      </ParentFolderIds>
    </FindItem>
  </soap:Body>
</soap:Envelope>

With the result of ...

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types" Version="V2018_01_08" MinorBuildNumber="26" MajorBuildNumber="7741" MinorVersion="20" MajorVersion="15"/>
</s:Header>
<s:Body>
<m:FindItemResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages">
<m:ResponseMessages>
<m:FindItemResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:RootFolder IncludesLastItemInRange="true" TotalItemsInView="2">
<t:Items>
<t:Message>
<t:ItemId ChangeKey="CQAAABYAAACRQk9bS2HYQbCNdh4roBZJAAhaLF+5" Id="AQMkADg0ZDZhNWFiLWE0Y2EtNDc4My05MGU1LTY5ZWNiOTQ5MmY5YwBGAAADEgGHnGK1T06Yq8xwQCjiHwcAkUJPW0th2EGwjXYeK6AWSQAAAgEMAAAAkUJPW0th2EGwjXYeK6AWSQAIWZAiNgAAAA=="/>
</t:Message>
<t:Message>
<t:ItemId ChangeKey="CQAAABYAAACRQk9bS2HYQbCNdh4roBZJAAhV+AoT" Id="AQMkADg0ZDZhNWFiLWE0Y2EtNDc4My05MGU1LTY5ZWNiOTQ5MmY5YwBGAAADEgGHnGK1T06Yq8xwQCjiHwcAkUJPW0th2EGwjXYeK6AWSQAAAgEJAAAAkUJPW0th2EGwjXYeK6AWSQAIIU4X0wAAAA=="/>
</t:Message>
</t:Items>
</m:RootFolder>
</m:FindItemResponseMessage>
</m:ResponseMessages>
</m:FindItemResponse>
</s:Body>
</s:Envelope>

As you may notice, I have 2 messages that meet my "internet message ID". Is there any <t:AdditionalProperties> I am able to add to understand which message the user is replying to? Any suggestions? I have a couple of thoughts, for example, just take the first in the list or the latest from "createdDateTime" or "lastModifiedDateTime", etc., but all of them have nothing to do with the actual message the user is replying to (click "reply"). All my thoughts can be implemented easily, but wrong and I am looking for an advise.

gscales commented 4 hours ago

It depends on what environments your operating in because you may find that different email clients and MTA's will implement how they deal with these properties differently. Generally you would start with the rfc properties https://www.ietf.org/rfc/rfc2822.txt because every client should follow these rules. So you have the InternetMessageid, In-Reply-To and References all these properties are "Should" vs Must so not 100% but it pretty rare for clients not to use them, the In-Reply-to gives you the Internet messageId of the message being replied to. If that is what your above search is based on and you see two copies it could be they where the original sender but they have also received a copy of the message they sent so one in the Inbox and one in the SentItems folder (or they just copied the message with a drag and drop). You shouldn't see the two different messages with the same InternetMessageId unless some client or process is doing something it shouldn't. So you would probably want to start with check the parent folder (exclude anything in the SentItems), https://learn.microsoft.com/en-us/office/client-developer/outlook/mapi/pidtagsearchkey-canonical-property the SearchKey can tell you if its a drag and drop copy of the message.

The References which is an rfc property as well https://learn.microsoft.com/en-us/dotnet/api/microsoft.exchange.webservices.data.emailmessage.references?view=exchange-ews-api can be helpful as well as it should contain all the InternetMessageId of messages in the thread at the time the user responded.

In a pure Exchange environment you have the Mapi properties like https://learn.microsoft.com/en-us/office/client-developer/outlook/mapi/pidtagconversationindex-canonical-property which will give you the relative position of a message in a thread. It best to take a look with a Mapi editor like mfcMapi or outlookSpy

From a reliability point of view you need to be a big algorithmic.