将EWS会话*与Outlook加载项对话相匹配*

时间:2014-03-20 15:34:23

标签: exchange-server outlook-addin exchangewebservices

我几年前为Outlook编写了一个加载项,它根据Item的ConversationIndex / ConversationId属性向数据库添加条目。这很好,并且在与消息交互的所有客户端之间保持一致(例如,“Bob”可以看到“Mary”已经处理了此消息,因为已经存在ConversationIndex的条目。)

我现在正在尝试将此部分移动到服务(并通过EWS API连接),但我没有好运将这些属性与来自Outlook的值进行匹配。例如:

Outlook加载项会为我定位的特定电子邮件提供以下值:

ConversationID:     6B6369F5023EA646AA7BC161274BDAE8
ConversationIndex:  0101CF3C7EEC6B6369F5023EA646AA7BC161274BDAE8

但是,从EWS API我得到以下内容:

ConversationID:     AAQkADFhZThkNmJmLTlkODItNDQyZS1hM2YxLTQ2NWNkMTllYjhjOQAQAGtjafUCPqZGqnvBYSdL2ug=
ConversationIndex:  new byte[]{1,1,207,60,126,236,107,99,105,245,2,62,166,70,170,123,193,97,39,75,218,232}

我认为第一个是Base64编码的字符串,然而我解码的东西看起来并不像我认识的那样(或者可以解密)。有没有人熟悉这个,或谁可以帮助让这两个值对齐?我只能想象来自交换服务器的这些属性是某种方式,但客户端可能会执行一些清理,而EWS API只是给我原始值(减去Base64,因为我认为在给定XML介质的情况下运输目的)。

如果有人熟悉这个或已经做过,我会非常感谢任何指导。

旁注:

可能有更好的方法来识别电子邮件,但现在我仍然坚持尝试保持这两个同义词。修改outlook加载项实际上不是一个选项,一旦我将1:1的转换迁移到服务器(并删除加载项),我将灵活地改变它的工作方式。但是现在我需要它们并排运行。我需要能够从Web服务器中查看Outlook中的进程,反之亦然。

1 个答案:

答案 0 :(得分:3)

刚刚发现(我认为)。

击穿

随着更多谷歌搜索和更多的努力,我相信我能够使用以下内容使它们以1:1对齐:

的conversationId

这显然是由几个属性组成的组合值。幸运的是,我能够找到一种方法,Woodman发布了重新实现Outlook original algorithm使用的here的方法。通过一些小的修改(与EWS而不是Outlook一起使用),我能够让它发挥作用。

ConversationIndex

结果只是使用BitConverter(并删除连字符)。容易腻。

最终结果:

public static class EwsEmailMessageExtensions
{
    private const int c_ulConvIndexIDOffset = 6;
    private const int c_ulConvIndexIDLength = 16;
    private static ExtendedPropertyDefinition PidTagConversationIndexTracking = new ExtendedPropertyDefinition(0x3016, MapiPropertyType.Boolean);

    // HUGE props to Woodman
    // https://stackoverflow.com/a/21625224/298053
    public static string GetOutlookConversationId(this EmailMessage emailMessage)
    {
        Boolean convTracking;
        if (!emailMessage.TryGetProperty(PidTagConversationIndexTracking, out convTracking))
        {
            convTracking = true;
        }

        var convIndex = emailMessage.ConversationIndex;
        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 = emailMessage.ConversationTopic;
            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);
    }

    public static String GetOutlookConversationIndex(this EmailMessage emailMessage)
    {
        var convIndex = emailMessage.ConversationIndex;
        return BitConverter.ToString(convIndex).Replace("-", String.Empty);
    }
}

用法:

// Prep
ExchangeService service = new ExchangeService(...);
Folder inbox = Folder.bind(service, WellKnownFolderName.Inbox);
Item item = /* inbox.FindItems(...).First() */

// Implmentation
EmailMessage emailMessage = item as EmailMessage;
if (emailMessage != null)
{
   String conversationId = emailMessage.GetOutlookConversationId();
   String conversationIndex = emailMessage.GetOutlookConversationIndex();
   /* ... */
}