A small VBA project that runs Outlook local and server-side rules for all active iMap and Exchange accounts. Rules are run on both Read and Unread messages.
I started investigating this when, several months ago, my Exchange rules were no longer running on my Inbox with Outlook 2007. When it reoccured under a cleanly-installed (new profiles and recreated rules) Outlook 2016, I was far from content to be required to launch the Rules & Alerts dialog, select my Exchange account, click Run Rules Now..., place a check next to every rule, then click on Run Now. It was frustrating that, though others had reported this issue, neither Microsoft nor my Hosted Exchange provider could offer guidance.
After much searching, I came across OutlookCode.com, where Sue Mosher had posted an article in 2006 with the title Run all rules against inbox. This was exactly what I'd been looking for. Now I could run my rules with the click of a button I added to the Developer ribbon, or from a similar one added to the Quick Access Toolbar.
After a short while, I realized I wanted this macro to do more. I have eight (yes, really) different email accounts in my standard Outlook profile. One Exchange (the problematic one for rules, oddly enough), a couple of POP3 (no rules on these) and five iMap accounts (most have rules). As an aside, Outlook 2016 is so much better for iMap than was Outlook 2007. I just wish that was also true for running non-server rules.
Why did I want the macro to work with the iMap accounts too? Because I often check email on one or more of my tablets or phone. Once I've read a message, if I forget to mark it as unread, then the rules will not be applied, unless I run them manually and include unread messages (this is also true for the Exchange Inbox). Up until this time, I'd resorted to either manually sorting read messages or manually applying the rules for read messages. Now I had the chance to make it all happen with a single toolbar button.
It wasn't hard to update the code to be more robust (e.g. check for Offline or Cached mode, which leads to errors when you try to enumerate rules) and add multiple account processing. What was tricky was figuring out how to force the rules to run against each account's default inbox (see Points of Interest below for more on this).
One might think, after reviewing the sparse documentation on
Outlook.Rule.Execute, that simply enumerating the rules from the
DeliveryStore for each account would ensure that the rules were run against that account's Inbox. It took a while for me to understand that one is wrong for thinking that. Worse, I could not find anything on the Web that explained how this should work. Figuring out how the
Execute method chose the default folder was the trickiest part of this project.
Using the Code
Download the MyOutlookVBA.zip and extract the MyOutlookVBA.bas file. Open Outlook and press Alt-F11 to load the VBA editor. The default project name is often
Project1; the important thing is that next to that, in parenthesis, you should see VbaProject.OTM. Right Click the Modules folder, and select Import File... from the menu. When the Import File Dialog (really File Open, repurporsed) comes up, browse to the location where you extracted MyOutlookVBA.bas, and import it. Then click on the Save File icon in the VBA Editor toolbar (or select from the menu: File/Save VbaProject.otm).
Next, you will need to enable Macro Execution in Outlook's Trust Center. Once that is done, you have a few options. The first thing you will probably want to do, if you haven't already, is to show the Developer Tab on Outlook's Ribbon Bar. To run this macro, you can press the Macros button at the left side of the Developer ribbon and select
RunAllInboxRules, customize the ribbon to add a section to the Developer ribbon and create a button to execute
RunAllInboxRules to the Quick Access Toolbar, or some combination of these. If you don't want the results of
RunAllInboxRules output to the directory or file I've chosen, change that in the call to
LogInfo (see Additional Subroutines and Tracking Rule Exceptions below). I strongly suggest checking the log file now and again. It will tell you if any rules are failing, something that Outlook's automatic execution of rules (or manual execution via Run all rules against Inbox) does not do. This makes it a simple debugging tool for rules. Placing a breakpoint on the line with
rl.Execute will allow one to examine the details of the rule, to try to determine where things are going wrong... good luck with that ;-).
Points of Interest
The critical piece of getting this macro to work was understanding how
Rules.Execute works. In the end, it was manual operation of Outlook's rules via the Rules & Alerts dialog that gave me the needed clue. Here is an image of Run Rules Now from Outlook 2016:
Notice the options at the bottom of the dialog: Run in Folder, Include subfolders, Apply rules to. Each of these corresponds to 3 of the 4 parameters one can pass into
Rule.Execute. That led me to try the following code:
rl.Execute RuleExecuteOption:=OlRuleExecuteOption.olRuleExecuteAllMessages, _
rl is an Outlook.Rule object, and
st is the
Outlook.Store object for the current account (the
DeliveryStore to be precise). Using
GetDefaultFolder for each
Store was the key to pointing
rl.Execute at the correct Inbox. Otherwise, it seems to access the default Inbox for the active Outlook Profile (Exchange, in my case).
Additional Subroutines and Tracking Rule Execution
The original macro called
MsgBox to display the list of executed rules (that code is still present, albeit commented out). However, once I added multiple accounts (and with the number of rules I have defined), the limits of
MsgBox's text display cropped too much data. Plus, I did not like a
MsgBox popping up each time I ran my rules. I did want to know if there were any rule execution problems (or to note if any rules are disabled). That led me to add the
LogInfo subroutine. This simply outputs the
ruleList text to a text file (the folder location is passed as an argument (I use
"%USERPROFILE%\My Documents\Email\"). Note that the trailing backslash is required.
LogFile will create the final directory in the path, if required. All parent directories must exist, else
LogFile will fail with an error.
It is very important that when you import the VBA code into Outlook, you put the code in the Modules folder under VbaProject.otm. You will also need to go to the Tools/Trust center in Outlook and either enable macros with Warnings for All Macros, or use No Security Check (the latter option is dangerous).
You must ensure that you reference the Microsoft Office Object library for your Office version, as well as the Outlook Object library before you run this code. From the VBA Editor, click on Tools/References. For Outlook 2016, the required libraries are:
- Microsoft Outlook 16.0 Object library
- Microsoft Office 16.0 Object library
For my configuration, I also have these references:
- OLE Automation // needed for the LogInfo sub
- Visual Basic for Applications
- 2nd March, 2017: Initial release of the article/code
- 2nd March 2017
- Fixed mangled HTML that showed the HREF text vs. an actual link
- Typo & minor text formatting fix
- 3rd March 2017 - fixed more typos
I've been writing code as a hobby or for a living since 1970, working in machine code (octal input on a Compucorp programmable calculator), Assembler, Fortran (various flavors), Basic, APL, C, C++, Java, C#, PL/1 and others over the years. OS's used (sometimes as little as possible) include none (when writing machine code), IBM System/360 & 370 (with keypunch and TSO), OS/360 (really don't miss JCL), VM/CMS, DG RDOS, Unix, VAX/VMS, PC-DOS, MS-DOS and the many flavors of Windows.