Pieter van der Westhuizen

Outlook Item events explained: C#, VB.NET

Spring has finally sprung down here and I thought today would be a great day to dive into the Outlook Item Events Class provided by Add-in Express and have a closer look at what each event in this class does. For this example I’ll be using Add-in Express for Office and .Net.

To get started, create a new COM Add-in project in Microsoft Visual Studio 2010.

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. In this example it will be Visual C# and Microsoft Office 2007.

Selecting your programming language

The Outlook ItemEvents class is only available for Outlook, so select only Microsoft Outlook in the Supported Applications list.

Selecting Microsoft Outlook in the Supported Applications list

Complete the wizard and add a new Outlook Item Events Class to your project by selecting Add New Item… from the Visual Studio Project menu. You can find the template under Add-in Express Items > Outlook.

Adding a new Outlook Item Events Class to your project

Before we can respond to the events in the class, we need to do some work in the AddinModule class. Switch to the AddinModule.cs code view and declare the OutlookItemsEventsClass:

private OutlookItemEventsClass outlookItemEvents = null;

Next open the AddinModule.cs designer and double-click in the AddinStartupComplete event in die property grid, this will generate an event handler. Add the following code to the new event handler:

private void AddinModule_AddinStartupComplete(object sender, EventArgs e)
{
	outlookItemEvents = new OutlookItemEventsClass(this);
}

Switch back to the AddinModule.cs designer and add a new Microsoft Outlook events component.

Adding a new Microsoft Outlook events component

Select the newly added Outlook events component and double-click its InspectorActivate event in the property grid to generate an event handler. Add the following code:

C# code example

private void adxOutlookEvents_InspectorActivate(object sender,
	object inspector, string folderName)
{
    if (canConnect)
    {
        Outlook._Inspector olInsp = (Outlook._Inspector)inspector;
        object item = olInsp.CurrentItem;
 
        if (item is Outlook._MailItem)
        {
            outlookItemEvents.ConnectTo(item, true);
        }
    }
}

We need to add some more code in order to support the item connection regardless of whether the item is open/active or selected in an active explorer. (Thanks to Sergey for the code review and suggestions!)

Add the following method to the AddinModule class:

private void ConnectToSelectedItem(object explorer)
{
    Outlook.Selection sel = null;
 
    try
    {
        Outlook._Explorer expl = explorer as Outlook._Explorer;
        sel = expl.Selection;
        if (sel.Count == 1)
        {
            object item = sel[1];
            if (item is Outlook._MailItem)
                outlookItemEvents.ConnectTo(item, true);
            else
                Marshal.ReleaseComObject(item);
        }
    }
    finally
    {
        if (sel != null)
            Marshal.ReleaseComObject(sel);
    }
}

Next, we need to wire up the ConnectToSelectedItem method. To do this, add an event handler for ExplorerActivate and ExplorerSelectionChange:

private void adxOutlookEvents_ExplorerActivate(object sender, object explorer)
{
    ConnectToSelectedItem(explorer);
}

Add some code to check whether we can connect to items in an explorer, do this in ExplorerClose:

private void adxOutlookEvents_ExplorerClose(object sender, object explorer)
{
    int count = 0;
    Outlook._Explorers expls = null;
 
    try
    {
        expls = OutlookApp.Explorers;
        count = expls.Count;
    }
    catch
    {
    }
    finally
    {
        if (expls != null)
            Marshal.ReleaseComObject(expls);
    }
 
    if (count == 0)
        canConnect = false;
}

We need to clean up after ourselves by properly disposing of the ItemEvents object, to do this add event handlers for ItemSend, InspectorClose and AddinBeginShutdown:

private void adxOutlookEvents_ItemSend(object sender, ADXOlItemSendEventArgs e)
{
    if (outlookItemEvents != null)
        outlookItemEvents.RemoveConnection();
}

Now that we’ve hooked up the necessary code in order to raise the events, switch to the OutlookItemEventsClass and let's look at the events we can respond to.

ProcessAttachmentAdd

This event fires when you attach a file to an Outlook item i.e. MailItem, TaskItem , ContactItem and AppointmentItem. A reference to the attachment is passed into the method and you can get more information about it by casting it to an Outlook.Attachment object as illustrated in the example below:

C# code example

