Eugene Astafiev

How To: Set a custom icon for an Outlook folder in the Navigation Pane

Dear reader, today I want to show you one of the new features Outlook 2010 brought to programmers. Now Outlook allows setting custom icons the Navigation pane folders. The Outlook Object Model provides a special method for this task – SetCustomIcon. So, let’s start our journey into the Outlook programming world ;-)

Setting custom icons in Outlook – a bit of theory

The SetCustomIcon method is available at the MAPIFolder class level. This class also provides the opposite method for getting a custom icon – GetCustomIcon. However, today we will focus our attention on the setting a custom icon. The SetCustomIcon method accepts an instance of the IPictureDisp interface and doesn’t return anything. The VBA help reference (as well as the Outlook Object Model reference) provides a code to convert instances of .Net based classes to the IPictureDisp interface. Also you can find the sample solution (available for download at the end of article) which contains the entire code needed to get the job done.

Allowed types of images are icons and bitmaps. The size can be 32×32, 24×24 and 16×16. An appropriate size will be used depending on the DPI (Dots Per Inch) mode set on the PC. Outlook can scale up icons if a small image was set and Outlook is running in high DPI mode.

Not all Outlook folders accept custom icons

Not all folders allow you to set a custom icon. For example, I have tried to set a custom icon for the Inbox folder and immediately got the “Custom folder icon is not allowed…” exception:

Outlook exception: Custom folder icon is not allowed for a default or specified folder

A custom icon cannot be added to the following groups of folders in Outlook:

  • Default folders (see the OlDefaultFolders enumeration)
  • Special folders (see the OlSpecialFolders enumeration)
  • Exchange public folders
  • Exchange Root folders
  • Hidden folders

As you might have noticed there are no search folders on the list, which means you can set custom icons for Search folders. The same technique is used for solutions module folders.

Only in-process callers are allowed

The Outlook Object Model doesn’t allow setting a custom icon for a folder from another application (using the OLE Automation technology). Only the in-process code can be used for such a task. An exception will be thrown in the SetCustomIcon method in this case.

Set an icon each time Outlook is started

I would like to draw your attention to the fact that Outlook doesn’t store the icon set during a previous session. So, if you programmatically set an icon and then close Outlook, there will be no icon when you open it anew. That is why you need to set an icon on each Outlook startup. For example, I created a folder and set a custom icon for it. Here is how it looks in my Outlook 2010:

An Outlook folder with a custom icon

Then I close Outlook and when I reopen it anew (without the code which was used for creating a folder and setting an icon), no icon is there:

The custom icon is gone after restarting Outlook

The sample code in full details

Of course, I have prepared a sample code which shows how to set a custom icon for an Outlook folder. There are two main methods:

  1. The SetUpFolder method – is used for creating a new folder if no such folder was created earlier. If a folder with the same name already exists we just need to find it. The method accepts an instance of the Outlook Application.
  2. The SetCustomIcon method – is used for setting a custom icon for an Outlook folder (the name of our custom folder is “Smiling Folder”). It accepts an instance of the MAPIFolder class for which an icon should be set.

Note that if you try to add a folder and such a folder already exists, you will get an exception saying the folder cannot be created:

Outlook exception: Cannot create the folder

So, we need to find a folder first and only then, if there is folder with the same name, create it.

Below you can find a snippet of code developed in C# and VB.NET for VSTO and Add-in Express based add-ins. You can also download a complete solution which contains all the code including auxiliary code needed for converting images into the IPictureDisp interface. Note that I have included an image to the resources of each add-in project, so you won’t need to include it in the setup package manually. The image will be embedded into the add-in assembly automatically.

    C# and Add-in Express:
using System.Drawing;
//
private void SetUpFolder(Outlook._Application OutlookApp)
{
    Outlook.NameSpace ns = null;
    Outlook.MAPIFolder folderInbox = null;
    Outlook.MAPIFolder parent = null;
    Outlook.Folders rootFolders = null;
    Outlook.MAPIFolder smileFolder = null;
    try
    {
         ns = OutlookApp.GetNamespace("MAPI");
         folderInbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
         parent = folderInbox.Parent as Outlook.MAPIFolder;
         rootFolders = parent.Folders;
         for (int i = 1; rootFolders.Count >= i; i++)
         {
             smileFolder = rootFolders[i];
             if (smileFolder.Name == "Smiling Folder")
             {
                 break;
             }
             else
             {
                 Marshal.ReleaseComObject(smileFolder);
                 smileFolder = null;
             }
         }
         if (smileFolder == null)
         {
             smileFolder = rootFolders.Add("Smiling Folder");
         }
         SetCustomIcon(smileFolder);
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message, 
                      "An exception was thrown in the code...");
    }
    finally
    {
        if (smileFolder != null) Marshal.ReleaseComObject(smileFolder);
        if (rootFolders != null) Marshal.ReleaseComObject(rootFolders);
        if (folderInbox != null) Marshal.ReleaseComObject(folderInbox);
        if (ns != null) Marshal.ReleaseComObject(ns);
    }
}
 
