Pieter van der Westhuizen

Outlook Items and Folders events explained: C# code sample

In this post, we’ll have a closer look at two classes provided by Add-in Express: the Outlook Folders Events class and the Outlook Items Events class. I’ll be using Add-in Express for Office and .Net and Visual Studio 2010.

First, let’s create a new COM Add-in in Visual Studio:

Creating a new add-in project

In the first prompt of the New Microsoft Office COM Add-in project wizard, select your programming language and the Minimum Office version you would like to support. Today we’ll be using Visual C# and Microsoft Office 2007.

Selecting your programming language

Since the Outlook ItemEvents and FolderEvents classes are only available for Microsoft Outlook we’ll choose Microsoft Outlook from the list of Supported Applications.

Selecting Microsoft Outlook in the Supported Applications list

Outlook Items Events class

Add a new Outlook Items Events Class to your project by Selecting Add New Item… from the Visual Studio Project menu. The item template is under Add-in Express Items > Outlook.

Adding a new Outlook Items Events Class to your project

In order to use the Outlook Items Events Class we need to add some code to the AddinModule class.

First declare the Outlook Items Events class we’ve just added:

OutlookItemsEventsClass itemsEvents = null;

Switch to the AddinModule designer and double-click in its AddinStartupComplete event in the property grid to generate an empty event handler.

Add the following code to the AddinStartupComplete event handler:

private void AddinModule_AddinStartupComplete(object sender, EventArgs e)
{            
    itemsEvents = new OutlookItemsEventsClass(this);
    itemsEvents.ConnectTo(ADXOlDefaultFolders.olFolderContacts, true);
}

We also need to add an event handler for the AddinBeginShutdown event and insert the following code:

private void AddinModule_AddinBeginShutdown(object sender, EventArgs e)
{
    if (itemsEvents != null)
    {
        itemsEvents.RemoveConnection();
        itemsEvents.Dispose();
    }
}

Now that we’ve added all the necessary code to the AddinModule class, open the Outlook Items Events class we’ve added earlier and let’s have a look at the Items Events.

ProcessItemAdd

This event occurs when one or more items are added to the specific folder. A reference to the newly added item is passed as a parameter. Be careful though because this event does not fire when a large number of items are added to the folder at once. This is one of the reasons this event is not reliable when checking for new mail. You can read more about it in Eugene’s post: Handling NewMail, NewMailEx and ItemAdd Outlook events in .NET. We’ll investigate the NewMail challenge later in a series of posts.

C# code example

public override void ProcessItemAdd(object item)
{
    if (item is Outlook._ContactItem)
    {
        Outlook._ContactItem newContact = (Outlook._ContactItem)item;
        Outlook._Application outlookApp = ((AddinModule)this.Module).OutlookApp;
        Outlook.MAPIFolder targetFolder = (Outlook.MAPIFolder)this.FolderObj;
        Outlook._JournalItem journalItem = null;
 
        try
        {
            journalItem = (Outlook._JournalItem)outlookApp.CreateItem(
				Outlook.OlItemType.olJournalItem);
            journalItem.Subject = String.Format("You've added {0} to {1}", 
                newContact.FullName, targetFolder.FolderPath);
            journalItem.Save();
        }
        finally
        {
            if (journalItem != null)
                Marshal.ReleaseComObject(journalItem);
        }
    }
}

ProcessItemChange

This event is fired when an item in the specified folder is changed. A reference to the changed item is passed as a parameter.

public override void ProcessItemChange(object item)
{
    if (item is Outlook._ContactItem)
    {
        Outlook._ContactItem changedContact = (Outlook._ContactItem)item;
 
        if (String.IsNullOrEmpty(changedContact.JobTitle))
        {
            MessageBox.Show(String.Format(
				"Please add a job title for {0}. All contacts must have proper titles",
                 changedContact.FullName), 
				 "Title Required");
        }
    }
}

ProcessItemRemove

This event is the opposite of the ProcessItemAdd event and occurs when an item is deleted from a specified folder. As with the ProcessItemAdd event, this event does not fire when more than 16 items are deleted at once. It also does not fire when the last item in a .pst file is deleted. Unfortunately this event does not give us any reference to the items that has been deleted.

