Fixing Outlook's terrible IMAP deletion handling with vbscript

May 26th, 2009 - Written By: Jared Hollingsworth <webmaster@telekawaru.com>

I initially started using IMAP through outlook with version 2003. If you've used it for IMAP, or attempted to, then I'm sure you've felt my pain. Outlook 2007 should have been the fix for their terrible IMAP implementation, but alas, it was not.

I spent some time digging around online to find a way to make Outlook handle deleting emails a little more appropriately for an IMAP account. Most of the solutions involved incorporating a macro into the toolbar and from there having to highlight the emails to be 'deleted' and clicking an additional button. (see this and this) This solution was not acceptable since an untrained user will not know to do this. I needed something better.

I've never specifically written any VBA previously, but I have used Visual Basic frequently in the past, so I figured I would at least have an understanding of the language. I spent some time digging around the MSDN for object reference and getting myself familiar with inspectors and explorers.

I ended up adding inspectors to almost everything and watching as the events fired. At first it seemed like the MailItem's 'BeforeDelete' was my answer, but that only handled emails that you opened in it's own window and not any other time. What I ended up discovering is that a folder would fire the 'BeforeItemMove' even when an item was deleted, whether it was with the delete key or the toolbar button. The difference is that the MoveTo would be Nothing, instead of a destination folder. By trapping this event and passing it with my own function, the deleted emails can be moved to a trash folder of my own specification.

Of course the downside of this is that Outlook simply marks messages for deletion and shows them with a strikethrough. There are a few ways this can be handled. I've chosen to simply have outlook hide the items marked for deletion, and the folders auto-purge when changing (defined in the account settings). This meets all of my needs and is transparent to the user.

So basically this is what the code does: When you start Outlook, the script will create references so that it can watch as events happen. When you do something that would cause an item to be deleted (press delete, click the X on the toolbar) it will check to see if we have a folder named 'Trash' under the root folder, and if so, it will move the email to that folder.

Update February 7th, 2010: Received several emails of people having problems using the specified code, changed code to look for folder named "Deleted Items" which is the default Outlook trash folder name. Was previously using IMAP Trash default.

Update June 1st, 2009: Added check for Trash folder items so you can actually delete something that's in the trash

Outlook will need to be restarted after adding this code

To use this code, copy and paste it into 'ThisOutlookSession' in the VBA editor. (Tools/Macro/Visual Basic Editor) See the screenshots below for help.

Tools Menu/Macro/Visual Basic Editor ThisOutlookSession
Open the Visual Basic Editor Be sure you are in 'ThisOutlookSession' before pasting the code

You can either copy/paste this code or download outlookimapfix.txt


Public WithEvents myItem As MailItem            'for trapping deletion of opened mail
Public WithEvents myInspector As Inspectors     'for trapping new windows
Public WithEvents myExplorer As Explorer        'for folder reference
Public WithEvents myFolder As Folder            'for trapping mail deletion in main outlook window
Public myNameSpace As NameSpace                 'Parent folder
Private Sub Application_Startup()
    Set myInspector = Application.Inspectors
    Set myExplorer = Application.ActiveExplorer
    Set myFolder = myExplorer.CurrentFolder
    Set myNameSpace = Application.GetNamespace("MAPI")
End Sub
Private Sub myExplorer_BeforeFolderSwitch(ByVal NewFolder As Object, Cancel As Boolean)
    Set myFolder = NewFolder
End Sub
Private Sub myFolder_BeforeItemMove(ByVal item As Object, ByVal MoveTo As MAPIFolder, Cancel As Boolean)
    If TypeName(item) = "MailItem" Then         'only trap mail items
        Dim lMI As MailItem
        Set lMI = item
        If MoveTo Is Nothing And lMI.Parent <> "Deleted Items" Then	'Item was deleted
            moveIMAPItem lMI
            Cancel = True                       'bypass normal deletion function
        End If
    End If
End Sub
Private Sub myInspector_NewInspector(ByVal Inspector As Inspector)
    If Inspector.CurrentItem.Class = olMail Then Set myItem = Inspector.CurrentItem 'New window for reading mail
End Sub
Private Sub myItem_BeforeDelete(ByVal item As Object, Cancel As Boolean)
    If TypeName(myItem) = "MailItem" Then       'only trap mail items
        moveIMAPItem item
        Cancel = True                           'bypass normal deletion
    End If
End Sub
Private Sub moveIMAPItem(ByVal item As Object)
    Dim lMI As MailItem
    Dim fParent As Folder
    Dim parentFolder As Folder
    Dim trashFolder As Folder
    Set lMI = item
    Set fParent = myExplorer.CurrentFolder
    Do Until fParent.Parent = myNameSpace       'Root folder
        Set fParent = fParent.Parent
    Loop
    Set parentFolder = fParent
    If parentFolder.Folders("Deleted Items") Is Nothing Then 'Deleted Items folder doesn't exist
        MsgBox "Unable to find folder named 'Deleted Items'", vbOKOnly + vbInformation, "IMAP Delete" 'Inform user and exit routine
        Exit Sub
    End If
    Set trashFolder = parentFolder.Folders("Deleted Items") 'Set destination
    lMI.Move trashFolder                            'move email
End Sub