'How to get EntryID of removed OutlookItem?

I need to synchronize Outlook contacts to another service. I can subscribe to create, change, and delete events as follows:

        Outlook.MAPIFolder folderContacts = this.Application.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
        Outlook.Items contacts = folderContacts.Items;

        contacts.ItemAdd += Contacts_ItemAdd;
        contact.ItemChange += Contacts_ItemChange;
        contacts.ItemRemove += Contacts_ItemRemove;

This works perfectly for create and change as I get the item in the event handler:

    private void Contacts_ItemAdd(object Item)
    {
        Outlook.ContactItem contact = (Outlook.ContactItem)Item;
        ...
    }

However, in case of remove event, I don't get the information of the removed item.

    private void Contacts_ItemRemove() {
        // how to get deleted item or at least it's EntryID?
    }

So how do I get the EntryID of the removed item? I use this ID to identify the item in the other service.



Solution 1:[1]

You need to maintain the list of items in each folder. And in the ItemRemove event handler you can compare out the list of existing items with yours. I'd recommend reading the following series of articles which gives an example for the NewMailEx event in Outlook (sometimes it is not fired at all, so developers should looks for possible workarounds like that):

Solution 2:[2]

All MAPI based notifications are raised after the action has already occurred. By the time you get the ItemRemove event, the message is already gone.

On the Extended MAPI level (C++ or Delphi only), when an item is deleted, the store provider raises the following fnevTableModified / TABLE_ROW_DELETED notification (you can see it in OutlookSpy (I am its author) if you click IMAPIFolder button and look at the log at the bottom of the GetContentsTable tab). Only PR_INSTANCE_KEY property is available:

ulEventType: fnevTableModified
    tab.ulTableEvent: TABLE_ROW_DELETED
    tab.propIndex: (PR_INSTANCE_KEY, cb:4, lpb: 0F 3E D3 A4 
    tab.propPrior: (PR_NULL, null)
    tab.row: (cValues : 0
    )

You can only make this work by retrieving PR_INSTANCE_KEY for all items in the folder beforehand so that you can map PR_ENTRYID <-> PR_INSTANCE_KEY.

Outlook Object Model does not expose PR_INSTANCE_KEY in the ItemRemove event. If using Redemption is an option (I am also its author), its RDOItems.ItemRemove event passes the instance key as a parameter. PR_INSTANCE_KEY for all items in a folder can be cached beforehand in a single call using RDOItems.MAPITable.ExecSQL method.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Eugene Astafiev
Solution 2