none
Outlook Add In - Hook into delete event without having to open the email. RRS feed

  • Question

  • Is it possible to hook into the BeforeDelete command without having to open the email to fire the event. At present my code will hit the BeforeDelete event when the email is open and delete is selected, but it does not fire if deleting without opening the email.
    Tuesday, March 10, 2015 1:29 PM

Answers

All replies

  • Yes, it is. You can subscribe to item level events without opening items. What code do you use now?

    What exactly do you need to implement?

    You may find the Developing an Inspector Wrapper for Outlook 2010 article helpful.


    Tuesday, March 10, 2015 1:38 PM
  • I'm using the following:

    ((Outlook.ItemEvents_10_Event)this.mailItem).BeforeDelete += new Outlook.ItemEvents_10_BeforeDeleteEventHandler(this.MailItem_Delete);

    It will only fire the Delete when you open the email and select delete

    Tuesday, March 10, 2015 1:56 PM
  • Where did you get the mail item object?
    Tuesday, March 10, 2015 2:01 PM
  • Below is the Property MailItem I have in a class called MailItemContainer:

    /// <summary>/// Gets or sets the Mail Item property/// </summary>public Outlook.MailItem MailItem         {             get             {                 returnthis.mailItem;             }             set             {                 if (this.mailItem != null)                 {                     try                     {                         ((Outlook.ItemEvents_10_Event)this.mailItem).Forward -= new Outlook.ItemEvents_10_ForwardEventHandler(this.MailItem_Reply);                         ((Outlook.ItemEvents_10_Event)this.mailItem).Open -= new Outlook.ItemEvents_10_OpenEventHandler(this.MailItem_Open);                         ((Outlook.ItemEvents_10_Event)this.mailItem).PropertyChange -= new Outlook.ItemEvents_10_PropertyChangeEventHandler(this.MailItem_PropertyChange);                         ((Outlook.ItemEvents_10_Event)this.mailItem).Reply -= new Outlook.ItemEvents_10_ReplyEventHandler(this.MailItem_Reply);                         ((Outlook.ItemEvents_10_Event)this.mailItem).ReplyAll -= new Outlook.ItemEvents_10_ReplyAllEventHandler(this.MailItem_Reply);                         ((Outlook.ItemEvents_10_Event)this.mailItem).Send -= new Outlook.ItemEvents_10_SendEventHandler(this.MailItem_Send);                         ((Outlook.ItemEvents_10_Event)this.mailItem).Unload -= new Outlook.ItemEvents_10_UnloadEventHandler(this.MailItem_Unload);                         ((Outlook.ItemEvents_10_Event)this.mailItem).BeforeDelete -= new Outlook.ItemEvents_10_BeforeDeleteEventHandler(this.MailItem_Delete);                     }                     catch                     {                     }                 }                 if (value != null && !value.Equals(this.mailItem))                 {                     this.mailItem = value;                                         ((Outlook.ItemEvents_10_Event)this.mailItem).Close += new Outlook.ItemEvents_10_CloseEventHandler(this.MailItem_Close);                     ((Outlook.ItemEvents_10_Event)this.mailItem).Forward += new Outlook.ItemEvents_10_ForwardEventHandler(this.MailItem_Reply);                     ((Outlook.ItemEvents_10_Event)this.mailItem).Open += new Outlook.ItemEvents_10_OpenEventHandler(this.MailItem_Open);                     ((Outlook.ItemEvents_10_Event)this.mailItem).PropertyChange += new Outlook.ItemEvents_10_PropertyChangeEventHandler(this.MailItem_PropertyChange);                     ((Outlook.ItemEvents_10_Event)this.mailItem).Reply += new Outlook.ItemEvents_10_ReplyEventHandler(this.MailItem_Reply);                     ((Outlook.ItemEvents_10_Event)this.mailItem).ReplyAll += new Outlook.ItemEvents_10_ReplyAllEventHandler(this.MailItem_Reply);                     ((Outlook.ItemEvents_10_Event)this.mailItem).Send += new Outlook.ItemEvents_10_SendEventHandler(this.MailItem_Send);                     ((Outlook.ItemEvents_10_Event)this.mailItem).Unload += new Outlook.ItemEvents_10_UnloadEventHandler(this.MailItem_Unload);                     ((Outlook.ItemEvents_10_Event)this.mailItem).BeforeDelete += new Outlook.ItemEvents_10_BeforeDeleteEventHandler(this.MailItem_Delete);                 }             }         }

    I have an Outlook AddIn which code is below:

    /// <summary>
    /// Mutex to control loading and new mails
    /// </summary>
    private System.Threading.Mutex mutexLoad = new System.Threading.Mutex();
     
    /// <summary>
    /// Gets or sets the mail item list
    /// </summary>
    internal List<MailItemContainer> MailItemList
    {
        get;
        set;
    }
     
    /// <summary>
    /// Checks the list to see if the item has already been registered.
    /// </summary>
    /// <param name="findItem">The <typeparamref name="Outlook.MailItem">MailItem</typeparamref> to find.</param>
    /// <returns><c>True</c> if found, <c>False</c> if not</returns>
    public bool ContainsMailItem(Outlook.MailItem findItem)
    {
        var found = false;
        foreach (var item in this.MailItemList)
        {
            found = item.MailItem != null && item.MailItem.Equals(findItem);
            try
            {
                found = found || (!string.IsNullOrWhiteSpace(item.MailItem.EntryID) && item.MailItem.EntryID.Equals(findItem.EntryID));
            }
            catch
            {
            }
     
            if (found)
            {
                break;
            }
        }
     
        return found;
    }
     
    /// <summary>
    /// Finds the container for the mailitem in the list if the item has already been registered.
    /// </summary>
    /// <param name="findItem">The <typeparamref name="Outlook.MailItem">MailItem</typeparamref> to find.</param>
    /// <returns>The MailItemContainer object that is used to extend the mail item</returns>
    public MailItemContainer FindMailItem(Outlook.MailItem findItem)
    {
        MailItemContainer mailContainer = null;
     
        foreach (var item in this.MailItemList)
        {
            if (item.MailItem != null)
            {
                if (item.MailItem.Equals(findItem))
                {
                    mailContainer = item;
                }
                else
                {
                    try
                    {
                        if (!string.IsNullOrWhiteSpace(item.MailItem.EntryID) && item.MailItem.EntryID.Equals(findItem.EntryID))
                        {
                            mailContainer = item;
                        }
                    }
                    catch
                    {
                    }
                }
     
                if (mailContainer != null)
                {
                    break;
                }
            }
        }
     
        return mailContainer;
    }
     
    /// <summary>
    /// This will attempt to get the default values for the user and bind to the outlook events.
    /// </summary>
    private void InitialiseAddIn()
    {
        var success = DA.SQLDataSource.IsDBConnectionValid();
     
        if (success)
        {
            Utility.UserUpdated -= new EventHandler(this.Utility_UserUpdated);
            try
            {
                Utility.User = DA.User.GetUserByUserId(Utility.UserId.GetValueOrDefault());
                success = Utility.User != null;
                if (success)
                {
                    Utility.Department = Utility.User.Department;
                    success = Utility.Department != null;
     
                    if (success)
                    {
                        this.MailItemList = new List<MailItemContainer>();
     
                        // Add a handler when an email item is opened
                        this.Application.ItemLoad += new Outlook.ApplicationEvents_11_ItemLoadEventHandler(this.ThisApplication_ItemLoad);
     
                        // Add a handler when an email item is new
                        this.Application.NewMailEx += new Outlook.ApplicationEvents_11_NewMailExEventHandler(this.ThisApplication_NewMailEx);
     
                        // Add a handler when the selection changes
                        this.Application.ActiveExplorer().SelectionChange += new Outlook.ExplorerEvents_10_SelectionChangeEventHandler(this.ThisAddIn_SelectionChange);
                    }
                    else
                    {
                        MessageBox.Show("Your department has not been selected. Click on the \"Call Centre\" option on the menu and press the \"Settings\" button to select your department.""PSP Call Centre Tracker");
                    }
                }
                else
                {
                    MessageBox.Show("Your user profile has not been set up yet. Click on the \"Call Centre\" option on the menu and press the \"Settings\" button to select your department and create a profile.""PSP Call Centre Tracker");
                }
            }
            catch
            {
                MessageBox.Show("Call Centre Tracker was unable to communicate with active directory.\nTracking will not be enabled for this Outlook session.""PSP Call Centre Tracker");
            }
        }
        else
        {
            MessageBox.Show("Call Centre Tracker was unable to communicate with database.\nTracking will not be enabled for this Outlook session.""PSP Call Centre Tracker");
        }
     
        Utility.UserUpdated += new EventHandler(this.Utility_UserUpdated);
    }
     
    /// <summary>
    /// The event that fires when the add-in is loaded
    /// </summary>
    /// <param name="sender">The object that fired the event</param>
    /// <param name="e">The evetn args</param>
    private void TrackingAddIn_Startup(object sender, System.EventArgs e)
    {
        this.InitialiseAddIn();
    }
     
    /// <summary>
    /// This fires when the add-in is closed
    /// </summary>
    /// <param name="sender">The ibject that fired the event</param>
    /// <param name="e">The event args</param>
    private void TrackingAddIn_Shutdown(object sender, System.EventArgs e)
    {
        this.Application = null;
    }
     
    /// <summary>
    /// Handles the event when the User has been changed.
    /// </summary>
    /// <param name="sender">The object that raised the event</param>
    /// <param name="e">The default event arguments</param>
    private void Utility_UserUpdated(object sender, EventArgs e)
    {
        this.InitialiseAddIn();
    }
     
    /// <summary>
    /// This is the application_ item load.
    /// </summary>
    /// <param name="item">The mail item.</param>
    private void ThisApplication_ItemLoad(object item)
    {
        if (item is Microsoft.Office.Interop.Outlook.MailItem)
        {
            Outlook.MailItem mailItem = item as Outlook.MailItem;
            try
            {
                this.mutexLoad.WaitOne();
                if (mailItem != null && !this.ContainsMailItem(mailItem))
                {
                    this.MailItemList.Add(new MailItemContainer(mailItem, this));
                }
            }
            finally
            {
                this.mutexLoad.ReleaseMutex();
            }
        }
    }
     
    /// <summary>
    /// Thises the application_ new mail ex.
    /// </summary>
    /// <param name="entryIDCollection">The entry ID collection.</param>
    private void ThisApplication_NewMailEx(string entryIDCollection)
    {
        var idCollection = entryIDCollection.Split(',');
        var sentFolder = this.Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
        var inboxFolder = this.Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
     
        foreach (var entryId in idCollection)
        {
            var item = this.Application.Session.GetItemFromID(entryId);
            if (item is Outlook.MailItem)
            {
                var mailItem = item as Outlook.MailItem;
                var parentFolder = Utility.GetTopLevelFolder(mailItem);
                if (parentFolder != null && parentFolder.EntryID == inboxFolder.EntryID)
                {
                    var referenceCode = Utility.MatchSubjectReference(mailItem.Subject);
                    try
                    {
                        this.mutexLoad.WaitOne();
                        var containerItem = this.FindMailItem(mailItem);
                        if (!DA.TrackingItem.ExistsByReferenceCode(referenceCode, mailItem.ReceivedTime))
                        {
                            if (containerItem == null)
                            {
                                containerItem = new MailItemContainer(mailItem, this);
                                this.MailItemList.Add(containerItem);
                            }
     
                            containerItem.IsNewItem = true;
                            containerItem.TrackingItem = Utility.RegisterMailIncoming(item as Outlook.MailItemthis.Application);
                        }
                    }
                    finally
                    {
                        this.mutexLoad.ReleaseMutex();
                    }
                }
            }
        }
        ////Insert into Detail file and get the refence number
        ////MailInsert("Incoming");
    }
     
    /// <summary>
    /// This action fires when the selection changes
    /// </summary>
    private void ThisAddIn_SelectionChange()
    {
        var unread = this.MailItemList.Where(d => d.IsNewItem && d.MailItem.UnRead).ToList();
        foreach (var item in unread)
        {
            item.DoUnReadCheck();
        }
    }

                               

    Tuesday, March 10, 2015 2:27 PM
  • Hello Mark,

    I have noticed the following line of code:

     // Add a handler when the selection changes
                        this.Application.ActiveExplorer().SelectionChange += new Outlook.ExplorerEvents_10_SelectionChangeEventHandler(this.ThisAddIn_SelectionChange);

    The SelectionChange event will not be fired as soon as the explorer is swiped by the GC. You need to keep the source object alive if you want to get the event fired.

    Where do you subscribe to the BeforeDelete event? What event do you use?


    Tuesday, March 10, 2015 3:19 PM
  • Hi PspMark,

    Based on this links below, it says that in order for this event to fire when an e-mail message, distribution list, journal entry, task, contact, or post are deleted through an action, an inspector must be open.

    https://msdn.microsoft.com/en-us/library/office/ff866473(v=office.15).aspx

    For your requirement, I suggest that you could capture ItemAdd or ItemRemove event to achieve.

    Regards

    Starain


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    Wednesday, March 11, 2015 7:11 AM
    Moderator
  • Starain,

    What about the next line of text from the Remarks section:

    In order for this event to fire when an e-mail message, distribution list, journal entry, task, contact, or post are deleted through an action, an inspector must be open.

    The event occurs each time an item is deleted.

    Wednesday, March 11, 2015 7:30 AM
  • Hi Eugene,

    >> The event occurs each time an item is deleted.

    I think it means the event occurs each time an item is deleted when the corresponding item is opened.

    I made a test, the result is the same as PspMark’s.

    Regards

    Starain


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, March 12, 2015 1:39 AM
    Moderator
  • Starain,

    I also decided to test the event in the fields. And here is what I get:

    The event is fired when the inspector window is opened and the Delete button is clicked on the Inspector's ribbon. But when I click the Delete button on the Explorer's ribbon the event is not fired even when the item is opened in the inspector. Is this a bug or feature?

    Thursday, March 12, 2015 12:34 PM
  • Mark,

    As tests show, the BeforeDelete event is very unstable and requires an Inspector window opened to get it fired.

    Consider using the ItemAdd event of the Items class. For example, when the item is deleted, it is moved to the Deleted Items folder where you can track the newly added items.

    Also you may consider handling the built-in UI controls. See Temporarily Repurpose Commands on the Office Fluent Ribbon for more information.

    Thursday, March 12, 2015 12:41 PM
  • Hi Eugene,

    >>But when I click the Delete button on the Explorer's ribbon the event is not fired even when the item is opened in the inspector

    I have the same result. It seems that the BeforeDelete event just fire when click the delete button on inspector’s ribbon.

    In my opinion, it’s better to base on the action (e.g. delete) to fire the event (e.g. BeforeDelete).

    Regards

    Starain


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Friday, March 13, 2015 1:42 AM
    Moderator
  • Starain,

    > In my opinion, it’s better to base on the action (e.g. delete) to fire the event (e.g. BeforeDelete). 

    It will not be working...

    For example, in the Explorer's table view you can see the crossed red symbol for deleting the mail item:

    And if you try to repurpose the Delete button (idMso: Delete), this action will not be handled.

    Friday, March 13, 2015 9:41 AM
  • Hi,

    What I mean is that I just expect that feature/action.

    Regards

    Starain


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    Friday, March 13, 2015 9:45 AM
    Moderator
  • Sorry, but I don't understand your last post. 


    Friday, March 13, 2015 10:55 AM
  • Hi Eugene,

    Outlook doesn’t have that action of fire delete event when delete a mail item from explorer delete button (also for the crossed red symbol of delete button), I want it has that action of fire delete event regardless of which way we delete the mail item.

    Regards

    Starain


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, March 16, 2015 3:29 AM
    Moderator
  • Sorry Starain, but I still don't understand your answer. Neither ways (repurposing the Delete button nor the BeforeDelete event) are helpful to handle the crossed red button in the grid. Is it a bug?
    Monday, March 16, 2015 1:08 PM
  • Hi Eugene,

    >> Is it a bug?

    Not sure. For that issue, the workaround is capture ItemAdd, ItemRemove event.

    Regards

    Starain


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, March 17, 2015 1:24 AM
    Moderator
  • MAPI notifications can be used to hook into events that delete messages from an explorer window even if no inspector is open. Notification fnevObjectMoved will fire if a message is deleted and moved into the Deleted Items folder and fnevObjectDeleted wil fire on a permanent deletion.
    Friday, March 20, 2015 1:52 AM
  • Of course, the low-level code can be considered as an alternative way for handling events. But I suppose we are talking about the Outlook object model events.
    Friday, March 20, 2015 2:15 AM