Pieter van der Westhuizen

Working with custom Outlook properties: C# code examples

Microsoft Outlook provides a rich interface for developers to add their own custom properties to Outlook Folders and Items. The Outlook Object model provides two objects when working with custom properties:

  • Outlook.UserDefinedProperties
  • Outlook.UserProperties

At first glance these two objects might appear to be the same thing, but the UserDefinedProperties are used to add custom properties to Outlook folders and the UserProperties are used to add custom properties to Outlook items, such as Contacts, Mails and Appointments.

The UserDefinedProperties collection object was introduced in Outlook 2007 that addresses and included an important feature to make the lives of Outlook developers easier. User properties need to be defined on both the item and folder level. The Add method of the UserProperties object contains an optional Boolean parameter called AddToFolderFields. If you set this parameter to True, your custom property will automatically be created on the item as well as in the folder.

It is important that the custom property is also created in the folder, because if it is not created in the folder you won’t be able to use it in Outlook queries when searching data.

In this article, we’ll write an Outlook add-in that will enable a user to view, add, edit and delete custom properties of an e-mail in Outlook. We’ll also add functionality to send the properties as an attachment via an e-mail to another user and display it inside their Outlook.

Creating the Outlook COM add-in project

Start by creating a new ADX COM Add-in project in Visual Studio using Add-in Express for Office and .net.

Creating the Outlook COM add-in project in Visual Studio 2013

