Click here to Skip to main content
Click here to Skip to main content

Outlook Automation

, 19 Jun 2009
Rate this:
Please Sign up or sign in to vote.
This article shows how to automate Outlook using VS2008 rather than VSTO or VBA

Introduction

This article is intended to assist VS2008 programmers inspired to enhance Microsoft Outlook by offering an easily implemented class radically simplifying the otherwise rather tedious (and error-prone) implementation of buttons and popups in Outlook's Menu Bars.

Background

Microsoft Outlook is a rich developer platform offering ample opportunities to improve on the built-in functionality of this mainstream information management program. There are three ways to pursue this opportunity:

  • Developing add-ins using VSTO
  • Writing VBA code
  • Developing automation executables using Visual Studio 2008

The relative merits of these three strategies are nicely discussed by E.Carter & E.Lippert [1] however with emphasis on add-in development with VSTO. The development of add-ins seems notoriously difficult: debugging is non-trivial and proper registration on the target machine tends to be fickle. Using VBA is rather limiting as it does not currently offer full access to the .NET platform. Developing automation executables with VS2008 seems to be the best of all worlds: it is a development environment we are comfortable with and provides access to the full range of debugging techniques offered by the VS2008 Integrated Development Environment. In addition, if the end-product must be an add-in, the resulting code can be relatively easily ported once it is fully debugged.

Using the Code

The code I am presenting here is intended to provide you with the framework needed to develop your own automation products. You need to add the following references to your VS2008 project:

  • Microsoft Office 11.0 (or 12.0) Object Library
  • Microsoft Outlook 11.0 (or 12.0) Object Library

The code is organized as a single class (OutlookMenuExtensions_Class_src.cs) which accomplishes the following essential steps:

  • It checks whether the user has provided non-empty captions for a single custom menu button and/or a custom popup menu item and the associated pull-down menu items.
  • It either marshals to an already running instance of Outlook or creates a new instance of Outlook (there can only be one running at a time).
  • It ensures that the requested menu items are added to the "Main Menu" commandbars of the Outlook application (for both explorer and inspector instances). The associated CommandBarButton objects are stored in a List of type Office.CommandBarButton.

The code instantiating the OutlookMenuExtensions class needs to define the captions of the single menu button and/or of the popup menu and the associated menu items for both Outlook explorers and inspectors. The event wiring is best accomplished by wiring all similar buttons to a single click-event handler which then needs to differentiate between the buttons firing the event by using their Tag property (see more details below).

I have included an implementation example (ImplementationExample_src.cs). Here is the main part of the code (I will explain the reason for the reference to the API method SetForegroundWindow, the details behind the WaitForEvents() method, and the commented lines referencing the LicenseGenie class later).

public YourApplication()
{
    //LicenseGenie myLicenseGenie = new LicenseGenie();
    //if (!myLicenseGenie.LicenseIsValid()) return;

    //Explorer Menu Items
    oL.NewExplorerMenuItem_Caption = "My Explorer Button";
    oL.NewExplorerMenuItem_Tag = "My Explorer Button";
    oL.NewExplorerMenuPopUp_Caption = "My Explorer Popup";
    oL.NewExplorerPopupMenuItem_Captions = new string[3]
    	{ "Explorer Item 1", "Explorer Item 2", "Explorer Item 3" };
    oL.NewExplorerPopupMenuItem_Tags = new string[3]
    	{ "Explorer Item 1", "Explorer Item 2", "Explorer Item 3" };

    //Inspector Menu Items
    oL.NewInspectorMenuItem_Caption = "My Inspector Button";
    oL.NewInspectorMenuItem_Tag = "My Inspector Button";
    oL.NewInspectorMenuPopUp_Caption = "My Inspector Popup";
    oL.NewInspectorPopupMenuItem_Captions = new string[3]
    	{ "Inspector Item 1", "Inspector Item 2", "Inspector Item 3" };
    oL.NewInspectorPopupMenuItem_Tags = new string[3]
    	{ "Inspector Item 1", "Inspector Item 2", "Inspector Item 3" };

    oL.SetupMenus();

    if (!oL.LaunchSuccessful) return;

    //Now wire up the event handlers
    oL.c_NewExplorerMenuItem[0].Click +=
    	new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler
						(Explorer_Menu_Click);
    for (int i=0; i < oL.NewExplorerPopupMenuItem_Captions.Length;i++)
        oL.c_NewExplorerPopUpMenuItem[i].Click +=
        	new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler
						(Explorer_Menu_Click);

    oL.c_NewInspectorMenuItem[0].Click +=
    	new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler
						(Inspector_Menu_Click);
    for (int i = 0; i < oL.NewInspectorPopupMenuItem_Captions.Length; i++)
        oL.c_NewInspectorPopUpMenuItem[i].Click +=
        	new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler
						(Inspector_Menu_Click);

    c_Outlook = oL.c_App;

    WaitForEvents();
}

Your custom code is easily implemented in the click handlers. I recommend to use a separate handler for the explorer and the inspector menu controls. It is left up to you to determine whether the custom method associated with a particular menu button is appropriate for the current context. I recommend you use c_Outlook.ActiveExplorer().Caption or c_Outlook.ActiveInspector().Caption, respectively, to make that determination.

In my implementation example (Program.cs) I used generic click handlers which simply display a form indicating which button the user pressed. For reasons I was unable to determine, it turned out that this could NOT be properly accomplished with a call to:

MessageBox.Show("User clicked " + Ctrl.Tag)

The MessageBox would not reliably bubble up to the top of the windows stack the first time a button was pressed after the launch of the application (it would work just fine on subsequent clicks. I remedied this by wiring the Activated event of the custom form (named 'alert') to the following event handler which ensured, by making use of the API function SetForegroundWindow that the alert form always bubbles up to the top.

void alert_Activated(object sender, EventArgs e)
{
    SetForegroundWindow(((Form)sender).Handle.ToInt32());
}

The code for the WaitForEvents() method is straightforward. It simply is intended to ensure that your application listens to the events fired by the Outlook application AND that your application closes when the user closed the Outlook application (which I assumed to be the case when the Outlook application no longer shows any explorer or inspector windows; in reality Outlook can persist when e.g. if the user did not respond to all reminders).

private void WaitForEvents()
{
    do
    {
        Application.DoEvents();
        if (c_Outlook.Explorers.Count == 0 & c_Outlook.Inspectors.Count == 0)
        {
            MessageBox.Show("User just terminated the last Outlook session\
            	nand hence this Outlook Sidekick is going to close as well.");
            ((Microsoft.Office.Interop.Outlook._Application)c_Outlook).Quit();
            break;
        }
        Thread.Sleep(500);
    } while (true);
}

Finally, as promised, a few words about the commented lines referring to a class I am calling LicenseGenie. Implementing this class as shown would incorporate a complete user license management framework into your application without having to write any additional code! If you find this intriguing, I invite you to find out more about LicenseGenie on SoarentComputing's web site.

An application implementing the OutlookMenuExtensions class can be found on SoarentComputing's web site. It is called OutlookSidekick2009 and offers two helpful additions to Outlook:

  • It eliminates the multi-step cut-and-paste process normally required to create calendar entries from e-mail messages containing meeting invitations from clients that don't use the meeting request features built into Outlook, and
  • It intercepts outgoing e-mail messages when the user forgets to include attachments promised in the e-mail.

Points of Interest

Since I have made the code of the OutlookMenuExtensions class available for anyone interested in studying it in more detail, I will include here just a few remarks.

Of all applications in the Microsoft Office Suite, Outlook is arguably the most complex in regard to its commandbar architecture (while Excel is arguably the least complex). Each of Outlook's explorers (e.g. Inbox, Calendar, Contacts, etc.) has its own command bars. The same holds for Outlook's inspectors (i.e. the detailed views for any of the items stored in Outlook (e.g. mail items, calendar items, contact items, etc.). The user can open a seemingly unlimited number of Outlook explorers and inspectors.

When starting on this project, I had been under the impression that there might be one master command bar for both explorers and inspectors one could extend to include custom buttons and popup menus, but it turned out that each explorer and inspector uses by default the original explorer and inspector Menu Bar which then needed to be extended for each new instance. This scenario can easily become a nightmare for the developer who is trying to extend the associated commandbars with menu buttons that remain consistently accessible. The number of CommandBarButton controls need to scale with the number of opened explorers and inspectors. This was however readily accomplished by using Lists of type Office.CommandBarButton for the custom menu controls. To simplify matters, I decided not to bother to delete any CommandBarButtons that were no longer used when the user closed the explorer or inspector whose Menu Bar those buttons were associated with. This clearly is a potential memory hog, but I figured that under normal Outlook usage, this should not become an issue.

Inspite of this rather large number of CommandBarButtons only the first single custom menu button and only the first set of the custom popup menu items need to be wired up explicitly, because the Tag property is identical for the repeated items. In fact trying to wire up more than the first set of buttons would result in multiple firing.

I already mentioned the surprise I encountered when a MessageBox shown by the application would not bubble up to the top of the window stack only the first time it was activated and described how I solved this nuisance. I was however unable to resolve another windows nuisance. Whenever a new inspector is launched from an open Outlook explorer, the subsequent clicking of one of the custom CommandBarButtons has an undesired effect: once the click-event handler completes its task, Outlook returns to explorer the new inspector was launched from, but only the first time! It would have been nice to prevent this, but I eventually gave up, and am now hoping that somebody reading this might be able to suggest a solution.

I need to make one more point regarding the threading apartment of this code. It turns out that in spite of my efforts to ensure that the process instantiating OutlookMenuExtensions uses the single-threaded apartment (STA) model by using various methods including the inserting of [STAThreadAttribute] in front of the Main method, the thread representing the Outlook process was using the multi-threaded apartment (MTA) model. Therefore the methods handling Outlook events could not include any methods that required the STA model (e.g. any methods of the Clipboard class).

References

[1] "Visual Studio Tools for Office 2007: VSTO for Excel, Word and Outlook", E.Carter & E.Lippert, Addison-Wesley, 2009

[2] "Programming Applications for Microsoft Office Outlook 2007", R. Byrne & R. Gregg, Microsoft Press, 2007

History

  • First revision published in June 2009

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Rolf_atSC

United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmemberDave Crump7-Dec-12 0:57 
QuestionSearch into all created dir and sub_dir.... PinmemberDave Crump7-Dec-12 0:54 
GeneralChaaching! Two thumbs straight up!! PinmemberRedDK15-Oct-10 7:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140709.1 | Last Updated 19 Jun 2009
Article Copyright 2009 by Rolf_atSC
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid