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
- Adding and designing the Outlook add-in’s user interface
- Displaying, adding, editing and deleting user properties
- Attaching custom user properties to an outgoing e-mail
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.
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.
Finally, select 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.
The design of our custom Outlook form will resemble the following image:
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.
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.
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.
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#)
9 Comments
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
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!
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.
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
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.
Hi,
Is it possible to save user properties on a custom email folder only without saving these properties on an email?
Best,
Chris
Hello Chris,
Please search for UserDefinedProperties in the text above.
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?
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.