public override void ProcessAttachmentAdd(object attachment)
{
    Outlook.Attachment myAttachment = (Outlook.Attachment)attachment;
    int sizeInBytes = myAttachment.Size;
    int sizeInKiloBytes = sizeInBytes / 1024;
    Marshal.ReleaseComObject(myAttachment);
 
    //Check if attachment is larger than 1MB
    if (sizeInKiloBytes >= 1024)
    {
        MessageBox.Show(
			"PLEASE NOTE: To keep mailbox sizes low, try and keep attachment under 1MB",
            "Attachment size warning");
    }
}

ProcessBeforeAttachmentAdd

This event was added in Outlook 2007 and is similar to ProcessAttachmentAdd except that it is raised before the attachment is added to the Outlook item. You also get an extra parameter enabling you to cancel the file attachment as illustrated below:

C# code example

public override void ProcessBeforeAttachmentAdd(object attachment,
    AddinExpress.MSO.ADXCancelEventArgs e)
{
    Outlook.Attachment myAttachment = (Outlook.Attachment)attachment;
    int sizeInBytes = myAttachment.Size;
    int sizeInKiloBytes = sizeInBytes / 1024;
    Marshal.ReleaseComObject(myAttachment);
 
    //Check if attachment is larger than 1MB
    if (sizeInKiloBytes >= 1024)
    {
        MessageBox.Show(
			"PLEASE NOTE: Attachment must be under 1MB. Attachment will be removed.",
            "Attachment size warning");
        e.Cancel = true;
    }
}

ProcessAttachmentRead

ProccessAttachmentRead will fire when the user opens an existing attachment on an Outlook item, which could include MailItem, TaskItem , ContactItem and AppointmentItem. As with the previous method a reference to the attachment is passed.

C# code example

public override void ProcessAttachmentRead(object attachment)
{
    Outlook._JournalItem journalItem = null;
 
    try
    {
        Outlook.Attachment myAttachment = (Outlook.Attachment)attachment;
        Outlook._Application outlookApp = ((AddinModule)this.Module).OutlookApp;
        string fileName = myAttachment.FileName;
 
        journalItem = (Outlook._JournalItem)outlookApp.CreateItem(
			Outlook.OlItemType.olJournalItem);
        journalItem.Subject = "You opened " + fileName + " today";
        journalItem.Save();
    }
    finally
    {
        if (journalItem != null)
            Marshal.ReleaseComObject(journalItem);
    }
}

ProcessAttachmentRemove

When the user deletes the attachment from the Outlook item the ProcessAttachmentRemove event will be raised, as with the previous methods you get a reference to the attachment.

C# code example

public override void ProcessAttachmentRemove(object attachment)
{
    Outlook.Attachment myAttachment = (Outlook.Attachment)attachment;
    Outlook._Application outlookApp = ((AddinModule)this.Module).OutlookApp;
 
    string fileName = String.Empty;
    Outlook._JournalItem journalItem = null;
 
    try
    {
        fileName = myAttachment.FileName;
 
    }
    catch (Exception)
    {
    }
 
    if (!String.IsNullOrEmpty(fileName))
    {
        try
        {
            journalItem = (Outlook._JournalItem)outlookApp.CreateItem(
				Outlook.OlItemType.olJournalItem);
            journalItem.Subject = "You removed " + fileName + " today";
            journalItem.Save();
        }
        finally
        {
            if (journalItem != null)
                Marshal.ReleaseComObject(journalItem);
        }
    }
}

ProcessBeforeAttachmentPreview

Introduced in Outlook 2007, you can use the ProcessBeforeAttachmentPreview method to add logic before an attachment is previewed in Outlook. A reference to the attachment is passed into the methods:

public override void ProcessBeforeAttachmentPreview(
	object attachment, AddinExpress.MSO.ADXCancelEventArgs e)
{
    Outlook.Attachment myAttachment = (Outlook.Attachment)attachment;
    Outlook._Application outlookApp = myAttachment.Application;
    string fullPath = @"C:\Temp\" + myAttachment.FileName;
    myAttachment.SaveAsFile(fullPath);
    Marshal.ReleaseComObject(myAttachment);
}

ProcessBeforeAttachmentRead

BeforeAttachmentRead was introduced in Outlook 2007 and will occur before the attached file of an Outlook object is read from the file system. A reference to the attachment is passed into the methods as well as ADXCancelEventArgs which can be used to cancel the operation.

