【发布时间】:2017-02-05 23:32:41
【问题描述】:
我有一个 Outlook COM 加载项(C#、Visual Studio 2012),它通过附加消息属性扩展了标准表单。该插件适用于 Outlook 2010、2013 和 2016。
插件的要求规定它支持读取和写入命名空间 PS_INTERNET_HEADERS 中的一组属性。我遵循http://blogs.technet.com/b/exchange/archive/2009/04/06/3407221.aspx 中的指导方针,将传入消息中的此类标头提升为 MAPI 属性。
但据我了解,所有此类标头都将成为 MAPI 字符串属性,对吧?!但是其中一些标头实际上具有更自然的类型。其中一个标头是 RFC5322 日期时间标头,其值类似于“Wed, 28 Sep 2016 06:27:00 GMT”。将此类标头映射到 PT_UNICODE 类型的 MAPI 属性并不是最佳选择,因为您无法根据它对消息进行排序,也无法真正在搜索中使用它等。
这个问题有好的解决办法吗?
我唯一的想法是从命名空间 PS_INTERNET_HEADERS 中的属性到命名空间 PS_PUBLIC_STRINGS 中的属性进行某种映射。这也会产生很好的副作用,即在打印消息时将包含属性。但是如果我必须走那条路,我需要某种钩子来进行映射。我当然可以遍历消息存储中的所有消息,侦听传入的新消息,侦听更改的消息等 - 但这并不是一个好的解决方案。我想我也可以编写一个 Exchange 传输代理,但我真的很想在客户端保留逻辑。
有什么建议吗?
在 Dmitry 发表评论后编辑:
对于传出消息,我必须使用命名空间 PS_INTERNET_HEADERS 中的属性,因为这些消息最终会通过 SMTP(Exchange 外部)传输到其他系统。详细的我要坚持https://www.rfc-editor.org/rfc/rfc6477。作为副作用,Exchange 会将传入消息的此类标头提升为命名空间 PS_INTERNET_HEADERS 中的属性。这一切都很好。
但即使在这种情况下,我也愿意按照您的建议在我的代码中显式提取属性并在命名空间 PS_PUBLIC_STRINGS 中编写一些新属性。我看到的挑战是使用哪个钩子来运行该代码。用户应该能够将映射的属性用作视图中的列、排序、过滤、搜索、收件箱规则等。我可以扫描整个消息存储来进行映射,我可以监听各种 Outlook 对象模型事件,但是最后,我很难理解如何避免用户暂时看到我的代码尚未处理的消息。
我有一个使用扩展 MAPI 用 C++ 编写的旧插件,但遇到了类似的挑战。在启动时,对于每个 IMsgStore 中的每个收件箱,它都会扫描整个收件箱(可能是一个非常昂贵的操作),然后使用 IMAPIFolder::GetContentsTable 和 IMAPITable::Advise 订阅更改。但我的经验是,我会时不时地收到表通知 TABLE_ERROR 或 TABLE_RELOAD 并且必须再进行一次扫描。对于 IMsgStore::Advise,我猜也存在类似的挑战?!在 C# 上下文中,我可以使用 Redemption 类 RDOStore (例如 OnMessageModified) 中的事件,但我假设该类使用 IMsgStore::Advise?!
【问题讨论】:
-
是的,您的假设是正确的。但是您应该能够修改视图以显示 PS_INTERNET_HEADERS 命名空间中的属性。它们不需要是 PS_PUBLIC_STRINGS - 视图 XML 使用 DASL 属性名称。
-
我有视图,没问题。还安装了一个带有属性定义的普通旧 .cfg 文件。但我的问题仍然存在:包含日期时间值的字符串属性可以显示,但您不能将它们用于排序、过滤和类似的事情——这是我真正的问题。
-
那么你真的不得不选择,但要在你的代码中明确设置 PT_SYSTIME 属性......
-
运行该代码的最佳钩子是什么?上述事件?
-
IMAPITable::Advise 可以完成这项工作。我要做的不同是添加一个额外的布尔属性来标记您处理过的消息(无论是否提取了自定义属性)。这样,您只需在未使用 RES_EXISTS 限制设置属性的收件箱文件夹中查询消息。
标签: outlook-addin mapi