C# code example

public override void ProcessItemRemove()
{
    Outlook._Application outlookApp = ((AddinModule)this.Module).OutlookApp;
    Outlook.MAPIFolder targetFolder = (Outlook.MAPIFolder)this.FolderObj;
    Outlook._JournalItem journalItem = null;
 
    try
    {
        journalItem = (Outlook._JournalItem)outlookApp.CreateItem(
			Outlook.OlItemType.olJournalItem);
        journalItem.Subject = String.Format("You've removed items from {0}", 
			targetFolder.FolderPath);
        journalItem.Save();
    }
    finally
    {
        if (journalItem != null)
            Marshal.ReleaseComObject(journalItem);
 
    }
}

ProcessBeforeItemMove

In Outlook 2007-2010 you can use the ProcessBeforeItemMove event to determine when an item is about to be deleted or moved from a folder. A reference to the item being moved is passed as a parameter as well as a reference to the folder it is being moved to. If the item is deleted permanently the MoveTo parameter will be Null or Nothing in Visual Basic.

C# code example

public override void ProcessBeforeItemMove(object item, object moveTo,
	AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (item is Outlook._ContactItem)
    {
        Outlook._ContactItem movedContact = (Outlook._ContactItem)item;
        Outlook._Application outlookApp = ((AddinModule)this.Module).OutlookApp;
        Outlook._JournalItem journalItem = null;
 
        try
        {
            journalItem = (Outlook._JournalItem)outlookApp.CreateItem(
				Outlook.OlItemType.olJournalItem);
            if (moveTo != null)
            {
                Outlook.MAPIFolder targetFolder = (Outlook.MAPIFolder)moveTo;
                journalItem.Subject = String.Format("You've moved {0} to {1}",
                    movedContact.FullName, targetFolder.FolderPath);
                Marshal.ReleaseComObject(moveTo);
            }
            else
            {
                journalItem.Subject = String.Format(
					"You've permanently deleted {0}", movedContact.FullName);
            }
            journalItem.Save();
        }
        finally
        {
            if (journalItem != null)
                Marshal.ReleaseComObject(journalItem);
        }
    }
}

ProcessBeforeFolderMove

This event occurs when a folder is about to be deleted or moved. A reference to the folder it is being moved to, is passed as a parameter. As with the ProcessBeforeItemMove event, if the MoveTo parameter is Null or Nothing in Visual Basic, it means the folder has been permanently deleted.

public override void ProcessBeforeFolderMove(object moveTo,
	AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (this.FolderObj != null)
    {
        Outlook._Application outlookApp = ((AddinModule)this.Module).OutlookApp;
        Outlook._JournalItem journalItem = null;
 
        try
        {
            journalItem = (Outlook._JournalItem)outlookApp.CreateItem(
				Outlook.OlItemType.olJournalItem);
            if (moveTo != null)
            {
                Outlook.MAPIFolder targetFolder = (Outlook.MAPIFolder)moveTo;
                journalItem.Subject = String.Format(
					"You've moved the folder to {1}", targetFolder.FolderPath);
            }
            else
            {
                Outlook.MAPIFolder deletedFolder = (Outlook.MAPIFolder)this.FolderObj;
                journalItem.Subject = String.Format(
					"You've permanently deleted {0}", deletedFolder.FolderPath);
            }
        }
        finally
        {
            if (journalItem != null)
                Marshal.ReleaseComObject(journalItem);
        }
    }
}

You can read more about these events here and here.

Outlook Folders Events class

Add a new Outlook Folder Events Class to your project by Selecting Add New Item… from the Visual Studio Project menu. The item template is under Add-in Express Items > Outlook.

Adding a new Outlook Folder Events Class to your project

Declare the Folders event class:

OutlookFoldersEventsClass folderEvents = null;

Add the following code to the AddinStartupComplete event handler of the AddinModule class:

if (folderEvents != null)
{
    folderEvents = new OutlookFoldersEventsClass(this);
    Outlook.NameSpace ns = OutlookApp.GetNamespace("MAPI");
    Outlook.MAPIFolder folderContacts = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);                        
    folderEvents.ConnectTo(folderContacts, true);
    if (ns != null) Marshal.ReleaseComObject(ns);
}

As with the Outlook Items event class we need to properly remove any connections when our add-in shuts down, so add the following to the AddinBeginShutdown event handler:

if (folderEvents != null)
{
    folderEvents.RemoveConnection();
    folderEvents.Dispose();
}

With all the necessary code added, we can have a look at the Folder events.

ProcessFolderAdd

This event occurs when a folder is added to the specified folder. A reference to the newly added folder is passed as a parameter.

public override void ProcessFolderAdd(object folder)
{
    if (folder != null)
    {
        Outlook.MAPIFolder newFolder = (Outlook.MAPIFolder)folder;
        Outlook.MAPIFolder parentFolder = (Outlook.MAPIFolder)this.FolderObj;
 
        MessageBox.Show(String.Format("You've added a sub folder called {0} to {1}", 
                        newFolder.Name, parentFolder.FolderPath));
    }
}

ProcessFolderChange

The ProcessFolderChange event is raised when a folder is changed. The changes include when a folder was renamed or when an item was added, renamed or removed from the folder. A reference to the changed folder is passed as a parameter.

public override void ProcessFolderChange(object folder)
{
    if (folder != null)
    {
        Outlook.MAPIFolder changedFolder = (Outlook.MAPIFolder)folder;
        Outlook.MAPIFolder parentFolder = (Outlook.MAPIFolder)this.FolderObj;
 
        MessageBox.Show(String.Format("The {0} folder in {1} has changed", 
            changedFolder.Name, parentFolder.FolderPath)); 
    }
}

ProcessFolderRemove

As the name of the event suggests, it is raised when a folder is removed from the specified folders collection. Unfortunately no reference to the folder is passed.

public override void ProcessFolderRemove()
{
    Outlook.MAPIFolder parentFolder = (Outlook.MAPIFolder)this.FolderObj;
    MessageBox.Show("A subfolder has been removed from " + parentFolder.FolderPath);
}

On MSDN you can read more about the Folders events.

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

Available downloads:

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

You may also be interested in:

