Eugene Astafiev

How To: Add a custom property to the UserProperties collection of an Outlook e-mail item

Today I want to tell you the story about Outlook user properties. Each item in Outlook such as MailItem, AppointmentItem, ContactItem and etc. (except for the NoteItem) provides you with the UserProperties property which returns an instance of the UserProperties class. Note that you will receive an exception if you try to programmatically add a user property to a DocumentItem object in Outlook (“Property is read-only”. The error code is 0x80070057).

The UserProperties object represents a collection of the UserProperty instances. The collection provides you with the Add method we are currently interested in. The Add method accepts the following four parameters (the last two are optional):

  • Name – The name of the property we are going to add. The following characters are forbidden: [,],_ and #. You will get an exception with the error code 0x80020009 if you use them.
  • Type – The type of the property we are going to add. It is defined by the OlUserPropertyType enumeration.
  • AddToFolderFields – Indicates whether a user property should be added to the UserDefinedProperties folder collection as well. By default it is true and it is added as a custom field to the folder that contains the item.
  • DisplayFormat – Specifies how it will be displayed in the Outlook user interface. You can get all possible values for this parameter from the DisplayFormat property.

The third parameter allows you to show the value of your custom property in the explorer view. You just need to pass true when you add a user property. Then you will be able to add a custom column to the current view of a particular folder where your item resides (see the CurrentView property of the Explorer class in Outlook if you are going to add it programmatically). In the code below I pass false because we are not going to modify the current folder view.

Please pay attention to the fact that user properties and their values can be transmitted to other Outlook clients due to the changes made in Outlook 2003 SP2. Later versions of Outlook already have these changes implemented. You can read more about this in the Changes to custom properties in Outlook article.

In the code I intend to demonstrate how to add a user property to the MailItem object in Outlook. To get the code running you need to pass an instance of the MailItem class to the AddUserProperty method. I will show you the code for VSTO and Add-in Express for Office and .net. So, let's start coding!

C# and Add-in Express:

private void AddUserProperty(Outlook.MailItem mail)
{
    Outlook.UserProperties mailUserProperties = null;
    Outlook.UserProperty mailUserProperty = null;
    try
    {
        mailUserProperties = mail.UserProperties;
        mailUserProperty = mailUserProperties.Add("TestUserProperty", 
           Outlook.OlUserPropertyType.olText, false, 1); 
           // Where 1 is OlFormatText (introduced in Outlook 2007)
        mailUserProperty.Value = "Eugene Astafiev";
        mail.Save();
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message);
    }
    finally
    {
        if (mailUserProperty != null) Marshal.ReleaseComObject(mailUserProperty);
        if (mailUserProperties != null) Marshal.ReleaseComObject(mailUserProperties);
    }
}

VB.NET and Add-in Express:

Private Sub AddUserProperty(mail As Outlook.MailItem)
    Dim mailUserProperties As Outlook.UserProperties = Nothing
    Dim mailUserProperty As Outlook.UserProperty = Nothing
    Try
        mailUserProperties = mail.UserProperties
        mailUserProperty = mailUserProperties.Add("TestUserProperty", _
             Outlook.OlUserPropertyType.olText, False, 1) 
             ' Where 1 is OlFormatText (introduced in Outlook 2007)
        mailUserProperty.Value = "Eugene Astafiev"
        mail.Save()
    Catch ex As Exception
        System.Windows.Forms.MessageBox.Show(ex.Message)
    Finally
        If Not IsNothing(mailUserProperty) Then 
            Marshal.ReleaseComObject(mailUserProperty)
        End If
        If Not IsNothing(mailUserProperties) Then 
            Marshal.ReleaseComObject(mailUserProperties)
        End If
    End Try
End Sub

C# and VSTO:

using System.Runtime.InteropServices;
// ...
private void AddUserProperty(Outlook.MailItem mail)
{
    Outlook.UserProperties mailUserProperties = null;
    Outlook.UserProperty mailUserProperty = null;
    try
    {
        mailUserProperties = mail.UserProperties;
        mailUserProperty = mailUserProperties.Add("TestUserProperty", 
            Outlook.OlUserPropertyType.olText, false, 1); 
            // Where 1 is OlFormatText (introduced in Outlook 2007)
        mailUserProperty.Value = "Eugene Astafiev";
        mail.Save();
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message);
    }
    finally
    {
        if (mailUserProperty != null) Marshal.ReleaseComObject(mailUserProperty);
        if (mailUserProperties != null) Marshal.ReleaseComObject(mailUserProperties);
    }
}

VB.NET and VSTO:

Imports System.Runtime.InteropServices
' ...
Private Sub AddUserProperty(mail As Outlook.MailItem)
    Dim mailUserProperties As Outlook.UserProperties = Nothing
    Dim mailUserProperty As Outlook.UserProperty = Nothing
    Try
        mailUserProperties = mail.UserProperties
        mailUserProperty = mailUserProperties.Add("TestUserProperty", _
            Outlook.OlUserPropertyType.olText, False, 1) 
            ' Where 1 is OlFormatText (introduced in Outlook 2007)
        mailUserProperty.Value = "Eugene Astafiev"
        mail.Save()
    Catch ex As Exception
        System.Windows.Forms.MessageBox.Show(ex.Message)
    Finally
        If Not IsNothing(mailUserProperty) Then 
            Marshal.ReleaseComObject(mailUserProperty)
        End If
        If Not IsNothing(mailUserProperties) Then 
            Marshal.ReleaseComObject(mailUserProperties)
        End If
    End Try
End Sub

See you on our forums and in the e-mail support!