C# code example

public override void ProcessBeforeAttachmentRead(
	object attachment, AddinExpress.MSO.ADXCancelEventArgs e)
{
    Outlook.Attachment myAttachment = (Outlook.Attachment)attachment;
    Outlook._Application outlookApp = myAttachment.Application;
    string fileName = myAttachment.FileName;
    Marshal.ReleaseComObject(myAttachment);
 
    if (fileName.ToLower().Contains("virus"))
    {
        MessageBox.Show(
			"WARNING: The file appears dangerous. Better not open it.",
            "Warning - Dangerous file");
        e.Cancel = true;
    }
}

ProcessBeforeAttachmentWriteToTempFile

When you double-click an attachment in Outlook in order to open it, the file will first be written to a temporary file location before opening. Use this method to intercept that event. You can use the ADXCancelEventArgs parameter to cancel the operation.

public override void ProcessBeforeAttachmentWriteToTempFile(
	object attachment, AddinExpress.MSO.ADXCancelEventArgs e)
{
    Outlook.Attachment myAttachment = (Outlook.Attachment)attachment;
    Outlook._Application outlookApp = myAttachment.Application;
    string fileName = myAttachment.FileName;
    Marshal.ReleaseComObject(myAttachment);
 
    if (fileName.ToLower().Contains("virus"))
    {
        MessageBox.Show(
			"WARNING: The file appears dangerous. Better not open it.",
            "Warning - Dangerous file");
        e.Cancel = true;
    }
}

ProcessBeforeAttachmentSave

The ProcessBeforeAttachmentSave is an interesting event. It is triggered when the attachment is saved to the messaging store and not when the user saves the attachment to disk. For example, if you have an MS Excel file attached to an Outlook contact item and the user double clicks on it, makes changes to the file and saves it, this event will only be triggered once the user saves the associated contact item.

public override void ProcessBeforeAttachmentSave(
	object attachment, AddinExpress.MSO.ADXCancelEventArgs e)
{
    Outlook.Attachment myAttachment = (Outlook.Attachment)attachment;
    Outlook._Application outlookApp = myAttachment.Application;
    string fileName = myAttachment.FileName;
 
    if (MessageBox.Show(
		"You've made changes to the attached file. " +
		"Would you like to save it to the central file system?",
        "File Changed", MessageBoxButtons.YesNo) == DialogResult.Yes)
    {
        myAttachment.SaveAsFile(@"K:\CentralStorage\" + fileName);
    }
 
    Marshal.ReleaseComObject(myAttachment);
}

ProcessBeforeCheckNames

The ProcessBeforeCheckNames method is used to intercept the BeforeCheckNames event, which occurs before Outlook starts to resolve the names of recipients of an Outlook item, for example when the user clicks on the Check Names button.

Check Names button

You can use this event to write your own contact name resolution logic.

public override void ProcessBeforeCheckNames(AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (this.ItemObj is Outlook._MailItem)
    {
        Outlook.Recipient recipient = null;
        Outlook.Recipients recipients = null;
 
        Outlook._MailItem mail = (Outlook._MailItem)ItemObj;
 
        try
        {
            recipients = mail.Recipients;
            for (int i = 1; i <= recipients.Count; i++)
            {
                recipient = null;
 
                try
                {
                    recipient = recipients[i];
                }
                finally
                {
                    if (recipient != null)
                        Marshal.ReleaseComObject(recipient);
                }
            }
        }
        finally
        {
            if (recipients != null)
                Marshal.ReleaseComObject(recipients);
        }
    }
}

ProcessPropertyChange

Use the ProcessPropertyChange method to intercept when a built-in property on an Outlook item has changed. The name of the property that changed is passed into the method as a parameter.

public override void ProcessPropertyChange(string name)
{
    if (this.ItemObj is Outlook._MailItem)
    {
        Outlook._MailItem mail = (Outlook._MailItem)this.ItemObj;
 
        Outlook.ItemProperty property = null;
        Outlook.ItemProperties properties = null;
 
        try
        {
            properties = mail.ItemProperties;
            property = properties[name];
 
            MessageBox.Show(String.Format("You've changed {0} to {1}",
                name, property.Value));
        }
        finally
        {
            if (properties != null)
                Marshal.ReleaseComObject(properties);
            if (property != null)
                Marshal.ReleaseComObject(property);
        }
    }
}

ProcessCustomPropertyChange

When the user changes the value of a user property on an Outlook item, you can use the ProcessCustomPropertyChange event to intercept that event. The name of the user property is passed as a parameter.

public override void ProcessCustomPropertyChange(string name)
{
    if (this.ItemObj is Outlook._MailItem)
    {
        Outlook._MailItem mail = (Outlook._MailItem)this.ItemObj;
 
        Outlook.UserProperty userProperty = null;
        Outlook.UserProperties properties = null;
 
        try
        {
            properties = mail.UserProperties;
            userProperty = properties.Find(name);
            if (userProperty != null)
            {
                MessageBox.Show(String.Format(
					"You've changed the user property {0} to {1}",
					name, userProperty.Value));
            }
        }
        finally
        {
            if (userProperty != null)
                Marshal.ReleaseComObject(userProperty);
            if (properties != null)
                Marshal.ReleaseComObject(properties);
        }
    }
}

ProcessReply

When the user replies on an Outlook Item, the Reply event is raised. Use the ProcessReply method to intercept it. The response parameter is a reference to the new item that is being sent in response. In our example this will be an Outlook MailItem.

public override void ProcessReply(object response,
    AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (response is Outlook._MailItem)
    {
        Outlook._MailItem mailResponse = (Outlook._MailItem)response;
        mailResponse.BCC = "someone@somewhere.com";
    }
}

ProcessReplyAll

The ProcessReplyAll is similar to the ProcessReply method. This event is raised when the user replies to all, on an Outlook item. The response parameter is a reference to the new item that is being sent in response and in our example this will be an Outlook MailItem.

public override void ProcessReplyAll(object response,
    AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (response is Outlook._MailItem)
    {
        Outlook._MailItem mailResponse = (Outlook._MailItem)response;
        mailResponse.BCC = "everyone@everywhere.com";
    }
}

ProcessForward

The Forward event occurs when the user forwards an Outlook Item. Similar to the Reply event, a reference to the new item being forwarded is passed as a parameter as well as a Boolean with which you can cancel the event.

public override void ProcessForward(object forward,
    AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (forward is Outlook._MailItem)
    {
        Outlook._MailItem mailForward = (Outlook._MailItem)forward;
        if (!mailForward.Subject.ToLower().Contains("confidential"))
        {
            mailForward.BCC = "mydropbox@work.com";
        }
        else
        {
            e.Cancel = true;
        }
    }
}

ProcessOpen

The Process event is raised when the user opens an Outlook item in an Inspector. Set the ADXCancelEventArgs’s Cancel property to true in order to cancel the open event.

public override void ProcessOpen(AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (this.ItemObj is Outlook._MailItem)
    {
        Outlook._MailItem mailOpen = (Outlook._MailItem)ItemObj;
        Outlook._Application outlookApp = ((AddinModule)this.Module).OutlookApp;
 
        Outlook._JournalItem journalItem = null;
 
        try
        {
            journalItem = (Outlook._JournalItem)outlookApp.CreateItem(
				Outlook.OlItemType.olJournalItem);
            journalItem.Subject = 
				"You've read a mail with Subject: " + mailOpen.Subject + " today";
            journalItem.Save();
        }
        finally
        {
            if (journalItem != null)
                Marshal.ReleaseComObject(journalItem);
        }
    }
}

ProcessClose

ProcessClose is exactly the opposite of ProcessOpen and is raise when the user closes the Inspector of an Outlook item. As with ProcessOpen you can use the ADXCancelEventArgs to cancel the close operation.

public override void ProcessClose(AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (this.ItemObj is Outlook._MailItem)
    {
        Outlook._MailItem mail = (Outlook._MailItem)ItemObj;
        if (mail.SenderEmailAddress != null &&
            mail.SenderEmailAddress.Equals("TheBoss@work.com"))
        {
            e.Cancel = true;
        }
    }
}

ProcessRead

The Read event is similar to the Open event except for the fact that it is also raised when the user selects the item in a view that supports in-cell editing.

public override void ProcessRead()
{
    if (this.ItemObj is Outlook._MailItem)
    {
        Outlook._MailItem mail = (Outlook._MailItem)ItemObj;
        Outlook._Application outlookApp = ((AddinModule)this.Module).OutlookApp;
 
        Outlook._JournalItem journalItem = null;
 
        try
        {
            journalItem = (Outlook._JournalItem)outlookApp.CreateItem(
				Outlook.OlItemType.olJournalItem);
            journalItem.Subject = 
				"You've read a mail with Subject: " + mail.Subject + " today";
            journalItem.Save();
        }
        finally
        {
            if (journalItem != null)
                Marshal.ReleaseComObject(journalItem);
        }
    }
}

ProcessWrite

The Write event is raised when a user saves an Outlook item or when the Save or SaveAs methods of the item is called. The Write event can also be cancelled.

public override void ProcessWrite(AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (this.ItemObj is Outlook._MailItem)
    {
        Outlook._MailItem mail = (Outlook._MailItem)ItemObj;
        Outlook._Application outlookApp = ((AddinModule)this.Module).OutlookApp;
 
        Outlook._JournalItem journalItem = null;
 
        try
        {
            journalItem = (Outlook._JournalItem)outlookApp.CreateItem(
				Outlook.OlItemType.olJournalItem);
            journalItem.Subject = "Mail Saved: " + mail.Subject;
            journalItem.Save();
        }
        finally
        {
            if (journalItem != null)
                Marshal.ReleaseComObject(journalItem);
        }
    }
}

ProcessSend

When the user clicks send or you invoke the Send method on an Outlook Item, this event will fire. It can also be cancelled as with the previous methods.

public override void ProcessSend(AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (this.ItemObj is Outlook._MailItem)
    {
        Outlook._MailItem mail = (Outlook._MailItem)ItemObj;
        Outlook._Application outlookApp = ((AddinModule)this.Module).OutlookApp;
 
        Outlook._JournalItem journalItem = null;
 
        try
        {
            journalItem = (Outlook._JournalItem)outlookApp.CreateItem(
				Outlook.OlItemType.olJournalItem);
            journalItem.Subject = "Sent an e-mail to " + mail.To;
            journalItem.Save();
        }
        finally
        {
            if (journalItem != null)
                Marshal.ReleaseComObject(journalItem);
        }
    }
}

ProcessBeforeDelete

When you invoke the Delete method or the user deletes an Outlook Item, the BeforeDelete events will be raised. A reference to the item being deleted is passed as a parameter.

public override void ProcessBeforeDelete(
	object item, AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (item is Outlook._MailItem)
    {
        Outlook._MailItem mail = (Outlook._MailItem)item;
        if (mail.To.Contains("TheBoss@work.com"))
        {
            Outlook._Application outlookApp = ((AddinModule)this.Module).OutlookApp;
 
            Outlook._JournalItem journalItem = null;
 
            try
            {
                journalItem = (Outlook._JournalItem)outlookApp.CreateItem(
					Outlook.OlItemType.olJournalItem);
                journalItem.Subject = "Oh oh! You deleted an email from the boss";
                journalItem.Save();
            }
            finally
            {
                if (journalItem != null)
                    Marshal.ReleaseComObject(journalItem);
            }
        }
    }
}

ProcessUnload

The ProcessUnload event is raised after the Close event and before the Outlook item is unloaded from memory. You can use this event to release any resources related to the object.

ProcessBeforeAutoSave

If the user has Auto save enabled in Outlook, this event will fire just before Outlook automatically saves the item. You can cancel this by setting ADXCancelEventArgs.Cancel to true.

public override void ProcessBeforeAutoSave(AddinExpress.MSO.ADXCancelEventArgs e)
{
    if (this.ItemObj is Outlook._MailItem)
    {
        Outlook._MailItem mail = (Outlook._MailItem)ItemObj;
 
        Outlook.UserProperties properties = null;
        Outlook.UserProperty newUserProperty = null;
 
        try
        {
            properties = mail.UserProperties;
            newUserProperty = properties.Add("AutoSaved", 
				Outlook.OlUserPropertyType.olDateTime);
            newUserProperty.Value = DateTime.Now;
        }
        finally
        {
            if (newUserProperty != null)
                Marshal.ReleaseComObject(newUserProperty);
            if (properties != null)
                Marshal.ReleaseComObject(properties);
        }
    }
}

ProcessBeforeRead

The ProcessBeforeRead event is raised before an item’s properties are read by Outlook; it occurs after the Read event and cannot be cancelled. An interesting caveat is that you can only access the Class and MessageClass properties of the item. If you try and access any other property you will receive an exception.

ProcessAfterWrite

The ProcessAtterWrite occurs after the Outlook item has been saved and after the Write event. As with the BeforeRead event it cannot be cancelled. Please note you can only access the Class and MessageClass properties of the item.

For more information about Outlook 2007 events, please see the Microsoft documentation. If you’re looking for more information on the Outlook 2010 events you can find it here.

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:

43 Comments