13 Comments

  • http://1.gravatar.com/avatar/f036e5d3f11b2a7c0024db4c2b6f4eaa?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Emil Nachev says:

    These events not works if account is not from Exchange server.

  • http://0.gravatar.com/avatar/ab4ec2858cfdf1e44dadf8c50fae314d?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Dmitry Kostochko (Add-in Express Team) says:

    Hi Emil,

    As far as I remember, these Outlook events are not dependent on the account type. We tested our code with Exchange accounts and usual POP3 accounts, the events work in both cases. Could you please tell me which event does not work in your case?

  • http://0.gravatar.com/avatar/6e70bfbfc88b846647c583c716a9091b?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Kasun says:

    I’m using ProcessBeforeFolderMove event for a folder which have subfolders. Event fires when I’m trying to move one of that sub folder.
    But when I’m accessing the FolderObj it gives me the parent folder. Is there any way to get the actual sub folder which is moving?

    I was trying to use adxOutlookEvents_ExplorerFolderSwitch event to store the current item. but when I’m trying to move it from FolderList ExplorerFolderSwitch doesnot fires.

    Any suggesstions?

  • http://0.gravatar.com/avatar/ab4ec2858cfdf1e44dadf8c50fae314d?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Dmitry Kostochko (Add-in Express Team) says:

    Hi Kasun,

    I would suggest connecting to all Outlook sub-folders in your code by using multiple instances of the ADXOutlookItemsEvents class. If you face any difficulties with implementation, please contact our support team and we will create a sample for you.

  • Hi,

    I use ADXOutlookFoldersEvents to get Public Folders updates online. So the top folder is connected recursively to be sure all subfolders are watched. However, when I try to open several subfolders in Outlook GUI I receive the following message:

    Cannot expand the folder. Your server administrator has limited the number of items you can open simultaneously. Try closing messages you have opened or removing attachments and images from unsent messages you are composing.

    If I remove my event handler it works OK. Looks like your code add some restriction on using Public Folders. I cannot find any information about ADXOutlookFoldersEvents in terms of this or similar issues in your documentation.

  • http://0.gravatar.com/avatar/ab4ec2858cfdf1e44dadf8c50fae314d?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Dmitry Kostochko (Add-in Express Team) says:

    Hi Mikhail,

    The ADXOutlookFoldersEvents component does not add any restrictions on using Outlook folders, it does exactly what you tell it to do – get events from the root folder and all its sub-folders. Most likely the limitation on the number of folders being accessed is set on your Exchange Server by your administrator. I can suggest two ways of dealing with it:

    - remove the limitation or allow to access more folders simultaneously on your Exchange Server;
    - connect the ADXOutlookFoldersEvents component only to the needed folders rather than all folders.

    Hope this helps.

  • Hi Dmitry,

    Thanks for your answer. Unfortunately I have no access to Exchange Server and cannot even know what exactly the limit is.

    However, it looks like the ADXOutlookFoldersEvents does something that Outlook considers as item opening. Probably there could be unexpected behavior if ADXOutlookFoldersEvents would try to handle all public folders recursively and the amount of folders exceeds Exchange Server limitations. It’s a potentially danger scenario. So I can conclude there is no way to handle changes for all Public Folders not for limited number of ones. At least by ADXOutlookFoldersEvents mechanism.

    Thanks.

  • http://0.gravatar.com/avatar/ab4ec2858cfdf1e44dadf8c50fae314d?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Dmitry Kostochko (Add-in Express Team) says:

    Hi Michail,

    >> However, it looks like the ADXOutlookFoldersEvents does something that Outlook considers as item opening.

    Of course, this component connects to Outlook folders in order to handle their events. The error message about the limited number of items actually means any and all Outlook items including folders.

    Also, I think the problem is not in the ADXOutlookFoldersEvents mechanism but in the limitation set directly on the Exchange Server. If you have a restriction of 2 items your code will be able to handle only 2 folders. Please consider reviewing and tweaking the logic of your code.

  • http://0.gravatar.com/avatar/c88821013fd072566250b942788415c4?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Mike Leedham says:

    Hi
    Forgive me if this question seems bit basic, but this is my first attempt at an Add-In Express Add-In.

    I have written some code in the AddInModule to (amongst other things) allow an appointment item to be copied from the default calendar to a public calendar. This is working OK from both the Inspector and Explorer. I now want to monitor if the original appointment is deleted or moved so have added an OutlookItemsEventsClass1 and linked it to the default folder (as per your example) and am able to successfully trap the ProcessBeforeItemMove event. What I can’t now work out is if there is any way to call functions and processes in my original AddInModule class. Or must all my code be contained within the OutlookItemsEventsClass1 class

  • http://0.gravatar.com/avatar/e1a4c2b21a5186e0b27c1c601f418b76?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Pieter van der Westhuizen says:

    Hi Mike,

    You can get a reference to your AddinModule class like so:

    MyAddin1.AddinModule module = AddinExpress.MSO.ADXAddinModule.CurrentInstance as MyAddin1.AddinModule;

    You can then call any methods or access any properties on said module from the events class. Just make sure that all events are marked as public. If you need to access controls, you need to set their Modifier property to Public.

    Hope this helps!

  • http://0.gravatar.com/avatar/c88821013fd072566250b942788415c4?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Mike Leedham says:

    Hi Pieter,

    Many thanks. That’s just what I was looking for.

  • http://0.gravatar.com/avatar/c88821013fd072566250b942788415c4?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Mike Leedham says:

    Hi Pieter

    Sorry, me again! Is it possible to connect the Outlook Items Events Class to anything other than the default folders?

    Mike

  • http://0.gravatar.com/avatar/e1a4c2b21a5186e0b27c1c601f418b76?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Pieter van der Westhuizen says:

    Hi Mike,

    Yes, you can connect it to any folder. The ConnectTo method has an overload with the following signature:

    bool ADXOutlookItemsEvents.ConnectTo(object olFolder, bool eventClassReleasesComObject)

    So, you can pass in an Outlook.Folder object as the first parameter.

    Hope this helps. Good Luck!

Post a comment

Have any questions? Ask us right now!