【问题标题】:Only get the latest reply text in an Outlook Email using VSTO and C#仅使用 VSTO 和 C# 获取 Outlook 电子邮件中的最新回复文本
【发布时间】:2020-05-12 16:40:49
【问题描述】:

我已经浏览了许多链接,但似乎都没有工作。我的问题是,在使用 C# 和 VSTO 编写的 Outlook 加载项中,我希望将最新回复电子邮件的文本捕获到线程。

问题在于,MailItem 对象上的所有属性(例如 Body、HTMLBody 等)都提供了电子邮件的整个文本,包括过去的回复。我希望以某种方式只获得最新的文本。考虑到电子邮件中的多种语言,我需要能够做到这一点。

这是我尝试过的

  1. 在 MailEditor 上使用书签 - 似乎没有更多带有 Exchange 和 Outlook 的 _MailOriginal 书签
  2. 不知何故试图推迟 MIME 属性 - 我不知道要选择哪些属性以及如何使用它们来解析最近的文本。

【问题讨论】:

    标签: c# outlook vsto outlook-addin


    【解决方案1】:

    即使在理论上你也不能这样做:想象一个用户在消息的顶部输入(例如“见下文”),然后在下面的消息正文中插入/删除各种片段(我一直这样做)。如果字体颜色不同,你就很幸运了。

    您可以尝试将原始消息与新消息进行比较并找出差异,但这需要访问原始消息。您可以查看PR_IN_REPLY_TO_ID MAPI 属性(DASL 名称http://schemas.microsoft.com/mapi/proptag/0x1042001F)并尝试在收件箱或已发送邮件文件夹中查找原始邮件。请注意,在后一种情况下(已发送邮件文件夹),该属性可能在缓存的消息中不可用,您需要搜索该文件夹的在线版本(在 OOM 中不能这样做,您需要 C++ 中的扩展 MAPI 或任何语言的 Delphi 或 Redemption)。

    【讨论】:

    • 这实际上是一个非常好的观点。我不知道该怎么回答。我的主要问题是我需要为用户提供一项功能,让他们最终看到最后一封电子邮件和最新回复之间的差异。
    • 谢谢德米特里。请问这些 MAPI 属性的 DASL 名称是否有列表?
    • 没有这样的地图。但是您可以在 OutlookSpy (dimastr.com/outspy) 中看到 PR_xyz 及其 DALS 名称 - 选择一条消息,单击 IMessage 按钮,选择属性,查看 DASL 编辑框。
    【解决方案2】:

    Outlook 对象模型没有为此提供任何东西。您需要自己解析消息正文字符串。

    此外,您可以遍历对话中的所有项目,并在最新/最近的项目中检测每个项目。通过删除旧项目,您可以获得最新的。以下示例展示了如何在对话中获取和显示邮件项目。

        void DemoConversation()
        {
           object selectedItem = Application.ActiveExplorer().Selection[1];
           // For this example, you will work only with 
           //MailItem. Other item types such as
           //MeetingItem and PostItem can participate 
           //in Conversation.
           if (selectedItem is Outlook.MailItem)
           {
              // Cast selectedItem to MailItem.
              Outlook.MailItem mailItem = selectedItem as Outlook.MailItem; 
              // Determine store of mailItem.
              Outlook.Folder folder = mailItem.Parent as Outlook.Folder;
              Outlook.Store store = folder.Store;
              if (store.IsConversationEnabled == true)
              {
                 // Obtain a Conversation object.
                 Outlook.Conversation conv = mailItem.GetConversation();
                 // Check for null Conversation.
                 if (conv != null)
                 {
                    // Obtain Table that contains rows 
                    // for each item in Conversation.
                    Outlook.Table table = conv.GetTable();
                    Debug.WriteLine("Conversation Items Count: " +                   table.GetRowCount().ToString());
                    Debug.WriteLine("Conversation Items from Table:");
                    while (!table.EndOfTable)
                    {
                        Outlook.Row nextRow = table.GetNextRow();
                        Debug.WriteLine(nextRow["Subject"]
                            + " Modified: "
                            + nextRow["LastModificationTime"]);
                    }
                    Debug.WriteLine("Conversation Items from Root:");
                    // Obtain root items and enumerate Conversation.
                    Outlook.SimpleItems simpleItems = conv.GetRootItems();
                    foreach (object item in simpleItems)
                    {
                        // In this example, enumerate only MailItem type.
                        // Other types such as PostItem or MeetingItem
                        // can appear in Conversation.
                        if (item is Outlook.MailItem)
                        {
                            Outlook.MailItem mail = item as Outlook.MailItem;
                            Outlook.Folder inFolder = mail.Parent as Outlook.Folder;
                            string msg = mail.Subject 
                                + " in folder " + inFolder.Name;
                            Debug.WriteLine(msg);
                        }
                        // Call EnumerateConversation 
                        // to access child nodes of root items.
                        EnumerateConversation(item, conv);
                     }
                  }
               }
            }
         }
    
         void EnumerateConversation(object item, Outlook.Conversation conversation)
         {
            Outlook.SimpleItems items = conversation.GetChildren(item);
            if (items.Count > 0)
            {
              foreach (object myItem in items)
              {
                // In this example, enumerate only MailItem type.
                // Other types such as PostItem or MeetingItem
                // can appear in Conversation.
                if (myItem is Outlook.MailItem)
                {
                   Outlook.MailItem mailItem = myItem as Outlook.MailItem;
                    Outlook.Folder inFolder = mailItem.Parent as Outlook.Folder;
                    string msg = mailItem.Subject
                        + " in folder " + inFolder.Name;
                    Debug.WriteLine(msg);
                }
                // Continue recursion.
                EnumerateConversation(myItem, conversation);
              }
           }
        }
    
    

    在示例代码示例中,我们获取一个选定的MailItem 对象,然后使用Folder 对象的Store 属性确定MailItem 对象的存储。 DemoConversation 然后检查IsConversationEnabled 属性是否为真;如果为真,则代码示例通过使用GetConversation 方法获取Conversation 对象。如果Conversation 对象不是空引用,则该示例使用GetTable 方法获取包含对话中每个项目的关联Table 对象。该示例然后枚举Table 中的每个项目并在每个项目上调用EnumerateConversation 以访问每个项目的子节点。 EnumerateConversation 接受 Conversation 对象并使用 GetChildren(Object) 方法获取子节点。 EnumerateConversation 被递归调用,直到没有更多的子节点。然后将每个对话项显示给用户。

    【讨论】:

    • 谢谢。我知道如何枚举 Outlook 中的对话。我不想在对话中重复解析潜在的 100 封电子邮件以找到差异,这本身将是一个字符串密集型工作负载,可能会严重影响 Outlook。有没有办法在 Outlook 上下文中运行时使用 Graph API 来解决这个问题,这样我们就没有身份验证提示?
    • 我看不出 Graph API 在这种情况下有何帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-18
    • 2011-03-15
    • 2017-10-09
    • 2021-03-08
    • 2020-09-28
    相关资源
    最近更新 更多