  • Prakash says:

    Howzit,

    Create new project ADX COM Addin, does not exist in vs2012, so how do I create a
    one in vs2012.

    Thanks

  • Pieter van der Westhuizen says:

    Hi Prakash,

    Do you have Add-in Express installed?

  • Roelant says:

    Someone?

    Is there also an event for creating new items?

    the activeExplorer.SelectionChange doesn’t seem to capture creating a new appointment (for example).

    Best regards,
    Roelnat

  • Pieter van der Westhuizen says:

    Hi Roelant,

    Have a look at the ItemAdd event. You can read more about it in this blog post: https://www.add-in-express.com/creating-addins-blog/outlook-folders-events/

    Good luck!

  • beweh says:

    Hello Pieter,

    is it possible to catch the event when the “from” address is changed in the inspector? Sure, this requires multiple accounts.

    Thanks and kind regards,
    beweh

  • Pieter van der Westhuizen says:

    Hi Beweh,

    Have a look at the PropertyChange event. The name of the property that changed is passed in as a parameter.

    Good luck!

  • Raghunathan S says:

    Hi

    I’ve created an Outlook 2010 add-in using Add-In Express Regions (v7.3.4x). My Add-in has a timer which does some operation every 10mins.

    Now, when the add-in is disabled from Outlook, i want to disable the timer at that time. Because even after the add-in is disabled, timer is still running in the background.

