Follow us on Twitter
Follow us on YouTube
Would you like to suggest a topic for the Exchange team to blog about? Send suggestions to us.
You've been using Outlook for years now and you've probably established some delivery rules for yourself. Maybe mail from your manager is automatically routed to a subfolder of your inbox. If you're using Outlook 2003 or later, you've got an automatically maintained rule to handle junk mail. If you've ever set your Out Of Office, that's handled by a rule too.
But how do rules actually work? What's the implementation like? Obviously, I won't get into the grimy details (trade secrets and all), but I can pass along the basics.
First, the rules infrastructure is fully documented on MSDN. Those among you brave enough to explore this documentation may be inspired to write a little app which will enumerate your inbox rules and print them out on the console for detailed inspection of just what Outlook creates. I wrote such an app for internal diagnostic purposes (which means I most likely can't share it with you, sorry). Oh wait! Someone else has already published something here!
A rule consists of two fundamental properties, and a bunch of other support properties which mostly won't matter for this discussion. The important ones are the rule's conditions, and the rule's actions. Simplistically, if the incoming mail passes the restriction, the rule engine subsequently carries out the actions. The rule engine itself is completely agnostic to the intentions of the rule creator. In other words, the rule engine doesn't care what the title of the rule type in Outlook's wizard is – it only applies the restriction and then if that passes, it carries out the actions.
The conditions are expressed as a MAPI Restriction. As each mail is delivered, the restriction on each rule is applied to the incoming message. The restriction describes a complex property value comparison tree, such as (the received time > somedatetime AND the sender's display name starts with "Bob" AND the body contains "Loser") OR (the message size is greater than 2k). Such restrictions are also used for searching for messages, filtering views, and so on. In this case, the restriction is applied to the incoming message. This means that rules cannot check against dynamic values, such as the current system time or how big the mailbox is. It's constrained to checking properties of the message against constant values. One exception to this is how the Junk Mail rule works, which I'll describe later.
Outlook has a variety of pre-canned restrictions that it uses and I won't go into the exact nature of each one (yes, I know, you're just burning to know what the precise nature of each of these is, but you can use the sample app I linked to above to study the precise nature of each of the rule types). I will point out an important design point though: rules which are of the form "FROM some DISTRIBUTION GROUP" actually means "if the sender is a direct or indirect member of that DL". This often confuses people because they create a rule like "mail from <my team DL>, move to the <my team> folder". What ends up happening is all mail from anyone on the "my team DL" starts having their mail moved to that folder. If you think about it, it makes complete sense. However, more often than not, folks really wanted the rule "mail SENT TO <my team DL>, move it".
If the message meets the restriction criteria, the actions are then carried out. While Outlook rarely creates rules with multiple actions within, it's possible to have a list of actions on one rule. The possible actions are:
The asterisk on Move and Copy refers to what to do if the server can't reach the destination database. In this case, the server turns it into a "defer to client" action where it specifies to the client a) the move or copy action and b) the destination that should be used. As you can see, the server itself is pretty constrained on the kinds of things it can do, yet Outlook offers all these wonderful actions that can be carried out. This is accomplished via the "deferred" action. The client stores in the action any relevant data it needs and the server will later notify the client that it needs to carry out a deferred action on a message, and includes whatever the client stored in the rule (such as, perhaps, the WAV data for the sound to play, for example).
Because a single rule could have conflicting actions, or even because multiple rules that may apply to the message could have conflicting actions, the server pulls off trickery to make sure everything happens correctly. For example, you may have two MOVE rules which apply to a message. You can't move a message to two different folders at once, yet that's the end result (the server treats subsequent MOVEs as if they were COPYs instead).
Exchange Server rules are only executed during delivery. Outlook provides a "Run Rules Now" feature, but that's implemented entirely by Outlook. The server is not involved. Also, realize that server rules are not ever executed after delivery is complete. If you witness spontaneous changes happening to your inbox, this is either Outlook carrying out deferred actions, or someone else logged into your mailbox is changing things under your feet.
What about the Junk Mail Rule? How does it adjust itself based on the administrator's configuration of the move action threshold? The administrator's configuration lives in Active Directory, so how could the rule dynamically retrieve this value for comparison against the Spam Confidence Level value stamped on all incoming messages? Well, there's a one-off cheat just for this. The rule itself is crafted to compare the Spam Confidence Level against the constant value -1. The rule execution engine pre-scans the restriction, looking for this specific comparison. If it finds it, it replaces the constant -1 with the current value in Active Directory, and then the restriction is applied to the incoming mail.
You may be thinking: "but what about two mailboxes, each with a reply rule that replies to the other mailbox? Won't that cause a mail storm?" Well, ordinarily, yes. However, our rules engine is smarter than that. As a rule is triggered on a message, the rule's ID is stamped into an ever-growing property of "I've already run this rule" history. Therefore, if a message "comes back", the rules engine can check to see if any particular rule is in this rule history and avoid running it again. So, if mbx1 sends mail to mbx2, which autoreplies back to mbx1, which autoreplies back to mbx2, the rules engine will detect the loop and not execute the rule that would otherwise cause another autoreply back to mbx1.
- Dave Whitney