private void SetCustomIcon(Outlook.MAPIFolder folder)
{
    Icon icon = null;
    try
    {
        icon = ADX_CSharp.Properties.Resources.SampleIcon1;
        stdole.StdPicture iconPictureDisp = PictureDispConverter.ToIPictureDisp(icon) 
                                                                as stdole.StdPicture;
        folder.SetCustomIcon(iconPictureDisp);
    }
    finally
    {
        icon.Dispose();
    }
}
    VB.NET and Add-in Express:
Imports System.Drawing
'
Private Sub SetUpFolder(OutlookApp As Outlook._Application)
    Dim ns As Outlook.NameSpace = Nothing
    Dim folderInbox As Outlook.MAPIFolder = Nothing
    Dim parent As Outlook.MAPIFolder = Nothing
    Dim rootFolders As Outlook.Folders = Nothing
    Dim smileFolder As Outlook.MAPIFolder = Nothing
    Try
        ns = OutlookApp.GetNamespace("MAPI")
        folderInbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
        parent = CType(folderInbox.Parent, Outlook.MAPIFolder)
        rootFolders = parent.Folders
        For i As Integer = 1 To rootFolders.Count
            smileFolder = rootFolders(i)
            If smileFolder.Name = "Smiling Folder" Then
                Exit For
            Else
                Marshal.ReleaseComObject(smileFolder)
                smileFolder = Nothing
            End If
        Next
        If IsNothing(smileFolder) Then
            smileFolder = rootFolders.Add("Smiling Folder")
        End If
        SetCustomIcon(smileFolder)
    Catch ex As Exception
        System.Windows.Forms.MessageBox.Show(ex.Message, _
                                      "An exception was thrown in the code...")
    Finally
        If Not IsNothing(smileFolder) Then Marshal.ReleaseComObject(smileFolder)
        If Not IsNothing(rootFolders) Then Marshal.ReleaseComObject(rootFolders)
        If Not IsNothing(folderInbox) Then Marshal.ReleaseComObject(folderInbox)
        If Not IsNothing(ns) Then Marshal.ReleaseComObject(ns)
    End Try
End Sub
 
Private Sub SetCustomIcon(folder As Outlook.MAPIFolder)
    Dim icon As Icon = Nothing
    Try
        icon = ADX_VBNET.My.Resources.SampleIcon1
        Dim iconPictureDisp As stdole.StdPicture = _
            CType(PictureDispConverter.ToIPictureDisp(icon), stdole.StdPicture)
        folder.SetCustomIcon(iconPictureDisp)
    Finally
        icon.Dispose()
    End Try
End Sub
    C# and VSTO:
using System.Runtime.InteropServices;
using System.Drawing;
//
private void SetUpFolder(Outlook.Application Application)
{
     Outlook.NameSpace ns = null;
     Outlook.MAPIFolder folderInbox = null;
     Outlook.MAPIFolder parent = null;
     Outlook.Folders rootFolders = null;
     Outlook.MAPIFolder smileFolder = null;
     try
     {
         ns = Application.GetNamespace("MAPI");
         folderInbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
         parent = folderInbox.Parent as Outlook.MAPIFolder;
         rootFolders = parent.Folders;
         for (int i = 1; rootFolders.Count >= i; i++)
         {
             smileFolder = rootFolders[i];
             if (smileFolder.Name == "Smiling Folder")
             {
                 break; 
             }
             else
             {
                 Marshal.ReleaseComObject(smileFolder);
                 smileFolder = null;
             }
         }
         if (smileFolder == null)
         {
             smileFolder = rootFolders.Add("Smiling Folder");
         }
         SetCustomIcon(smileFolder);
     }
     catch (Exception ex)
     {
         System.Windows.Forms.MessageBox.Show(ex.Message,
                              "An exception was thrown in the code...");
     }
     finally
     {
         if (smileFolder != null) Marshal.ReleaseComObject(smileFolder);
         if (rootFolders != null) Marshal.ReleaseComObject(rootFolders);
         if (folderInbox != null) Marshal.ReleaseComObject(folderInbox);
         if (ns != null) Marshal.ReleaseComObject(ns);
     }
}
 
private void SetCustomIcon(Outlook.MAPIFolder folder)
{
    Icon icon = null;
    try
    {
        icon = VSTO_CSharp.Properties.Resources.SampleIcon1;
        stdole.StdPicture iconPictureDisp = PictureDispConverter.ToIPictureDisp(icon) 
                                                                as stdole.StdPicture;
        folder.SetCustomIcon(iconPictureDisp);
    }
    finally
    {
        icon.Dispose();
    }
}
    VB.NET and VSTO:
Imports System.Drawing
Imports System.Runtime.InteropServices
'
Private Sub SetUpFolder(Application As Outlook.Application)
    Dim ns As Outlook.NameSpace = Nothing
    Dim folderInbox As Outlook.MAPIFolder = Nothing
    Dim parent As Outlook.MAPIFolder = Nothing
    Dim rootFolders As Outlook.Folders = Nothing
    Dim smileFolder As Outlook.MAPIFolder = Nothing
    Try
        ns = Application.GetNamespace("MAPI")
        folderInbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
        parent = CType(folderInbox.Parent, Outlook.MAPIFolder)
        rootFolders = parent.Folders
        For i As Integer = 1 To rootFolders.Count
            smileFolder = rootFolders(i)
            If smileFolder.Name = "Smiling Folder" Then
                Exit For
            Else
                Marshal.ReleaseComObject(smileFolder)
                smileFolder = Nothing
            End If
        Next
        If IsNothing(smileFolder) Then
            smileFolder = rootFolders.Add("Smiling Folder")
        End If
        SetCustomIcon(smileFolder)
    Catch ex As Exception
        System.Windows.Forms.MessageBox.Show(ex.Message, 
                                       "An exception was thrown in the code...")
    Finally
        If Not IsNothing(smileFolder) Then Marshal.ReleaseComObject(smileFolder)
        If Not IsNothing(rootFolders) Then Marshal.ReleaseComObject(rootFolders)
        If Not IsNothing(folderInbox) Then Marshal.ReleaseComObject(folderInbox)
        If Not IsNothing(ns) Then Marshal.ReleaseComObject(ns)
    End Try
End Sub
 
Private Sub SetCustomIcon(folder As Outlook.MAPIFolder)
    Dim icon As Icon = Nothing
    Try
        icon = My.Resources.SampleIcon1
        Dim iconPictureDisp As stdole.StdPicture = CType( _
            PictureDispConverter.ToIPictureDisp(icon), stdole.StdPicture)
        folder.SetCustomIcon(iconPictureDisp)
    Finally
        icon.Dispose()
    End Try
End Sub

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

Available downloads:

These sample COM Add-ins were developed using Add-in Express for Office and .net:

C# Outlook add-ins: VSTO and Add-in Express based
VB.NET Outlook add-ins: VSTO and Add-in Express based

You may also be interested in:

14 Comments

  • Naresh says:

    Hi,
    I want to add image of email,like if email is in Inbox it has image,and if image is sent mail then it have different image. Like that i put a custom button on ribbon of outlook on clicking of the button i need to set a image to that particular email.

    Kindly help me in this.
    Thanks in advance.

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

    Hi Naresh,

    There is no trivial way to change an email item’s icon on the fly. You can try to create and publish an Outlook custom form containing custom icons and then change the email’s MessageClass property so that it uses the icons from that published form.

  • Silvio says:

    Hi, i’m having some trouble with attaching icons on outlook startup.

    I’m doing the following:

    1.- Load my custom .pst store into outlook
    2.- Get a Store object reference to that loaded .pst
    3.- Save the store.GetRootFolder() reference in a class private attibute.

    I call this methods with a reference to the store root folder:

    public static void AttachAllIconsRecursively(Folder root)
    {
    //attach icon
    FoldersUtil.AttachFolderIcon(root, SystemIcons.Warning);

    //Recursive Call to subfolders
    Folders children = root.Folders;

    for (int i = 1; i <= children.Count; i++)
    {
    Folder item = children[i] as Folder;
    AttachAllIconsRecursively(item);
    }

    if (children != null)
    {
    Marshal.ReleaseComObject(children);
    children = null;
    }
    }

    public static void AttachFolderIcon(Folder folder, Icon icon)
    {
    try
    {
    stdole.StdPicture iconPictureDisp = PictureDispConverter.ToIPictureDisp(icon) as stdole.StdPicture;
    folder.SetCustomIcon(iconPictureDisp);
    }
    catch (System.Exception e)
    {
    //…manage error
    }
    }

    It worked just fine until now.
    I'm getting this exception
    "El icono de carpeta personalizada no se permite para una carpeta que no se muestra en la interfaz de usuario de Outlook"

    in english it would be something like "The custom folder icon it's not allowed for a non-visible folder in the outlook user interface", i'm guessing outlook does not load it's UI before this method call, and the folder's tree in the pst it's not being shown at that time.

    Can you please tell me if there is any solution to this ?

    Thanks in advance.

    Silvio.

  • Eugene Astafiev says:

    Hi Silvio,

    First of all, thank you for reading my posts on our technical blog!

    Please take a look at the SetCustomIcon description in MSDN. It states:

    You can only call SetCustomIcon from code that runs in-process as Outlook. An IPictureDisp object cannot be marshaled across process boundaries. If you attempt to call SetCustomIcon from out-of-process code, an exception will occur.

    Is this the case? Do you develop a COM add-in or VBA macro?

  • Silvio says:

    Hi Eugene,

    Thanks to you for writing them! Them are really useful beccause microsoft does not provide real examples like this.

    I believe it runs in the same thread as the outlook plugin, i’m calling it from thisaddin_startup method and also from a RunWorkerCompleted event of a backgroundworker, i believe this event is handled by the .RunWorkerAsync() caller thread.

    I’m developing a plugin with ms visual studio 2010 and vsto 4.0, a outlook plugin project, i’m working with microsoft.interop… so i guess it’s a com add-in wrapped into C#. Is there any post about the com object referencing and how to use marshal.releasecomobject right?

    Thanks for your answer!

    Silvio

  • Eugene Astafiev says:

    Hi Silvio,

    Please take a look at the When to release COM objects in Office add-ins developed in .NET on our technical blog for more information about this.

    If you develop a COM add-in (VSTO based one), why isn’t there any Outlook window visible at the moment you’re trying to set icons? How do you run Outlook?

  • Silvio says:

    Hi,

    Thanks, i will read it.

    I click start on VS 2010, outlook is loaded with a fresh build from VS. There is a outlook window, but it’s the splash with the text “Loading plugins…”.
    When i said that it was no window, i meant that the main outlook window (The Explorer) with all the folder tree’s is not loaded yet.

    Any mistakes in this way of running the plugin?

    Thanks for the answer!

    Silvio

  • Eugene Astafiev says:

    Hi Silvio,

    Thank you for the explanation.

    What event handler do you use for setting icons in Outlook?

    It looks like you need to use the Startup event of the Application class. Am I right?

  • Silvio says:

    Yes, you are rigth, i’m using the startup event to call the method posted above.
    Does that method fires before outlook explorer UI is loaded?

    Greetings.

    Silvio

  • Eugene Astafiev says:

    Hi Silvio,

    No, it doesn’t.

    Sorry, but I can’t diagnose the issue off the top of my head. I would recommend you contact our support team by email or forum. Please understand that the cause of the issue could be in your code.

    Also please make sure that you have installed all the latest service packs for Outlook, OS and .Net.

  • Silvio says:

    Thanks,

    a last question, the problem seems to be that when i load the store with
    Session.AddStoreEx(path, Microsoft.Office.Interop.Outlook.OlStoreType.olStoreUnicode);
    the store shows in the UI, but closed ( i mean, the tree is all collapsed ) . any way to programatically expand the tree?.

    I will contact the support team for further questions, can you please email me the address where i have to send the email’s.

    Thanks again.

    Silvio

  • Eugene Astafiev says:

    Hello Silvio,

    Please use the CurrentFolder property of the Explorer class to select the folder programmatically.

  • Dritan says:

    Hi Eugene,

    i have download your example (ADX_VB.NET) to run im my pc but appear the error below :

    System.AccessViolationException was unhandled by user code
    HResult=-2147467261
    Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
    Source=Microsoft.Office.Interop.Outlook
    StackTrace:
    at Microsoft.Office.Interop.Outlook.MAPIFolder.SetCustomIcon(StdPicture Picture)
    at ADX_VBNET.AddinModule.SetCustomIcon(MAPIFolder folder) in H:\VB PROJECT\KODE VB.NET\adx-net-sample-projects\adx_outlook_set-custom-icon_vb\ADX_VB.NET\AddinModule.vb:line 175
    at ADX_VBNET.AddinModule.SetUpFolder(_Application OutlookApp) in H:\VB PROJECT\KODE VB.NET\adx-net-sample-projects\adx_outlook_set-custom-icon_vb\ADX_VB.NET\AddinModule.vb:line 159
    at ADX_VBNET.AddinModule.AdxCommandBarButton1_Click(Object sender) in H:\VB PROJECT\KODE VB.NET\adx-net-sample-projects\adx_outlook_set-custom-icon_vb\ADX_VB.NET\AddinModule.vb:line 186
    at AddinExpress.MSO.ADXCommandBarButton.OnButtonClick(ICommandBarButton button, Boolean& handled)
    InnerException:

    I use Visual Studio 2012 with ms office 2007.
    Can you help me please?

    Best regards
    Dritan

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

    Hi Dritan,

    Outlook 2007 does not support custom icons. This feature was added to the Outlook 2010 Object Model.

Post a comment

Have any questions? Ask us right now!