    Please help me out with this issue.

    Regards,
    Raghunathan S

  • Pieter van der Westhuizen says:

    Hi Raghunathan,

    What do you mean by “the add-in is disabled in Outlook”? Do you mean that the user deactivates the add-in in the Outlook Options?

  • Raghunathan S says:

    Hi Pieter

    Yes, If the User disables the Add-In by going to Options->Add-Ins->Com-Addins
    and unchecks the add-in and clicks ok.

  • Raghunathan S says:

    Hi Pieter

    To Simulate the issue.

    Create Outlook 2010 Add-In Using Add-In Express Regions for Outlook (7.3.4)

    In the AdxForm add a Timer Control. Set the Interval. On the Elapsed Event
    write some data to a text file (like a log).

    Now Install the Add-In, let the timer start, then go and disable the add-in, wait for the next interval, u will be able to see the log getting written.

    Here, i need to know to stop the timer when the add-in disabled and start it back when the add-in enabled by the user.

    Raghunathan S

  • Pieter van der Westhuizen says:

    Hi Raghunathan,

    Ok, so I’ve managed to replicate the problem. One key thing is, this only happens when using the System.Timers.Timer object. This does not happen when using the plain old Windows Forms Timer control(System.Windows.Forms.Timer)

    You can try to call the timers’ Stop method on either the AddinBeginShutdown or ADXAfterFormHide events – this depends on where you created the timer. Bear in mind though, according to MSDN :

    Even if SynchronizingObject is not null, Elapsed events can occur after the Dispose or Stop method has been called or after the Enabled property has been set to false, because the signal to raise the Elapsed event is always queued for execution on a thread pool thread. One way to resolve this race condition is to set a flag that tells the event handler for the Elapsed event to ignore subsequent events.

    All else fails you could always try using the standard winforms timer control.

    Hope this helps!

  • AVS says:

    Hi, I downloaded the sample for “Outlook Item events explained”, compiled it and installed it fine. From what I see the ProcessSend event is not triggered.
    The reply/forward are fine.
    I use VS 2013 and have outlook 2013 installed. Is there any compatability issues with demo?
    Thanks
    AVS

  • Pieter van der Westhuizen says:

    Hi AVS,

