Search code examples
c#outlookmapi

C# Problems getting a specific named MAPI property from a .msg


I'm having a similar problem to this question in getting a pair of "custom" MAPI properties from a MailItem in a C# console app, but with the extra twist that it works locally but not on the server.

The two properties are PR_SERVERID and PR_MSGID and both are available on the mailitems when inspected via MFCMAPI, I'm accessing them as follows:

MessageDetails.PR_SERVERID = Message.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/PR_SERVERID").ToString();

MessageDetails.PR_MSG_ID = Message.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/PR_MSGID").ToString();

Where Message is of type Outlook.MailItem. When I run this locally (from built exe or in debug) it works but on a separate server the exact same message fails with:

15:17:26 Error getting getting MAPI properties from the stub: 
System.ApplicationException: System.Runtime.InteropServices.COMException (0x8004010F): 
The property "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/PR_SERVERID" is unknown or cannot be found.

Before this, I am successfully retrieving two "standard" MAPI properties (PR_CREATOR_NAME and PR_INTERNET_MESSAGE_ID) from the same item so the MailItem is accessible.

The DASL for the properties shown in MFCMAPI is identical between the two servers and my local machine and both are running Outlook 2010 and accessing the mailItem by invoking an Outlook session.

The only thing I could think of was that Outlook itself is unable to recognise the custom properties without some configuration that's missing on the remote server(s), does Outlook have to have a property configured at the namespace level for it to be recognised even if identified by a DASL?

Edit: Additional information on the mail items: The mails are "stubs" downloaded from an archive system, the two attributes then provide the identifier for the "full" message content. I'm downloading the stub from the remote server, saving it locally and then accessing each stub in the set using:

Outlook.NameSpace NS = _outlookApplication.GetNamespace("MAPI");
Object item = _outlookApplication.Session.OpenSharedItem(MessageDetails.FilePath)
Outlook.MailItem Message = (Outlook.MailItem)item;

And attempting to add the two properties to the MessageDetails object by getting the properties from Message.

Edit 2: I've noticed that when retrieving the properties on a "fresh" host, I get a security prompt for "a program is trying to access e-mail address information stored in Outlook" when I access the custom properties but not when I access the subjectline/sender etc. from the standard properties. The seems to indicate that there is something about these custom properties that is "different" when accessed via COM interop using outlook. Nevermind, this is simply default protection on calling PropertyAccessor.GetProperty.

Answer: Dmitry is spot on and I have marked his response as the answer, the properties were not accessible because they had never been created on the store. With user machines these have been created because at some point we "archived" mails into the remote store and set the custom properties on the stubs left in our mail boxes. On the servers this had never been done so I added an option for a "first run" that creates a dummy object, sets two empty custom properties on it, saves it then deletes it. Subsequent runs are then able to access the properties using PropertyAccessor.GetProperty.


Solution

  • Outlook Object Model always assumes PT_UNICODE / PT_STRING8 type for the properties in the "string" namespace. The type in your case is PT_LONG (0x0003).

    As a test, can you install Redemption (I am its author) and try the following script from OutlookSpy (I am also its author - click Script, paste the script, click Run)

      set Session = CreateObject("Redemption.RDOSession")
      Session.MAPIOBJECT = Application.Session.MAPIOBJECT
      set Msg = Session.GetMessageFromMsgFile("c:\temp\yourmsg.msg")
      MsgBox Msg.Fields("http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/PR_SERVERID/0x00000003")
    

    UPDATE Try the following script in OutlookSpy on a machine where your code fails. When the IMessage window pops up, do you see the named properties?

    set msg = Application.Session.OpenSharedItem("c:\temp\yourmsg.msg")
    BrowseObject(msg.MAPIOBJECT)