33 Comments

  • umamaheswar says:

    How to send the outlook.mailitem to this method……..

    how to read the current opened mailitem of outlook.

    where should i call this method. please provide me total code.

  • umamaheswar says:

    I using this method add user properties but i am unable to create new instance of outlook.mailitem can u please tell me how to create instance for outlook.mailitem

    or

    please tell me how to add properties to the current opened outlook

  • Eugene Astafiev says:

    Hi Umamaheswar,

    Please take a look at the How To: Create and send an Outlook message programmatically and How To: Create and show a new Outlook message programmatically articles on our technical blog. They illustrate the way how you can create a new mail item object. Note, you just need to pass a MailItem object to the AddUserProperty method to get the code running.

  • Sunil says:

    The same code does not work for outlook 2003 client.. it works fine with 2007 and 2010 clients.. am i missing something here ?

  • Eugene Astafiev says:

    Hi Sunil,

    What do you mean saying “The same code does not work for outlook 2003 client…”?

    Could you please explain the issue in detail? Do you develop a VSTO based add-in project? Do you get any errors or exceptions?

  • Sunil says:

    Eugene,

    Sorry for being so abstract.

    Here is the code snippet which i was referring.. Please ignore other details and only concentrate on the commented code when i run this against 2003 outlook client i get casting error and the same code in the else loop works fine.. for 2007/2010 outlook client

    public void GetLyncCalanderMeetings(DataSet meetingsDs)
    {
    // declaring outlook objects
    //oType is used to connect to outlook dynamically
    Type oType = Type.GetTypeFromProgID(“Outlook.Application”);
    //oApp is used to connect to outlook application and access outlook items
    Object oApp = Activator.CreateInstance(oType);

    //mapiNamespace is used to connect to outlook profile and get default calander items
    Object mapiNamespace = oApp.GetType().InvokeMember(“GetNamespace”,
    BindingFlags.GetProperty, null, oApp, new object[1] { “MAPI” });

    //CalendarFolder is used to access outlook calander folder
    Object CalendarFolder = mapiNamespace.GetType().InvokeMember(“GetDefaultFolder”,
    BindingFlags.GetProperty, null, mapiNamespace, new object[1]{ 9 });
    //outlookCalendarItems is used to set calander items
    Object outlookCalendarItems = CalendarFolder.GetType().InvokeMember(“Items”,
    BindingFlags.GetProperty, null, CalendarFolder, null);
    int mailCount = 0;
    // Get current profile UserName Logon information.
    string strOutlookProfileUserName = ((dynamic)mapiNamespace).CurrentUser.Name;
    // get recurrence calander items using GetRecurringMeetings method
    outlookCalendarItems= objGetMeetingDetails.GetRecurringMeetings((dynamic)outlookCalendarItems);

    // filter the calendar items using this method
    dynamic restrictedItems = objGetMeetingDetails.FilterCalendarItems(outlookCalendarItems);

    Microsoft.Office.Interop.Outlook.UserProperty MigrateCustomUserProperty = null;
    // assign Outlook Properties defined from resx file
    string SNo = RM.GetString(“SNO”).ToString();
    string EntryID = RM.GetString(“EntryID”).ToString();
    string ConversationID = RM.GetString(“ConversationID”).ToString();
    string Title = RM.GetString(“Title”).ToString();
    string Descrpition = RM.GetString(“Descrpition”).ToString();
    string RequiredList = RM.GetString(“RequiredList”).ToString();
    string OptionalList = RM.GetString(“OptionalList”).ToString();
    string StartDateTime = RM.GetString(“StartDateTime”).ToString();
    string IsRecurring = RM.GetString(“IsRecurring”).ToString();
    string EndDateTime = RM.GetString(“EndDateTime”).ToString();
    string IsMigrated = RM.GetString(“IsMigrated”).ToString();

    // loop through all outlook calender items
    foreach (dynamic item in restrictedItems)
    {
    try
    {
    // check for active meetings or not
    string strMeetingStatus = objGetMeetingDetails.CheckLyncMeetingStatus(item);
    // check lync meetings or not using UserProperties and meeting is active or not
    if (!item.MessageClass.Contains(“Live Meeting”) && item.UserProperties[“OnlineMeetingExternalLink”] != null && strMeetingStatus!=”5″ && strMeetingStatus!=”7″) // dont include cancelled meetings whose status is having 5 or 7
    {
    // if OnlineMeetingExternalLink is not null
    if (!string.IsNullOrEmpty(item.UserProperties[“OnlineMeetingExternalLink”].Value))
    {
    string strOnlineMeetingExtLink = Convert.ToString((dynamic)item.UserProperties[“OnlineMeetingExternalLink”].Value);
    // check meeting organizer with outlook logged user to show items created by outlook current user
    if (item.Organizer == strOutlookProfileUserName)
    {
    outlookVersion = ((dynamic)oApp).Version;
    if (outlookVersion.StartsWith(“11.”))
    {
    MigrateCustomUserProperty = item.UserProperties.Find(“MigratedStatus”);
    if (MigrateCustomUserProperty == null)
    {

    //MigrateCustomUserProperty =
    // item.UserProperties.Add(“MigratedStatus”,
    // Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText, false, 1);

    MigrateCustomUserProperty.Value = “false”;
    item.Save();

    }
    }
    else
    {
    MigrateCustomUserProperty = item.UserProperties.Find(“MigratedStatus”);
    if (MigrateCustomUserProperty == null)
    {
    MigrateCustomUserProperty =
    item.UserProperties.Add(“MigratedStatus”,
    Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText, false, 1);

    MigrateCustomUserProperty.Value = “false”;
    item.Save();
    }
    }

    mailCount += 1;
    //Create New DataRow to set all meeting properties into Datarow
    DataRow dr = meetingsDs.Tables[0].NewRow();
    dr[SNo] = mailCount;
    dr[EntryID] = item.EntryID;
    dr[ConversationID] = “”;//item.ConversationID;
    dr[Title] = item.Subject;
    dr[Descrpition] = item.Body;
    dr[RequiredList] = item.RequiredAttendees;
    dr[OptionalList] = item.OptionalAttendees;
    dr[StartDateTime] = Convert.ToDateTime(((dynamic)item).Start);
    dr[IsRecurring] = ((dynamic)item).IsRecurring;
    dr[EndDateTime] = Convert.ToDateTime(((dynamic)item).End);
    dr[IsMigrated] = MigrateCustomUserProperty.Value;
    if (MigrateCustomUserProperty.Value == “false”)
    {
    // adding calender items to dataset
    meetingsDs.Tables[0].Rows.Add(dr);
    }

    }
    }
    }
    // check for live meetings or not using UserProperties and meeting is active or not
    if (item.MessageClass.Contains(“Live Meeting”) && strMeetingStatus != “5” && strMeetingStatus != “7”) // dont include cancelled meetings whose status is having 5 or 7
    {
    if (item.UserProperties.Count > 0)
    {
    if (!string.IsNullOrEmpty(item.UserProperties[“JoinInfo”].Value) && !string.IsNullOrEmpty(item.UserProperties[“LiveMeetingAttendeeKey”].Value))
    {
    // check meeting organizer with outlook logged user to show items created by outlook current user
    if (item.Organizer == strOutlookProfileUserName)
    {

    MigrateCustomUserProperty = item.UserProperties.Find(“MigratedStatus”);
    if (MigrateCustomUserProperty == null)
    {
    MigrateCustomUserProperty = item.UserProperties.Add(“MigratedStatus”, Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText, false, 1);
    MigrateCustomUserProperty.Value = “false”;
    item.Save();
    }
    mailCount += 1;
    //Create New DataRow to set all meeting properties into Datarow
    DataRow dr = meetingsDs.Tables[0].NewRow();
    dr[SNo] = mailCount;
    dr[EntryID] = item.EntryID;
    dr[ConversationID] = “”; // item.ConversationID;
    dr[Title] = item.Subject;
    dr[Descrpition] = item.Body;
    dr[RequiredList] = item.RequiredAttendees;
    dr[OptionalList] = item.OptionalAttendees;
    dr[StartDateTime] = Convert.ToDateTime(((dynamic)item).Start);
    dr[IsRecurring] = ((dynamic)item).IsRecurring;
    dr[EndDateTime] = Convert.ToDateTime(((dynamic)item).End);
    dr[IsMigrated] = MigrateCustomUserProperty.Value;

    if (MigrateCustomUserProperty.Value == “false”)
    {
    // adding calender items to dataset
    meetingsDs.Tables[0].Rows.Add(dr);
    }

    }
    }
    }

    }

    }
    catch
    {
    // catch exceptions here
    }

    }
    //obsMeetingDetails is a collection to add and remove meeting items for binding datapager
    obsMeetingDetails = new ObservableCollection();
    // if meetings count is >0
    if (meetingsDs.Tables[0].Rows.Count > 0)
    {
    // looping through all dataset meeting items
    foreach (DataRow drMd in meetingsDs.Tables[0].Rows)
    // add meetings in datatable to observable collection
    obsMeetingDetails.Add(new LyncLibrary(drMd[SNo].ToString(), drMd[EntryID].ToString(), drMd[ConversationID].ToString(),
    drMd[Title].ToString(), drMd[Descrpition].ToString(), Convert.ToDateTime(drMd[StartDateTime].ToString()),
    Convert.ToDateTime(drMd[EndDateTime].ToString()), Convert.ToBoolean(drMd[IsRecurring].ToString()),
    Convert.ToBoolean(drMd[IsMigrated].ToString())));

    }
    }

  • Eugene Astafiev says:

    Hi Sunil,

    Thank you for providing me with the sample code.

    Do you develop a standalone application? If so, do you use Outlook 2003 interops?

  • Sunil says:

    yes, this is a stand alone applicaiton to get the lync meetings from outlook client across all the Operation System and all outlook clients. Its not a VSTO based add-in project. i have Microsoft.Office.Interop (14) version already added to my reference. and i get this error…(Unable to cast COM object of type ‘System.__ComObject’ to interface type ‘Microsoft.Office.Interop.Outlook.UserProperty’)

  • Eugene Astafiev says:

    Hi Sunail,

    It looks like we have found the cause – the version of interop files is 14 (for Outlook 2010). Instead, you need to use Outlook 2003 interops.

  • Sunil says:

    Here is what i get from Immediate window..

    ?item.UserProperties.Add(“Migrated123”, Microsoft.Office.Interop.Outlook.OlUserPropertyType.olKeywords, false, 1)
    Embedded interop type ‘Microsoft.Office.Interop.Outlook.OlUserPropertyType’ is defined in both ‘Microsoft Lync Meeting Migrator.exe’ and ‘Outlook.dll’. Some operations on objects of this type are not supported while debugging. Consider casting this object to type ‘dynamic’ when debugging or building with the ‘Embed Interop Types’ property set to false.

  • Sunil says:

    But it wont let me add 2003 Dll that is for interop (12) when 14 is already there

  • Eugene Astafiev says:

    Hi Sunil,

    Right. You need to replace them.

  • Sunil says:

    hmm.. but my code shoudl also work for 2010 and 2007 outlook clients.. if i add 2003 interops will the same code work for 2010 ? i dont think so..

    Also i have downloaded and installed 2003 interops from MS site.. but did not add the references to my project though.

  • Sunil says:

    i have remove 14 dll and added 12 version.. but running into the same issue.

  • Eugene Astafiev says:

    Sunil,

    Most likely you downloaded Outlook 2007 interops (12) instead of Outlook 2003 interops. Please e-mail me to our support address and I will continue to help you with this issue. You can find the support e-mail address in the readme.txt file (it is included in our product packages).

  • Sunil says:

    It worked for me with 11 version dll.. The issue is resolved. Thanks a lot for help

  • Eugene Astafiev says:

    You are welcome, Sunil! ;-)

  • Germán says:

    Hi Eugene,

    Thanks for your example, I followed your code but I got stuck on a minor problem.

    I added an event on the send handler, that checks to see if the item that is being sent is a meeting and if one of the recipients is a specific account. If so then a popup displays and asks the user for some additonal info, then I store the info the user entered as UserDefined properties once he hits OK button in the popup window.

    Please note that at the startup of the add in I check the default calendar folder to see if the user properties exist if not I create them.

    So far all of this works, the problem I’m running into is that the user defined properties for the meeting are blank in the calendar folder once the meeting is sent. I also checked the user properties after the popup window closes, and they are set without problems.

    Any ideas?

    This is the code for updating the user properties:

    private void UpdateMessage(Outlook.MeetingItem meetingitem, string VisitorName, string VisitType, string VisitPurpose)
    {
    try
    {
    Outlook.UserProperty visitorname = meetingitem.UserProperties.Add(“VisitorName”, Outlook.OlUserPropertyType.olText, Type.Missing, Type.Missing);
    visitorname.Value = textBox1.Text;
    Outlook.UserProperty visittype = meetingitem.UserProperties.Add(“VisitType”, Outlook.OlUserPropertyType.olText, Type.Missing, Type.Missing);
    visittype.Value = comboBox1.Text;
    Outlook.UserProperty visitpurpose = meetingitem.UserProperties.Add(“VisitPurpose”, Outlook.OlUserPropertyType.olText, Type.Missing, Type.Missing);
    visitpurpose.Value = textBox2.Text;
    meetingitem.Save();
    }
    catch (Exception ex)
    {
    System.Windows.Forms.MessageBox.Show(ex.Message);
    }
    }

    Thanks in advance for any help you can provide…

  • Eugene Astafiev says:

    Hi German,

    Please check out the Sent Items folder where the sent meeting item resides. Does it contain the user property?

  • Germán says:

    Hi Eugene,

    Yes it does contain the user defined properties…

    When I added the user defined properties to sent items folder, actually to all the folders just in case, then the meeting items that had the user defined properties in the sent items folder had the corresponding values set but when you look at the meeting item in the calendar the calendar item does not have them set.

    So I guess this means that Outlook sends the meeting item as a message and then it makes a copy of the item in the calendar, but when it copies the item is does not copy the user defined properties?

    Any ideas or recommendation on how to set these properties after the item is copied over?

    Thanks,
    Germán

  • Eugene Astafiev says:

    Hi German,

    Well, it confirms my assumptions that you need to update the corresponding item in the Calendar folder manually. You can handle the ItemAdd event of the Items collection (see Folder.Items property) and do the homework.

  • Morscha says:

    Hi Eugene,

    I copied your AddUserProperty(Outlook.MailItem mail) method, but i get the following error:

    System.AccessViolationException: Attempted to read or write protected memory. Th
    is is often an indication that other memory is corrupt.
    at Microsoft.Office.Interop.Outlook.UserProperty.get_Value()
    at Bluepond.Net.Kpn.RO.ProcessEmailsForDataCollector.ProcessEmailsAndCreateCs
    vFile.AddUserProperty(MailItem mail)
    at Bluepond.Net.Kpn.RO.ProcessEmailsForDataCollector.ProcessEmailsAndCreateCs
    vFile.StartProcessingOutlook()
    at Bluepond.Net.Kpn.RO.ProcessEmailsForDataCollector.Program.Main()

    Unhandled Exception: System.AccessViolationException: Attempted to read or write
    protected memory. This is often an indication that other memory is corrupt.
    at Microsoft.Office.Interop.Outlook.UserProperty.get_Value()
    at Bluepond.Net.Kpn.RO.ProcessEmailsForDataCollector.ProcessEmailsAndCreateCs
    vFile.AddUserProperty(MailItem mail)
    at Bluepond.Net.Kpn.RO.ProcessEmailsForDataCollector.ProcessEmailsAndCreateCs
    vFile.StartProcessingOutlook()
    at Bluepond.Net.Kpn.RO.ProcessEmailsForDataCollector.Program.Main()

    Could you please help me?

    -I am using Outlook 2003
    -In the C:\Program Files\Microsoft Visual Studio 9.0\Visual Studio Tools for Office\PIA\Office11 there is a Microsoft.Office.Interop.Outlook.dll version 11.0.5530.0

    Yours sincerely,

    Morscha

  • Andrei Smolin (Add-in Express Team) says:

    Hi Morsha,

    It looks like you develop a standalone application, not an Outlook add-in. Please confirm.

    Possible reasons are:

    I. Something is wrong in Outlook
    – please check that you have Office 2003 SP3 installed
    II. Something is wrong with the MailItem
    – can you modify that item in the Outlook UI?
    – please make sure that the UserProperty actually exists
    – Or, you use it at a wrong moment. In what event you access the UserProperty?
    III. Something prevents your code from accessing the UserProperty.
    – are you getting security warnings? If yes, consider using our Security Manager
    – turn off all other COM add-ins and Exchange extensions (please google for these)
    – try to turn your antivirus off temporarily

  • Rasmus says:

    Is it possible to define properties that are “local user only” – ie. are NOT sent to recipients?
    With a plugin that adds some properties to AppointmentItem, those properties are apparently also sent if the AppointmentItem is a meeting request or update.
    The recipient’s plugin sees the sender’s values, and the recipient’s values can be overwritten if he receives a meeting update.

  • Dmitry Kostochko (Add-in Express Team) says:

    Hi Rasmus,

    This cannot be done using the Outlook Object Models’ methods. I would suggest either not to add properties to meeting requests and updates or delete the added properties before an item is sent.

  • Jim Ryan says:

    I tried adding a UserProperty to a mailitem before sending it so that I could inspect that UserProperty value after the mail was successfully sent using the ItemAdd event on the Sent Items folder.

    I confirmed by stepping through and watching that the UserProperty was correctly added before sending the email. I saved the email before sending.

    The problem is when the ItemAdd event triggers and I inspect the mailitem, all of the UserProperties are gone (UserProperties.count = 0). It seems Outlook clears all the UserProperties when a message is sent. Is there any way around this? I need to pass on some information to code that runs after the message is successfully sent.

    Code snippet below:

    — Before Send —
    objItem.UserProperties.Add “MyInfo”, olText
    objItem.UserProperties(“MyInfo”) = “Info to pass…”
    objItem.Save
    ‘ At this point I confirmed in the Watches window that the UserProperty is set
    objItem.Send

    — Code that Executes on the Sent Items Folder AddItem event —
    Set reminderDateProperty = oMailItem.UserProperties.Find(“MyInfo”)
    ‘ Returns Nothing
    ‘ I confirmed in the Watches window that UserProperties.count is 0

  • Andrei Smolin (Add-in Express Team) says:

    Hello Jim,

    You don’t release COM objects. The need to do this is described at https://www.add-in-express.com/creating-addins-blog/releasing-office-objects-net/. For instance, every objItem.UserProperties call creates a COM object representing the collection of UserProperty objects – each UserProperty object is a COM object.

    I’ve used VBA to add a UserProperty to an email opened in an inspector; then I ‘ve sent it and checked the email in the Sent Items folder (also with VBA) – it also contains the UserProperty. Using VBA is a way to test the code with all COM objects being properly released; this is because VBA releases every COM object behind the scenes.

    But I tested this on a PST account. Do you use Exchange?

  • Sandeep Atri says:

    Hi Eugene ,

    Thanks much for sharing the code. That has saved a lot of my time. I am facing problems in fetching the newly created user property. It always returns me null when I try to find for the user property. Looks like the user property was not saved with the mail item properly. Any thoughts? Here are some more details that you might need :

    Outlook version 2010
    .net version 4.0

  • Andrei Smolin (Add-in Express Team) says:

    Hello Sandeep,

    You need to make sure that you save the Outlook item after adding the UserProperty.

  • Pie says:

    Hello there,
    I’m coding a simple C# program that tries to store some custom properties in a Outlook MailItem as metadata…
    I created this simple method in order to write a single property:

    public static void AddCustomPropertyToEmail(Outlook.MailItem mail, string propKey, object propValue)
    {
    if (propValue is System.Int32) { // INT
    mail.UserProperties.Add(propKey,
    Outlook.OlUserPropertyType.olInteger,
    true,
    Outlook.OlFormatInteger.olFormatIntegerPlain);
    }
    else if (propValue is System.DateTime){ // DATE
    mail.UserProperties.Add(propKey,
    Outlook.OlUserPropertyType.olDateTime,
    true,
    Outlook.OlFormatDateTime.OlFormatDateTimeLongDayDate);
    }
    else if (propValue is System.String){ // STRING
    mail.UserProperties.Add(propKey,
    Outlook.OlUserPropertyType.olText,
    true,
    Outlook.OlFormatText.olFormatTextText);
    }
    else if (propValue is System.Double){ // DOUBLE
    mail.UserProperties.Add(propKey,
    Outlook.OlUserPropertyType.olCurrency,
    true,
    Outlook.OlFormatCurrency.olFormatCurrencyDecimal);
    }
    else if (propValue is System.Boolean){ // BOOL
    mail.UserProperties.Add(propKey,
    Outlook.OlUserPropertyType.olYesNo,
    true,
    Outlook.OlFormatYesNo.olFormatYesNoTrueFalse);
    }
    else{
    Console.WriteLine(“\tERROR: No valid type for the custom” + propKey + “property”);
    System.Threading.Thread.Sleep(1750);
    System.Environment.Exit(1);
    }

    mail.UserProperties[propKey].Value = propValue;
    mail.Save();
    }

    and this in order to read a single property:

    public static string GetCustomPropertyFromEmail(Outlook.MailItem mail, string propKey)
    {
    return (mail.UserProperties[propKey] != null) ? mail.UserProperties[propKey].Value.ToString() : null;
    }

    When I print at Console each property that I’ve added before the print goes fine only if I read the property on the same MailItem type stored in memory…
    For example:

    static void Main(string[] args){

    Outlook.Application outlookObj = new Outlook.Application();
    Outlook.MailItem m1 = GetCurrentEmailItem(outlookObj);

    AddCustomPropertyToEmail(m1, “Int”, 100);
    AddCustomPropertyToEmail(m1, “Double”, 2.0003);

    Console.WriteLine(GetCustomPropertyFromEmail(m2, “Int”));
    Console.WriteLine(GetCustomPropertyFromEmail(m2, “Double”));

    if (m1 != null) Marshal.ReleaseComObject(m1);
    Console.ReadKey();
    }

    This program works fine, it prints the values!!!

    But the follow code does not, it returns null in each case:

    static void Main(string[] args){

    Outlook.Application outlookObj = new Outlook.Application();
    Outlook.MailItem m1 = GetCurrentEmailItem(outlookObj);

    AddCustomPropertyToEmail(m1, “Int”, 100);
    AddCustomPropertyToEmail(m1, “Double”, 2.0003);

    m1.SaveAs(@”C:\PWS\myMail.msg”, Outlook.OlSaveAsType.olMSG);

    Outlook.MailItem m2 = (Outlook.MailItem)outlookObj.CreateItem(Outlook.OlItemType.olMailItem);
    m2 = (Outlook.MailItem)outlookObj.Session.OpenSharedItem(@”C:\PWS\myMail.msg”);

    // HERE THE PROGRAM PRINTS NULL
    Console.WriteLine(GetCustomPropertyFromEmail(m2, “Int”));
    Console.WriteLine(GetCustomPropertyFromEmail(m2, “Double”));

    if (m2 != null) Marshal.ReleaseComObject(m2);
    Console.ReadKey();
    }

    My question is: How can I save/store custom property in a MailItem, and possibly save a related msg file in my PWS and read these custom properties in a second time???

    Thank you very much in advance

  • Dmitry Kostochko (Add-in Express Team) says:

    Hello Pie,

    The UserProperties collection gets cleared when you open an msg file. I would suggest that you try to add and retrieve your properties as Extended MAPI properties, via the PropertyAccessor object.

  • Filip Szesto says:

    Hi,

    I added UserProperty same way as you in your code sample.
    Then opened new Outlook’s mail window.
    I inspected MailItem with OutlookSpy. My property was correctly added to Mail.

    After sending mail I checked Mail in SentItems folder. My property disappeared.
    What is more interesting, everything was OK when I moved Mail manually from working copies to SentItems.

    Thank you very much in advance!

  • Andrei Smolin (Add-in Express Team) says:

    Hello Filip,

    In a comment above, I wrote:
    ===
    I’ve used VBA to add a UserProperty to an email opened in an inspector; then I ‘ve sent it and checked the email in the Sent Items folder (also with VBA) – it also contains the UserProperty. Using VBA is a way to test the code with all COM objects being properly released; this is because VBA releases every COM object behind the scenes.

    But I tested this on a PST account. Do you use Exchange?
    ===

    Anyway, a UserProperty can’t leave the boundaries of a given domain: if you send an email outside of the domain, the UserProperty will never be received. A way out of this is to add your bit of data to the Internet headers of your email; please check https://www.add-in-express.com/forum/read.php?FID=5&TID=14156&MID=72475.

Post a comment

Have any questions? Ask us right now!