    I’m going to give you the dreaded “It works on my PC” :)
    I’ve downloaded and registered the sample project and it created a journal entry when I sent an email. Maybe try removing some of the other event’s code for example remove the code from ProcessPropertyChange where it shows a message box – maybe this is interfering with the actual send…i had to click through a number of message boxes and then click send again for the mail to send.

  • beweh says:

    Hi Pieter,

    the PropertyChange event is working well with Outlook 2013, when I change the from address the event will be fired and can be handled. But this isn’t working with Outlook 2007, am I right or what I’m doing wrong?

    Thanks and regards,
    beweh

  • Pieter van der Westhuizen says:

    Hi Beweh,

    If I can remember correctly Outlook 2007 did have an issue with the PropertyChange event on recipient type fields.
    The PropertyChange event will only fire when you save the item.

    Hope this helps!

  • beweh says:

    I’ll give that a try and report. Thanks you very much!

  • M G says:

    Add-in Express Team,
    Any info on how to handle attachments in the above event “public override void ProcessReply(object response, AddinExpress.MSO.ADXCancelEventArgs e)”?

    I can read the response object but any attachments from the original email are lost (attachment.Count shows 0).
    The other events, such as processwrite seem to still contain an attachment for an email that have an attachment..

  • Pieter van der Westhuizen says:

    Hi There,

    By default Outlook does not include attachments when replying to an e-mail. So this is probably the reason you cannot access the attachments in the Reply event.
    You could try the approach detailed in this article. However, this only give you the option to attach the original message, so not sure if it will work for your requirement.

    Hope this help. Good luck!

  • M G says:

    Thanks. I understand. I am wondering if there is (within Add-in express) a way to passing any attached items to the new inspector (or accessing them from the new reply window) which gets created after a reply button is clicked.

  • Pieter van der Westhuizen says:

    Mmmm…you could try having a look at the Conversation object. The MailItem object has a ConversationID and ConversationIndex. You could try using these to find the e-mails that was replied to in the conversation thread.

    I have not tried this approach myself, so please let us know if it works.

    Good luck!

  • M G says:

    Thanks, Pieter! I will definitively check that out and see if I can capture the MailItem object in the events prior to processReply and see if I can use that in later events…

  • M G says:

    Tracking by Conversation object (index) works, but I seem to get “COM object that has been separated from its underlying RCW cannot be used.” error/exception sometimes..

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

    The “COM object that has been separated from its underlying RCW cannot be used” exception can be thrown when your code tries to access a COM object that has already been released by using the Marshal.ReleaseComObject() method.

  • Surender Singh says:

    Hi Peter, This is a great article! However I found an issue.
    Problem: I am trying to intercept the auto save event. The issue is that when I have multiple inspector windows open (which is a very common scenario) and only one window is active and connected at a time as per above code sample. All other windows remain disconnected because they are In-Active.

    As a result when auto save fires, none of the in-active windows will be able to capture it because they are disconnected. The problem is you have only one global object outlookItemEvents that connects only one item at a time but there are cases when you may need more than one items to be connected simultaneously. I’m yet to figure out a solution to this but in the meantime some pointers will help to handle it in best way!

    Thanks again for this great article!
    Thanks,
    Surender

  • David says:

    I’m confused, you are doing an if/then for canConnect, but nowhere in the code you provide is there a canConnect sub, variable, or anything else so I cannot compile the code I created by following your tutorial. Please assist.

  • Andrei Smolin (Add-in Express Team) says:

    Search “Available downloads” on the page and download the sample project.

  • beweh says:

    Dear Pieter,

    does it make sense to unhook the event class even on the inspector close event!?
    I think I encountered some problems when using DMS. The mail object is the still in use when reopen a mail e.g. with Symantec Enterprise Vault.
    Is this possible?

    Cheers

  • Andrei Smolin (Add-in Express Team) says:

    Hello beweh,

    I’m sorry, I don’t follow. Could you please provide more details? Unhooking the event class can be done when you need this. What do you mean by “The mail object is the still in use when reopen a mail”?

  • Eric To says:

    How exactly do you override ProcessPropertyChange??? Inside the AddinModule.cs? It says there is no suitable method found to override.

  • Andrei Smolin (Add-in Express Team) says:

    Hello Eric,

    You need to add a new Outlook Item Events Class to your project. See the Add New Item dialog of your add-in project.

  • German_Mso says:

    Firstly, great article. You got my project off the ground.

    My question is about the proper releasing of COM objects.

    You have the following code in places dealing with attachments where “attachment” is passed in as a Parameter.

    Outlook.Attachment myAttachment = (Outlook.Attachment)attachment;
    Outlook._Application outlookApp = myAttachment.Application;
    ….
    Marshal.ReleaseComObject(myAttachment); //— IS THIS CORRECT?

    It’s my understanding that the reference count on the RCW is not incremented on a simple assignment. In this case “myAttachment” is a simple assignment, unlike “outlookApp” where the Application object would have it’s reference count incremented.

    Is my assumption correct that we should not be trying to release “myAttachment”?

  • Andrei Smolin (Add-in Express Team) says:

    Hello,

    Actually, you are right: that method should not release myAttachment. First off, in the .NET world, casting doesn’t increment the reference counter. That is, releasing myAttachment actually releases the attachment parameter and this operation is prohibited by Add-in Express rules: see also section Releasing COM objects at https://www.add-in-express.com/docs/net-office-tips.php#releasing.

    Thank you for pointing us to this issue. I will review this code.

  • Francisco Herrera says:

    Hi, I developing an outlook plugin but I have an issue.
    Whenever the user modifies an appointment or task the event ProcessItemChange is fired more than one time. Do you have an idea what could be triggering the event again? I’m using Outlook 2016.

  • Andrei Smolin (Add-in Express Team) says:

    Hello Francisco,

    I’ve reproduced the issue using VBA: the ItemChnage event is fired twice when I edit a task. It looks like this behavior is inherent to Outlook. Note that the Explorer.SelectionChange may also occur several time: for instance, when you just click the selected item. A way out of this is to check the item’s EntryId property and skip the item if it is already processed.

  • Francisco Herrera says:

    Hello, yeah I applied something like that to skip the extra execution of the event, thank you.
    But I have another problem with tasks, I have a web service which creates task and then I syncronize them into my own task folder in Outlook, the problem is that when one of that tasks is updated by the web service the changes are only displayed in the list view if the task but if I double click them to see the details the changes are not applyed. Do you have an idea of what could be happening? am I missing doing something in an event before showing the form when double clicking the task?

    Thanks in advance

  • Andrei Smolin (Add-in Express Team) says:

    Hello Francisco,

    Does the issue occurs if you restart Outlook? If not, then what you see is a typical manifestation of a COM object(s) left unreleased by your code. I suggest that you start with checking section Releasing COM objects at https://www.add-in-express.com/docs/net-office-tips.php#releasing.

  • Lawrence E Hughes says:

    Hi,

    The event ProcessWrite is fired on Save as of MailItem only if it is saved as .msg, .oft file types. Is there a way to listen Save as for all file formats please

    Thanks,
    Lawrence.

  • Andrei Smolin (Add-in Express Team) says:

    Hello Lawrence,

    In Add-in Express, the MailItem.Write event is mapped to the ProcessWrite method. The method is called whenever the event is raised.

    The event isn’t triggered for me if I use the Outlook 2016 UI to save an email in the HTML format.

    A way to bypass this would be to intercept clicking the Save (Save As) Ribbon button. This allows you to show the File Save dialog, and call the MailItem.SaveAs() method with appropriate parameters. I don’t know if the Write event would be raised in this case. If it isn’t raised, you can imitate receiving it just after you call MailItem.SaveAs(): add a custom method to the events class and call that method; the method can invoke the ProcessWrite method.

  • Scott Deaver says:

    Where and how is “canConnect” declared and intialized (referenced in adxOutlookEvents_InspectorActivate() and adxOutlookEvents_ExplorerClose())?

    Also, Outlook._Explorer.Selection members must now be accessed with the Item() method, and cannot be indexed with [].

    Thanks,
    Scott

  • Andrei Smolin (Add-in Express Team) says:

    Hello Scott,

    That variable is declared on the class level of the add-in module:
    private bool canConnect = true;

    The other issue only occurs if you use version-neutral interops.

  • Raghavendra says:

    Hi Scott ,
    Do we have a event for Save Draft in MailItem

  • Raghavendra says:

    Hi Add-in Express Team,
    Do we have a event for Save Draft in MailItem

  • Andrei Smolin (Add-in Express Team) says:

    Hello Raghavendra

    You need to install version 1.06 of the add-in described at https://www.add-in-express.com/creating-addins-blog/2010/07/01/outlook-events-tool/ and study the events that the Outlook object model provides.

Post a comment

Have any questions? Ask us right now!