Send MailMessage via EWS with Custom Extended Properties

I have a requirement to be able to construct an email, send it (via Exchange) and then save the 'sent item' as a .msg file.

I'm trying to send the email via EWS and then find it in the sent items later. In order to accomplish this I set a named mapi property on the email before I send it which I can then use later to identify it in the sent items folder.

I set a custom property on an instance of MapiMessage as follows:


private void SetCustomProperty(MapiMessage message, string propertyValue)
{
var mapping = message.NamedPropertyMapping;
var pid = mapping.GetNextAvailablePropertyId(MapiPropertyType.PT_UNICODE);

var property = new MapiProperty(pid, Encoding.Unicode.GetBytes(propertyValue));

message.SetProperty(property);
mapping.AddNamedPropertyMapping(property, TestConstants.IdPropertyName, MapiProperties.PS_PUBLIC_STRINGS);
}


As I've said, I need to send the message via EWS as follows:


var ews = CreateEWSClient();

ews.Send(mailMessage);


However, when I load the message into a MailMessage object I lose the custom property.

THE PROBLEM: I can set the named property on the email using a MapiMessage, but I need to send the email as a MailMessage (via EWS) in which case the named property is no longer available / present.

The test below proves this (as it fails!):


[TestMethod]
public void MailMessageAndMapiMessage_IsPropertyPresentWhenMailMessageLoaded_PropertyExists()
{
var propertyValue = CreateUniqueId();

var message = CreateMailMessage();

var mapiMessage = MapiMessage.FromMailMessage(message);

SetCustomProperty(mapiMessage, propertyValue);

var loadedMessage = CreateMailFromMapiMessage(mapiMessage);

var loadedMapiMessage = MapiMessage.FromMailMessage(loadedMessage);

// this assert fails as the property does NOT exist after all!
AssertCustomPropertyIsSet(loadedMapiMessage, propertyValue);
}


The assert call is as follows:


private void AssertCustomPropertyIsSet(MapiMessage mapiMessage, string expected)
{
string actual = default(string);
foreach (MapiNamedProperty prop in mapiMessage.NamedProperties.Values)
{
if (prop.NameId == TestConstants.IdPropertyName)
{
actual = prop.GetString();
break;
}
}

Assert.AreEqual(expected, actual, "Custom named property " + TestConstants.IdPropertyName + " not found in email.");
}


n.b. I can confirm that the property is set ok and is available if the variable loadMapiMessage is created by calling MapiMessage.FromFile.

I've tried loading the instance of MailMessage in the following ways (this is encapsulated by the call to CreateMailFromMapiMessage in the test code above):

1) Save the instance of MapiMessage to a memory stream then call MailMessage.Load
2) Save the instance of MapiMessage to a temporary file then call MailMessage.Load

Unfortunately neither of these approaches work.

A WORKAROUND?: I've tried using the EWS API directly, but unfortunately the API doesn't provide a way to save emails as .MSG files. Perhaps I could use the EWS API to create, send and find the sent email, and use Aspose to save the sent email as a .MSG file. Any thoughts on this approach?

Any help you can provide on the problem and the proposed workaround would be really appreciated.

Many thanks,

Richard.

Hi,

Thank you for your inquiry.

I would request you to please give a try to the following code sample that uses InterpretAsTnef. Properties such as custom properties are not retained otherwise. Please try this code sample at your end and let us know your feedback.

Code:

string file = "567260\\Enter_for_the_Sydney_Running_Festival_today_for_a_20%_discount.msg";
MapiMessage msg = MapiMessage.FromFile(file);

//Add a custom property
MapiProperty property = new MapiProperty(msg.NamedPropertyMapping.GetNextAvailablePropertyId(MapiPropertyType.PT_UNICODE), Encoding.Unicode.GetBytes("test value - hello 123"));
msg.AddCustomProperty(property, "StringProp");

MailMessageInterpretor mi = MailMessageInterpretorFactory.Instance.GetIntepretor(msg.MessageClass);
MailMessage eml = mi.InterpretAsTnef(msg);

NetworkCredential credentials = new NetworkCredential(name, password, host);
ServicePointManager.ServerCertificateValidationCallback += CheckCertificate;

using (IEWSClient client = EWSClient.GetEWSClient(exchangeMailboxUri, credentials))
{
    client.Send(eml);
}