Programmatically Adding a Column to Your Outlook 2007 Inbox Table View

In my previous post, I mentioned that I will write an article about adding a new column to your inbox. Here you go!

What we will achieve

Quite simple. Take a look at below screenshot and you will notice that a new column, SubjectLength, is added to the inbox. Its values are the length of individual email’s subject.

Add a column to inbox table

How table view is displayed

This backs to the traditional (but useful) discussion of data and view. In view side, we need add a new column to table view via ViewFields.Insert method. In data side, we can easily add a new user property via MailItem.PropertyAccessor. Now the question is how to correlate view with data? The trick here is MAPI property namespace. They both can be referenced this way. OK, now let us talk about details in code.

Step 1: Add new user property to the inbox folder

Before we add new property to the view or items inside a folder, we have to add that property to the folder first. (Assume theFolder is inbox folder we get before hand)

private void AddUserPropertyToFolder(Outlook.Folder theFolder, string userPropertyName)

{

if (null == theFolder || string.IsNullOrEmpty(userPropertyName))

{

return;

}

// If the user property is not there, create it.

Outlook.UserDefinedProperty nameLengthProperty = null;

try

{

nameLengthProperty = theFolder.UserDefinedProperties[userPropertyName];

}

catch (Exception ex)

{

Debug.WriteLine("The UserProperty is not there." + ex.Message + ex.StackTrace);

}

if (nameLengthProperty == null)

{

try

{

theFolder.UserDefinedProperties.Add(userPropertyName,

Outlook.OlUserPropertyType.olText,

Type.Missing,

Type.Missing);

}

catch (System.Exception exc)

{

Debug.WriteLine("Error in creating User Property:" + exc.Message + exc.StackTrace);

}

}

}

Step 2: Add a new field to the inbox table view

Since the inbox folder gets a new user property, we can go ahead to add new field to the inbox table view.

private void AddOneColumnToView(Outlook.Folder theFolder, string userPropertyName)

{

const int newColumnIndex = 1;

if (null == theFolder || string.IsNullOrEmpty(userPropertyName))

{

return;

}

// Update the current view

// IMPORTANT: Actually modifying current view is not a encouraged practice

// In production code, you'd better clone a new view and change that new one

try

{

Outlook.TableView currentView = theFolder.CurrentView as Outlook.TableView;

currentView.ViewFields.Insert(userPropertyName, newColumnIndex);

currentView.Save();

currentView.Apply();

}

catch (Exception exc)

{

Debug.WriteLine("Fail to update view: " + exc.Message + exc.StackTrace);

}

}

Step 3: Get the prop of newly added column

As we talked about early, MAPI property is the way to connect view and data. So we need get the prop first. If you print the View.XML out, you will find the XML schema is pretty straightforward like below:

<?xml version="1.0" encoding="utf-8"?>

<view type="table">

  <viewname>Sent To</viewname>

  <!-- Other elements ommitted -->

  <column>

    <heading>SubjectLength</heading>

    <prop>http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/SubjectLength</prop>

    <type>string</type>

    <width>50</width>

    <style>padding-left:3px;;text-align:left</style>

    <editable>0</editable>

  </column>

  <column>

    <maxrows>1919942656</maxrows>

    <heading>Subject</heading>

    <prop>urn:schemas:httpmail:subject</prop>

    <type>string</type>

    <width>226</width>

    <style>padding-left:3px;;text-align:left</style>

    <editable>1</editable>

  </column>

  <column>

    <maxrows>1010302976</maxrows>

    <heading>Sent</heading>

    <prop>urn:schemas:httpmail:date</prop>

    <type>datetime</type>

    <width>110</width>

    <style>padding-left:3px;;text-align:left</style>

    <editable>0</editable>

    <format>M/d/yyyy||h:mm tt</format>

    <displayformat>2</displayformat>

  </column>

</view>

If this is case, below LINQ query code can get highlighted prop ID out. (Yeah, you are right that we need .NET3.5 to run the code.)

private string GetColumnProp(Outlook.Folder theFolder, string userPropertyName)

{

if (null == theFolder || string.IsNullOrEmpty(userPropertyName))

{

return null;

}

// Get LINQ XML elements

XElement folderViewXElement = XElement.Parse(theFolder.CurrentView.XML);

var props = from Columns in folderViewXElement.Elements("column")

where (string)Columns.Element("heading") == userPropertyName

select Columns.Element("prop");

// Return the first element which should be the only one

foreach (var prop in props)

{

return prop.Value;

}

return null;

}

Step 4: Create user property in items with the prop ID

private void AddUserPropertyValuesToItems(Outlook.Folder theFolder, string propName)

{

if (null == theFolder || string.IsNullOrEmpty(propName))

{

return;

}

// Create user property on all mails

Outlook.Items items = theFolder.Items;

string columnProp = this.GetColumnProp(theFolder, propName);

if (null != columnProp)

{

foreach (Outlook.MailItem theMail in items)

{

try

{

Outlook.PropertyAccessor oPA = theMail.PropertyAccessor;

oPA.SetProperty(columnProp, theMail.Subject.Length.ToString());

theMail.Save();

Debug.WriteLine("Mail property is set: " + theMail.Subject);

}

catch (Exception ex)

{

Debug.WriteLine("Set mail property goes wrong." + ex.Message + ex.StackTrace);

}

}

}

}

Finally, put above code into the addin entry point which is ThisAddIn_Startup by default, it will do the magic for you.

That is it. Solution file can be found at:

http://www.codeplex.com/bali/SourceControl/changeset/view/10689