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?
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With