Matt, Rick, and I were working on an issue recently where when an application using EWS would set a contact’s Street address to a value containing a carriage return and line feed, like this:
physicalAddress.Street = "1234 56 Ave NE\r\nc/oPatrick Creehan";
the address card control in Outlook would render it like this:
Ugly, right? The problem was that the XMLSerializer would strip out the line feed and leave the carriage return, which the address card didn’t like.
We could prove by sending raw XML requests in a separate application that sending
for the carriage return line feed would make everything right, however, if we set the street address like this:
physicalAddress.Street = "1234 56 Ave NE
then the contact’s address card would look like this:
Even uglier! It seems that the .net framework, in an attempt to help us out is encoding our string for XML but it wasn’t letting us specify the value we knew was right.
So – the solution is to implement your own class which can handle the XmlSerialization yourself, and replace the auto-generated proxy class’s decision for the type to yours.
Here’s my simple class:
A few things to point out is that I decorated this class with the XML namespace for the Exchange Web Services so that it doesn’t fail schema validation. Also, I didn’t really test whether this works when binding to an existing contact – there may be more work needed in the ReadXML section. In order to support still setting the Street property to a string, I had to override the implicit operator. That allows me to set Street to a string even though technically, now Street is an “mstring.” You’ll notice that the work of actually writing the correct value occurs in WriteXml which we got by implementing IXmlSerializable. Now when the SOAP infrastructure goes to build the request, it will call into our interface to serialize this class.
That reminds me, the last thing you need to do to hook all this up is to go into the web service proxy class Reference.cs and modify the PhysicalAddressDictionaryEntryType so the street properties use your new mstring class instead of string:
and (after removing the email address so the address will fit on the card) it looks like this:
I recently helped a customer with an issue where they were calling ConfigureMsgService and that call was failing, returning an HRESULT of MAPI_E_INVALID_PARAMETER (0x80070057). After debugging it, we established that the reason that ConfigureMsgService was failing was that the PR_PROFILE_HOME_SERVER_ADDRS property was missing from the profile. Outlook seemed to work fine, logons worked, sending mail worked; it was just that ConfigureMsgService would fail. We tried recreating the profile, but still the property wasn’t being set on the profile.
It turns out that PR_PROFILE_HOME_SERVER_ADDRS gets its value from PR_EMS_AB_NETWORK_ADDRESS, which in turn, gets its value from the networkAddress attribute on the server object in Active Directory. That value was set correctly, but permissions to that object were not. After following the requirements laid out on technet for permissions to AD objects, we determined that the Authenticated Users group was missing the ACL for Read All Properties on the server object. Once we set that permission and recreated the profile, the property was set correctly on the profile and ConfigureMsgService started succeeding.
According to our documentation, DeleteItem calls should fail with a ErrorStaleObject error when the ChangeKey is not the most recent one. This, however, is not the case. In Exchange 2007, the ChangeKey is completely ignored in DeleteItem calls. This decision was made on the logic that if you are trying to delete an item, chances are you don’t care if you have the most recent copy or not. But, what if you do?
You could try doing a GetItem, check the ChangeKey and then call DeleteItem right after, but that still leaves a small window of time between your GetItem and your DeleteItem calls where the item may have been changed.
Here’s a workaround which will help you implement the logic yourself using pull notifications.
As discussed in Chapter 1 of this captivating series, MAPI contains an interface to allow developers to create and read TNEF data. This interface is the ITnef interface. There are only a few methods in this interface and they are, for the most part, self explanatory. The entire process of creating a TNEF stream can be done in just a few steps:
So it’s pretty easy to do this. This is essentially the way that MFCMAPI demonstrates how to do it (look in File.cpp under SaveToTNEF). There are problems associated with doing it this way when it comes to Unicode properties and when having multiple embedded messages.
The more complicated way to do this to work around some of the issues described above is to add the properties you want explicitly, including each attachment.
The basic difference in the strategy is that instead of calling AddProps with TNEF_PROP_EXCLUDE, call it with TNEF_PROP_INCLUDE and give it the SPropTagArray you get from a call to GetPropList on the message. You’ll need to filter out the non-transmittable properties (such as custom props and things like the Store EntryID). Once you add all the message props, call GetAttachmentTable and loop through each attachment and do one of two things, if it’s not an embedded message, just add the attachment data with AddProps on PR_ATTACH_DATA_BIN; otherwise, you’re going to recurse over yourself and build a TNEF stream from the embedded message. When you call Finish on it, then you’ll add it to the parent TNEF stream by calling AddProps with PR_ATTACH_DATA_OBJ and using the TNEF_PROP_CONTAINED_TNEF flag and give it the stream for your TNEF blob. Once you unwind all the way, you’ll have your “master” TNEF stream. Essentially, you’ll follow the steps here: http://msdn.microsoft.com/en-us/library/cc839833.aspx
I’ve worked quite a few cases recently regarding problems some folks have had either reading or composing TNEF content. I’ve learned quite a bit myself as a result, and I thought I’d share. I decided I would do a series of blog posts on the topic and hopefully save some of you the time I spent learning all this.
So, being the first post on the topic, I suppose now would be a good time for a review on just what TNEF is and how it’s structured.
TNEF stands for Transport-Neutral Encapsulation Format. If you use Outlook or any other MAPI client as your mail client, you may know that MAPI is a protocol for communication between the client and the mailbox server. MAPI defines a set of interfaces which the client can use to work with the data in the mailbox. The MAPI structure for the data is hierarchical with messages being contained in containers, which themselves can have a parent container, all the way up to the root of the store. MAPI also defines a set of properties understood by the client and, in some cases, the server. If all mail sent could stay on this one server and only go between clients on this one system, this would be all we need; but we know that’s not the case. A very large quantity of e-mail is sent over the internet to foreign systems every day. The vast majority of those use an industry-standard protocol called SMTP (Simple Mail Transfer Protocol) to send messages in an industry-standard format called MIME (Multipurpose Internet Mail Extensions). MIME is composed of body parts, which can in turn be composed of additional body parts themselves. MIME also allows you to add headers to each of the body parts which allow you to describe the content of that body part. So one body part may be a Word Document attachment, so the MIME headers on that body part would contain the MIME type such as application/doc and the transfer type, such as base64. The content of that body part would then contain a base64 encoding of the document. The headers for the root body part contain information such as the subject of the message, the sender and recipient information, etc.
As a message makes its way through transport from one person’s email client to another person’s, it encounters many “hops” (brief stops at SMTP servers in the routing path) which have the opportunity to modify the headers. They do this in order to track the path the message took or to flag it as SPAM, verify the sender address, etc. So there’s a chance the headers you specify when you send the message won’t be the same as when the message arrives at the destination. The headers also only support text values. One of the problems discovered early on about the MIME format was that it has no concept of “rich text.”
In early versions of Outlook, users wanted the ability to send and receive email that contained rich text bodies. Microsoft devised a plan to create an attachment to the messages it was sending that would have a certain content-type and would come to have a well-known name, “winmail.dat”. This attachment would contain an encapsulation of the MAPI properties that could represent this rich body that would work across any transport and be readable by any system that supported MIME.
The original structure just supported a very simple structure that was basically Name/size/value. These were called “attributes” and the names of these attributes are still prefixed by “att.” Many of the attribute names can be seen here: http://msdn.microsoft.com/en-us/library/cc765736.aspx. The most important of these attributes for the purposes of our discussion will be the attMAPIProps. This attribute contains a list of MAPI properties that the receiving system can set on the message once it has converted the other MIME parts into their MAPI format. Some of the TNEF attributes can be directly translated into MAPI properties as defined by the link earlier in this paragraph, but there is not a 1-1 mapping between TNEF attributes and MAPI properties – hence the attMAPIProps attribute. Attachments and recipient data can also be encoded into the TNEF structure, which we’ll examine more later.
MSDN documents the general structure of TNEF but it’s hard to understand. Last year, when Exchange decided to be among those systems that elected to publicly document their protocols, they created [MS-OXTNEF].pdf, which documents very clearly the structure of the TNEF data and how to parse it. Don’t get too nervous, though. I have parsed a 3MB TNEF blob manually myself, but in Exchange 2007, we provide managed code interfaces to allow you to read (or write) this data very easily. In subsequent posts, I’ll dive more into the structure and into the managed classes, as well as the legacy MAPI ITnef interfaces, and more into problems you may experience in developing TNEF-enabled applications.