How to create custom Outlook rules and execute them programmatically: C# example
The Microsoft Outlook Rules is a very powerful feature that can sometimes get lost amongst the myriad other features and abilities of Outlook. Many Outlook programmers do not realise that Microsoft introduced a new rules object model in Outlook 2007 allowing developers to harness the power of Outlook rules.
In this article we’ll explore aspects of the rule object model and I’ll show you how to create your own rule and how to execute rules on demand on any folder in Outlook 2007, 2010 and 2013.
Creating the Outlook add-in project in Visual Studio
We’ll start by creating a new ADX COM Add-in project in Visual Studio 2012 with Add-in Express for Office and .net. If you’re wondering why my Visual Studio 2012’s colour scheme looks different than the default colour scheme, have a look at the Visual Studio 2012 Color Theme Editor.
Next, select your programming language (its C# for this project), minimum supported version of Office (I’m selecting Office 2007, since the new rules object model was only introduced in Outlook 2007, and my plug-in will work in Outlook 2007, 2010 and 2013) and Microsoft Outlook as the supported application and finish the wizard.
Creating the Outlook rule programmatically
Programmatically creating an Outlook rule is pretty straight-forward once you understand the object hierarchy and how all the pieces fit together. All the current users’ rules are stored in the Store objects’ Rules collection property. Each Rule within the Rules collection has a collection of RuleActions and RuleConditions.
In this example we’ll create a rule that will check for all mail items in a folder that contains the words “Order” or “Orders” and then move those mail items to a sub-folder in our Outlook root folder.
The following code first checks whether our Rule already exists, if not, we then check whether the destination “Orders” folder exists and if it does not exist, we create it. We then get a reference to the Outlook Rules collection and create our rule, its conditions and actions. You’ll need to wrap it inside a try-catch as the GetRules() method of the Store object will raise an exception if the user is not connected to Microsoft Exchange or if they are disconnected.
private void AddinModule_AddinStartupComplete(object sender, EventArgs e) { Outlook.NameSpace session = null; Outlook.Store store = null; Outlook.Rules rules = null; Outlook.MAPIFolder destinationFolder = null; Outlook.MAPIFolder rootFolder = null; Outlook.Folders rootFolderFolders = null; Outlook.Rule rule = null; Outlook.RuleConditions ruleConditions = null; Outlook.TextRuleCondition subjectTextRuleCondition = null; Outlook.RuleActions ruleActions = null; Outlook.MoveOrCopyRuleAction moveRuleAction=null; string ruleName = string.Empty; try { ruleName = "Move Order Mails Rule"; session = OutlookApp.Session; store = session.DefaultStore; rules = store.GetRules(); if (!RuleExist(ruleName, rules)) { rootFolder = store.GetRootFolder(); destinationFolder = GetFolder(rootFolder.FolderPath + "\\Orders",this.OutlookApp); if (destinationFolder == null) { rootFolderFolders = rootFolder.Folders; destinationFolder = rootFolderFolders.Add("Orders"); } rule = rules.Create(ruleName, Outlook.OlRuleType.olRuleReceive); ruleConditions = rule.Conditions; subjectTextRuleCondition = ruleConditions.Subject; subjectTextRuleCondition.Text = new string[] { "Orders", "orders", "Order", "order" }; subjectTextRuleCondition.Enabled = true; ruleActions = rule.Actions; moveRuleAction = ruleActions.MoveToFolder; moveRuleAction.Folder = destinationFolder; moveRuleAction.Enabled = true; ruleActions.DesktopAlert.Enabled = true; rules.Save(true); } LoadRules(); } catch (Exception ex) { Debug.Write(ex.Message); } finally { if (moveRuleAction != null) Marshal.ReleaseComObject(moveRuleAction); if (ruleActions != null) Marshal.ReleaseComObject(ruleActions); if (subjectTextRuleCondition != null) Marshal.ReleaseComObject(subjectTextRuleCondition); if (ruleConditions != null) Marshal.ReleaseComObject(ruleConditions); if (rule != null) Marshal.ReleaseComObject(rule); if (rootFolderFolders != null) Marshal.ReleaseComObject(rootFolderFolders); if (rootFolder != null) Marshal.ReleaseComObject(rootFolder); if (destinationFolder != null) Marshal.ReleaseComObject(destinationFolder); if (rules != null) Marshal.ReleaseComObject(rules); if (store != null) Marshal.ReleaseComObject(store); if (session != null) Marshal.ReleaseComObject(session); } }
The LoadRules() method loads all Outlook rules into a Ribbon combo-box, and the code listing for this method is as follows:
private void LoadRules() { Outlook.NameSpace session = null; Outlook.Store store = null; Outlook.Rules rules = null; try { session = OutlookApp.Session; store = session.DefaultStore; rules = store.GetRules(); for (int i = 1; i <= rules.Count; i++) { Outlook.Rule rule = rules[i]; ADXRibbonItem item = new ADXRibbonItem(); item.Caption = rule.Name; ruleNamesRibbonComboBox.Items.Add(item); } } finally { if (rules != null) Marshal.ReleaseComObject(rules); if (store != null) Marshal.ReleaseComObject(store); if (session != null) Marshal.ReleaseComObject(session); } }
Running your custom Outlook rule on demand
Now that we've created the rule, let's add functionality that will allow the user to run any custom Outlook rule on demand for the current folder. To do this, we need to add a new ADXRibbonTab control to the design surface of the AddinModule designer, and design its layout to resemble the following image:
Add the following code to the buttons' OnClick event:
private void runRuleRibbonButton_OnClick(object sender, IRibbonControl control, bool pressed) { Outlook.Explorer currExplorer = null; Outlook.MAPIFolder currFolder = null; Outlook.NameSpace session = null; Outlook.Store defaultStore = null; Outlook.Rules rules = null; Outlook.Rule selectedRule = null; try { currExplorer = OutlookApp.ActiveExplorer(); currFolder = currExplorer.CurrentFolder; session = currExplorer.Session; defaultStore = session.DefaultStore; rules = defaultStore.GetRules(); selectedRule = rules[ruleNamesRibbonComboBox.Text]; if (selectedRule != null) { selectedRule.Execute(true, currFolder, includeSubFoldersRibbonCheckBox.Pressed, Outlook.OlRuleExecuteOption.olRuleExecuteAllMessages); } } catch (Exception ex) { Debug.Write(ex.Message); } finally { if (selectedRule != null) Marshal.ReleaseComObject(selectedRule); if (rules != null) Marshal.ReleaseComObject(rules); if (defaultStore != null) Marshal.ReleaseComObject(defaultStore); if (session != null) Marshal.ReleaseComObject(session); if (currFolder != null) Marshal.ReleaseComObject(currFolder); if (currExplorer != null) Marshal.ReleaseComObject(currExplorer); } }
The code above grabs the name of the rule to run from the combo-box and executes the rule on the currently open folder in the Outlook Explorer, if it finds mails with the words "Order" or "Orders" in their subject lines it then moves them to the Orders folder. It will also search the current folder's sub-folders if the user has checked the "Include Sub-folders" checkbox on the ribbon tab.
It's a good idea to set the first parameter of the Execute() method to True, as this will then display a progress window, indicating to the user that Outlook is busy executing a rule and will stop the user from thinking Outlook is hanging.
And as easy as that you too can harness the power of Outlook Rules in your Microsoft Outlook add-in!
Thank you for reading! Until next time, keep coding!
Available downloads:
This sample Outlook add-in was developed using Add-in Express for Office and .net:
18 Comments
Pieter and Add-in Express Team,
In a similar way to this, I am trying to do some email processing after outlook starts and folders are updated. I built part of my logic in AddinModule_AddinStartupComplete but as it requires database connection and processing, the whole outlook app is failing to start. Even adding a timer event procedure in this subroutine to delay the process and give outlook time to load didn’t help. Initially it worked just fine, but once it started failing, it keeps doing that. Outlook works fine if I remove the logic from the start up routine.
My question is, is there a different way to do some processing right after this routing is done? or right after outlook is done retrieving emails and updating folders (outside of this subroutine)?
Thanks,
Mesfin
Hi Mesfin,
Can you elaborate a bit more on what it is your add-in is doing? Do you loop through all emails in the inbox?
If you loop through the emails, do you make changes to the actual email and save it back to Outlook or do you save info about the email to a database?
Pieter,
I loop through all emails in the inbox to save some specific emails into a drive or a pst folder, which is done thru some search words saved in an access database. Before doing that, I pull the drive info from the access db. The actual processing of the emails is done in a different subroutine which is called from add-in start up complete itself. I suspect loading of my add-in is completed before Outlook finishes it’s start-up process and is getting disabled by Outlook as it is causing outlook delay to finish the start up. That was why I put a ticker event to let Outlook finish before starting my processes such as parsing the inbox or look up info in a db.
An application level event or similar to that which would tell me that Outlook was done starting would be really helpful to do my processing right after that.
Otherwise, users can move or delete emails before I start my processing.
Thanks
Hi Mesfin,
It sound like the problem here is the slow speed at which Outlook items are processed. All processing happens on Outlook’s main thread so Outlook will freeze up
when processing large quantities of items. I would recommend you try to process items in smaller portions e.g. When the add-in starts start the Timer that performs the processing
every 2 seconds, take the firs 100 emails, process them and wait another 2 seconds.
You would have to consider running starting the timer in another thread or background worker to avoid causing Outlook to freeze.
Hope this helps, and good luck!
Hello Pieter.
I have been able run the timer in a background and let Outlook start without any delay. After that, I call my email processor, which is run after emails are loaded.
Would still like to know if there is an event or a way to know that Outlook is done loading all emails and folders though.
Thanks a lot for your help.
Regards,
Mesfin
Hi Mesfin,
Glad to hear that you made some progress!
Unfortunately, as far as I know, there is no specific event that fires when Outlook finished processing all emails and folders. The SyncEnd event seems like a likely solution but it appears to only function well for pop3 accounts, not exchange server accounts.
Maybe have a look at the solution we proposed on how to effectively handle new mail. You might be able to adopt a similar approach for your project.
Good Luck!
Can’t find RuleExist() and GetFolder() methods. Where can I get it?
Hi Tahiaji,
You can download the sample project available at the end of the article and you will find the methods in question there.
Thank you, I did not see sample project
Hello,
Please search the words “Available downloads” on the page.
Hallo,
kann man auch “Regeln für automatische Antworten” erstellen?
____________________________________________________________
Hallo,
can I also create “auto-reply rules”?
Translated with google
Hi Thomas,
I’ve done some research and it does not look like you can create a rule to auto reply. The RuleActions object does not appear to have a property for it.
You would probably have to create a solution using the NewMail/NewMailEx events.
Hope this helps and good luck!
Hi,
How to programmatically perform action when the first click happens on message body box? I want to capture the Outlook.MailItem.Recipients as soon as the first click happens on message body box.
Hi Abhi,
Mmm…interesting challenge. Have a look at the solution explained here
Their approach was to check whether certain Ribbon items were disabled and based on that they could establish whether the e-mail body has the focus or not.
Hope this helps. Good luck!
Hi,
I am trying to build dynamic rule using outlook 2016 and VS 2015 on win7 64 bit but got stuck please help.
I am not able to move forward from this line:
colRules = Application.Session.DefaultStore.GetRules()
It says This store does not support rules
Please help
Thanks,
Rashid
Hello Rashid,
This can be a limitation of the Outlook message store that you use. Is this an IMAP folder? PST? Exchange? Check if you can create a rule in the Outlook UI. If yes, check if there are other stores that support rules.
Hi Pieter,
How to find definition for below two methods:
GetFolder
RuleExist
Hi Murtaja,
You can download the sample project available at the end of the article and you will find the methods in the source code.