Next, select your programming language of choice (C#, VB.NET or C++.NET) and the minimum version of Office that your add-in needs to support.

Selecting your programming language of choice and the minimum version of Office

Finally, select Microsoft Outlook from the list of supported applications:

Selecting Microsoft Outlook from the list of supported applications

Adding and designing the Outlook add-in’s user interface

We’ll use an Advanced Outlook Form to display the e-mail item’s properties and expose the functionality to add, edit and delete the user properties. To do this, we first need to add a new ADX Outlook Form item to the add-in project.

Adding a new ADX Outlook Form item to the add-in project

The design of our custom Outlook form will resemble the following image:

The design of the custom Outlook form

The UI primarily consists of a ListView, which will be used to display the user properties of the mail item, 3 buttons to add, edit or delete the properties. We’ll also add a panel with two text boxes and a save button which will be displayed when the user either adds or edits a user property.

Next, switch back to the AddinModule.cs designer surface and add a new ADXOlFormsManager component by clicking on its button in the designer toolbar.

Adding a new ADXOlFormsManager component

Add a new item to the newly added ADXOlFormsManager component and set the following properties:

  • AlwaysShowHeader: True
  • FormClassName: CustomOutlookProperties.frmCustomProperties (this is the name of the ADX Outlook Form we’ve added earlier)
  • InspectorItemTypes: Mail
  • InspectorLayout: RightSubpane
  • InspectorMode: Read;Compose

That should take care of showing the Advanced Outlook Form in the Outlook Mail Inspector window.

Display, add, edit and delete user properties

Open the Advanced Outlook Form we’ve added earlier and create an event handler for its ADXAfterFormShow event, which will contain the following code:

private void frmCustomProperties_ADXAfterFormShow()
{
    LoadAttachment();
    ShowProperties();
}

The LoadAttachment method will check whether the e-mail has an attachment called userproperties.xml. If it finds this specific attachment, it will save it to a folder on the local disk, read which properties should be added to the e-mail item and add them. The code for the LoadAttachment method follows:

private void LoadAttachment()
{
    Outlook.Inspector currInsp = null;
    Outlook.MailItem mail = null;
    Outlook.UserProperties props = null;
    Outlook.Attachments attachments = null;
    string savePath = string.Format("{0}\\OutlookProperties\\userproperties.xml",
        Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
 
    try
    {
        currInsp = this.InspectorObj as Outlook.Inspector;
        if (currInsp.CurrentItem is Outlook.MailItem)
        {
            mail = currInsp.CurrentItem as Outlook.MailItem;
            attachments = mail.Attachments;
            if (attachments.Count > 0)
            {
                props = mail.UserProperties;
                for (int i = 1; i <= attachments.Count; i++)
                {
                    Outlook.Attachment attachment = attachments[i];
                    if (attachment.FileName == "userproperties.xml")
                    {
                        attachment.SaveAsFile(savePath);
                        attachment.Delete();
                    }
                    Marshal.ReleaseComObject(attachment);
                }
                LoadProperties(props, savePath);
                mail.Save();
            }
        }
    }
    finally
    {
        if (mail != null) Marshal.ReleaseComObject(mail);
        if (attachments != null) Marshal.ReleaseComObject(attachments);
        if (props != null) Marshal.ReleaseComObject(props);
    }
}

You’ll notice that we call a method inside LoadAttachment, LoadProperties. This method reads the XML file containing the user properties and adds them to the UserProperties collection that is passed to it as a parameter:

private void LoadProperties(Outlook.UserProperties props, string filePath)
{
    XDocument doc = null;
    doc = XDocument.Load(filePath);
    var xmlProperties = doc.Descendants("UserProperty");
    foreach (var xmlProperty in xmlProperties)
    {
        string value = xmlProperty.Value;
        string name = xmlProperty.Attribute("Name").Value;
        Outlook.UserProperty prop = props.Add(
            xmlProperty.Attribute("Name").Value,
            Outlook.OlUserPropertyType.olText,
            true);
        prop.Value = xmlProperty.Value;
        Marshal.ReleaseComObject(prop);
    }
}

ShowProperties in turn, checks the mail item in the active inspector for custom user properties and loads them into the ListView control.

private void ShowProperties()
{
    Outlook.Inspector currInsp = null;
    Outlook.MailItem mail = null;
    Outlook.UserProperties itemProps = null;
 
    try
    {
        lvProps.Items.Clear();
        currInsp = this.InspectorObj as Outlook.Inspector;
        if (currInsp.CurrentItem is Outlook.MailItem)
        {
            mail = (Outlook.MailItem)currInsp.CurrentItem;
            itemProps = mail.UserProperties;
 
            for (int i = 1; i <= itemProps.Count; i++)
            {
                Outlook.UserProperty property = itemProps[i];
                ListViewItem item = new ListViewItem(property.Name);
                ListViewItem.ListViewSubItem subItem = 
                    new ListViewItem.ListViewSubItem(item, property.Value.ToString());
                item.SubItems.Add(subItem);
                lvProps.Items.Add(item);
                Marshal.ReleaseComObject(property);
            }
        }
    }
    finally
    {
        if (itemProps != null) Marshal.ReleaseComObject(itemProps);
        if (mail != null) Marshal.ReleaseComObject(mail);
    }
}

Next, add event handlers for each of the buttons. The Add button’s Click event will look similar to the following:

private void btnAdd_Click(object sender, EventArgs e)
{
    txtPropertyName.Clear();
    txtPropertyValue.Clear();
    txtPropertyName.ReadOnly = false;
    panelAddNew.Visible = true;
}

The code above simply clears any values that might be in the two textboxes and shows the panel. The Edit button’s Click event gets a reference to the selected item in the ListView and shows its values in the two textboxes:

private void btnEdit_Click(object sender, EventArgs e)
{
    var selectedItem = lvProps.SelectedItems[0];
    if (selectedItem != null)
    {
        var valueItem = selectedItem.SubItems[1];
        txtPropertyName.Text = selectedItem.Text;
        txtPropertyName.ReadOnly = true;
        txtPropertyValue.Text = valueItem.Text;
        panelAddNew.Visible = true;
    }
}

The Delete button’s functionality is a bit more involved, as it first gets a reference to the selected item in the ListView, searches for the corresponding user property on the mail item and deletes it:

private void btnDelete_Click(object sender, EventArgs e)
{
    Outlook.Inspector currInsp = null;
    Outlook.MailItem mail = null;
    Outlook.UserProperties itemProps = null;
 
    try
    {
        currInsp = this.InspectorObj as Outlook.Inspector;
        if (currInsp.CurrentItem is Outlook.MailItem)
        {
            mail = (Outlook.MailItem)currInsp.CurrentItem;
            itemProps = mail.UserProperties;
            foreach (var item in lvProps.SelectedItems)
            {
                ListViewItem selectedItem = item as ListViewItem;
                lvProps.Items.Remove(selectedItem);
 
                Outlook.UserProperty prop = itemProps.Find(selectedItem.Text);
                if (prop != null)
                {
                    prop.Delete();
                    Marshal.ReleaseComObject(prop);
                }
            }
            mail.Save();
        }
    }
    finally
    {
        if (itemProps != null) Marshal.ReleaseComObject(itemProps);
        if (mail != null) Marshal.ReleaseComObject(mail);
    }
}

Last in line with the buttons is the Save button. This code tries and finds the user property by name and once found, updates its value with the value in the textbox. If it does not find it, we assume it is a new property and add it to the UserProperties collection of the mail item.

private void btnSave_Click(object sender, EventArgs e)
{
    Outlook.Inspector currInsp = null;
    Outlook.MailItem mail = null;
    Outlook.UserProperties itemProps = null;
    Outlook.UserProperty newProp = null;
 
    try
    {
        currInsp = this.InspectorObj as Outlook.Inspector;
        if (currInsp.CurrentItem is Outlook.MailItem)
        {
            mail = (Outlook.MailItem)currInsp.CurrentItem;
            itemProps = mail.UserProperties;
            newProp = itemProps.Find(txtPropertyName.Text);
            if (newProp != null)
            {
                newProp.Value = txtPropertyValue.Text;
            }
            else
            {
                newProp = itemProps.Add(txtPropertyName.Text,
                    Outlook.OlUserPropertyType.olText, true);
            }
 
            newProp.Value = txtPropertyValue.Text;
            mail.Save();
            panelAddNew.Visible = false;
            ShowProperties();
        }
    }
    finally
    {
        if (newProp != null) Marshal.ReleaseComObject(newProp);
        if (itemProps != null) Marshal.ReleaseComObject(itemProps);
        if (mail != null) Marshal.ReleaseComObject(mail);
    }
}

Attaching custom user properties to an outgoing e-mail

Lastly, we’ll write some code that will save all the user properties of an outgoing e-mail and attach it to the email as an XML file. To do this, switch back to the AddinModule.cs design surface and add a Microsoft Outlook events component.

Adding a Microsoft Outlook events component

Add an event handler for the ItemSend event by double-clicking next to the event name in the list of events for the Microsoft Outlook event component.

Adding an event handler for the ItemSend event

Add the following code to the ItemSend event handler:

private void adxOutlookEvents_ItemSend(object sender, ADXOlItemSendEventArgs e)
{
    Outlook.MailItem mail = null;
    Outlook.Attachments attachments = null;
    Outlook.UserProperties props = null;
 
    try
    {
        if (e.Item is Outlook.MailItem)
        {
            mail = e.Item as Outlook.MailItem;
            props = mail.UserProperties;
            attachments = mail.Attachments;
            if (props.Count > 0)
            {
                string attachmentPath = PackageProperties(props);
                attachments.Add(attachmentPath);
            }
        }
    }
    finally
    {
        if (props != null) Marshal.ReleaseComObject(props);
        if (attachments != null) Marshal.ReleaseComObject(attachments);
    }
}

The above code will check whether the outgoing mail item contains any user properties and then package those properties in an XML file and attach the file to the outgoing e-mail. The code in our Advanced Outlook form in turn will read this XML file, add the user properties to the e-mail item and will then display it.

Thank you for reading. Until next time, keep coding!

Available downloads:

This sample Outlook add-in was developed using Add-in Express for Office and .net:

Custom Outlook Properties add-in (C#)

You may also be interested in:

9 Comments

  • Fabrice says:

    Nice article
    I wonder if you know why Outlook send winmail.dat attachment ? It’s seems it’s linked to Outlook Properties, and when Outlook is not used with Exchange.
    When I put some properties in an email just before the send, outlook put a winmail.dat attachment. Do you know a way to avoid that ?
    Thank you

  • Pieter van der Westhuizen says:

    Hi Fabrice,

    Outlook attaches the winmail.dat file to outgoing e-mail if the format of the e-mail is Rich Text Format(RTF)
    You can read more about this here : https://support.microsoft.com/kb/278061

    Thanks for reading!

  • Fabrice says:

    Yes I already read this, but this is the “theory” because I also have winmail.dat for email in html. I just got one case today.

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

    Hello Fabrice,

    According to the page below, that file is created when you send an email with UserProperties.

    https://social.msdn.microsoft.com/Forums/en-US/d697f0db-2c70-4044-ac59-e635a4c6904f/userproperties-and-winmaildat?forum=outlookdev

  • Fabrice says:

    Thank you for the link.
    I’ve already tried to remove all user properties in the ItemSend event, but I’m not sure it’s the right place to do it. I think it’s already too late.
    I’ll need to take so time to investigate further and
    try to set the MAPI property to tell Outlook to not use TNEF.

  • Chris says:

    Hi,
    Is it possible to save user properties on a custom email folder only without saving these properties on an email?
    Best,
    Chris

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

    Hello Chris,

    Please search for UserDefinedProperties in the text above.

  • Kelly says:

    I currently have a Procedure written in vb.net which Adds Entries to Outlook 2007 Shared Calendars.

    Imports Outlook = Microsoft.Office.Interop.Outlook

    Public Sub UpdateCalendar(ByVal subject As String, ByVal body As String, ByVal startdate As Date, ByVal enddate As Date, ByVal location As String, ByVal dept As String)

    Dim objApp As New Outlook.Application
    Dim objNS As Outlook.NameSpace
    Dim objFolder As Outlook.MAPIFolder
    Dim objDummy As Outlook.MailItem
    Dim objRecip As Outlook.Recipient
    Dim objAppt As Outlook.AppointmentItem
    Dim strMsg As String = Nothing
    Dim strName As String = Nothing
    Dim d As New DBRequest
    Dim Calendar As String = Nothing

    Calendar = d.GetCalendarEmail(dept)
    If Calendar = “No Calendar” Then
    MsgBox(“No Calendar is associated with this user. Contact IT Department to resolve this issue.”, vbOKOnly, TITLE)
    Exit Sub
    End If

    Try
    objNS = objApp.GetNamespace(“MAPI”)

    objRecip = objNS.CreateRecipient(Calendar)
    objRecip.Resolve()

    objFolder = objNS.GetSharedDefaultFolder(objRecip, Outlook.OlDefaultFolders.olFolderCalendar)
    objAppt = objFolder.Items.Add

    With objAppt
    .Subject = subject
    .Body = body + “” + vbCrLf + location
    .Start = Convert.ToDateTime(startdate)
    .End = Convert.ToDateTime(enddate)
    .Save()
    End With

    Catch ex As Exception

    objFolder = Nothing
    objAppt = Nothing
    objRecip = Nothing
    End Try

    objNS = Nothing

    objApp = Nothing
    objNS = Nothing
    objFolder = Nothing
    objDummy = Nothing
    objRecip = Nothing
    objAppt = Nothing
    d = Nothing

    End Sub

    My company is upgrading to Office 365 and I need to add entries to Outlook 365 shared Calendars in the same manner.
    How can I do this with Microsoft.Office365.OutlookServices?
    Can anyone help?

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

    Hello Kelly,

    This blog is about Windows Desktop versions of Outlook. In these terms, you can share that calendar with some Windows user who could add that calendar to their profile and run that VBA macro or a modification of it.

Post a comment

Have any questions? Ask us right now!