4

I want to automate Outlook so that I can download the "pieces parts" of email messages so that I can tie related messages together. I understand that email usually has a "MessageID" to serve this purpose, so that emails can be viewed in context, as "threads" in a newsreader are tied together.

Does Outlook have the notion of "Message IDs" in emails sent with it? I see that the elements that can be extracted (using automation) are Subject, SenderEmail, CreationTime, Body, SenderName, and HTMLBody. Is a "message id" or equivalent available somewhere, too?

B. Clay Shannon-B. Crow Raven
  • 8,547
  • 144
  • 472
  • 862
  • I always thought that Outlook did this by the email subject since when you go to 'find related messages' it just looks in the subject of emails – Charleh Aug 08 '12 at 08:28
  • I did a quick search - maybe this might help: http://www.pcreview.co.uk/forums/do-get-mail-items-messageid-t2968634.html – Bridge Aug 08 '12 at 08:29
  • @Charleh - Subject would work most of the time, but not always, as sometimes people change the subject - especially when the direction of the conversation has shifted. – B. Clay Shannon-B. Crow Raven Aug 08 '12 at 08:43
  • @Bridge: I think it's Outlook 2003 (I'm not at work now, as it's 2 a.m., but I'm pretty sure that's the version. Also: thanks for the link; it looks like "Subject" will have to suffice. – B. Clay Shannon-B. Crow Raven Aug 08 '12 at 08:47
  • @ClayShannon I _think_ (my experience is more with `SMTPClient` than Outlook interop) that Exchange server might set a different MessageID before it goes off "out into the world" anyway - but I'm no expert on that side of things I'm afraid! – Bridge Aug 08 '12 at 08:54
  • @Bridge: Yes, I verified it's Outlook 2003. – B. Clay Shannon-B. Crow Raven Aug 08 '12 at 16:13
  • 1
    If you are interested please commit for this :http://stackoverflow.com/documentation/outlook-addin/commit – Kushan Randima Jul 28 '16 at 04:35

2 Answers2

7

Outlook tracks related messages by using Conversations.

In Outlook 2003, there is ConversationTopic (MAPI: PR_CONVERSATION_TOPIC) & ConversationIndex (MAPI: PR_CONVERSATION_INDEX). ConversationTopic is typically the message subject (minus prefixes - RE:/FW:, etc.), while ConversationIndex represents the sequential ordering of the ConversationTopic (essentially GUID + timestamp). See Working with Conversations on MSDN. ConversationIndex is explicitly defined on MSDN here.

In Outlook 2010, they added ConversationID (MAPI: PR_CONVERSATION_ID) which is derived from the ConversationTopic. ConversationID can be generated from the ConversationTopic as discussed here.

For more detailed info about the MSG protocol specs regarding Conversations see [MS-OXOMSG]: E-Mail Object Protocol Specification, section 2.2.1.2 and 2.2.1.3.

SliverNinja - MSFT
  • 31,051
  • 11
  • 110
  • 173
2

Small addition to previous great answer. In case if anyone else will also need C# implementation of algorithm used to retrieve ConversationID from ConversationIndex/ConversationTopic:

private const int c_ulConvIndexIDOffset = 6;
private const int c_ulConvIndexIDLength = 16;

private string GetConversationId()
        {
            var convTracking = GetMapiPropertyBool(PR_CONVERSATION_INDEX_TRACKING);
            var convIndex = GetMapiPropertyBytes(PR_CONVERSATION_INDEX);
            byte[] idBytes;
            if (convTracking
                && convIndex != null
                && convIndex.Length > 0)
            {
                // get Id from Conversation index
                idBytes = new byte[c_ulConvIndexIDLength];
                Array.Copy(convIndex, c_ulConvIndexIDOffset, idBytes, 0, c_ulConvIndexIDLength);
            }
            else
            {
                // get Id from Conversation topic
                var topic = GetMapiPropertyString(PR_CONVERSATION_TOPIC);
                if (string.IsNullOrEmpty(topic))
                {
                    return string.Empty;
                }

                if (topic.Length >= 265)
                {
                    topic = topic.Substring(0, 256);
                }
                topic = topic.ToUpper();

                using (var md5 = new System.Security.Cryptography.MD5CryptoServiceProvider())
                {
                    idBytes = md5.ComputeHash(Encoding.Unicode.GetBytes(topic));
                }
            }

            return BitConverter.ToString(idBytes).Replace("-", string.Empty);
        }

GetMapiProperty...() is a helper functions which just retrieve required MAPI property and cast result to appropriate managed type

Woodman
  • 1,108
  • 9
  • 11