Search code examples
outlook-addinmapi

Mapping properties from namespace PS_INTERNET_HEADERS to PS_PUBLIC_STRINGS


I have an Outlook COM add-in (C#, Visual Studio 2012) that extends the standard form with additional message properties. The add-in works with Outlook 2010, 2013 and 2016.

The requirements for the add-in dictate that it supports reading and writing a set of properties in namespace PS_INTERNET_HEADERS. I follow the guidelines in http://blogs.technet.com/b/exchange/archive/2009/04/06/3407221.aspx to have such headers on incoming messages promoted to MAPI properties.

But as I understand it, all such headers will become MAPI string properties, right?! But several of these headers actually have more natural types. One the headers is an RFC5322 date-time header and will have a value like 'Wed, 28 Sep 2016 06:27:00 GMT'. Having such a header mapped to a MAPI property of type PT_UNICODE is not optimal as you cannot sort messages based on it, you cannot really use it in searches, etc.

Is there a good solution to this problem?

The only idea I have is to do some kind of mapping from properties in namespace PS_INTERNET_HEADERS to properties in namespace PS_PUBLIC_STRINGS. That would would also have the nice side-effect that properties will be included when printing messages. But if I have to go down that road, I need some kind of hook for doing the mapping. I can of course loop through all messages in a message store, listen for new messages coming in, listen for changed messages, etc - but it does not feel like a good solution. I guess I could also write an Exchange Transport Agent, but I would really like to keep logic on the client side.

Any suggestions?

Edit after Dmitry's comment:

For outgoing messages, I have to use properties in namespace PS_INTERNET_HEADERS since such messages are eventually transported by SMTP (outside Exchange) to other systems. In detail, I have to adhere to https://www.rfc-editor.org/rfc/rfc6477. As a side-effect, Exchange will for incoming messages promote such headers to properties in namespace PS_INTERNET_HEADERS. And that's all working fine.

But even in that case, I would like to follow your suggestion to extract properties explicitly in my code and write some new ones in namespace PS_PUBLIC_STRINGS. The challenge as I see it is which hook to use for running that code. Users should be able to use the mapped properties as columns in views, for sorting, for filtering, for search, inbox rules, etc. I can sweep entire message stores to do that mapping, I can listen for various Outlook object model events, but in the end I have a hard time seeing how I can avoid users to temporarily see messages that my code haven't treated yet.

I have an old add-in written in C++ using Extended MAPI with a similar challenge. On start-up, for each inbox in each IMsgStore it sweeps the entire inbox (potentially a quite expensive operation) and then subscribes to changes using IMAPIFolder::GetContentsTable and then IMAPITable::Advise. But my experience is that I will get table notifications TABLE_ERROR or TABLE_RELOAD now and then and will have to do another sweep. For IMsgStore::Advise I guess similar challenges are present?! In a C# context, I could use the events in Redemption class RDOStore (e.g. OnMessageModified) , but I assume that class uses IMsgStore::Advise?!


Solution

  • No, the property type will never to converted. It always stay as a string. Why not read the internet headers from the PR_TRANSPORT_MESSAGE_HEADERS property (DASL name http://schemas.microsoft.com/mapi/proptag/0x007D001F) and extract the properties explicitly in your code? You will have full control over which properties are extracted and how they are converted.