Using the procmail program

The procmail program is available from http://www.procmail.org/

There is a great tutorial at http://www.ii.com/internet/robots/procmail/qs/

Installing procmail is beyond the scope of this document but note that many Linux distributions come with procmail already set up as the "local delivery agent". In such cases the presence of a ~/.procmailrc file is all that is necessary for a user to begin filtering mail using procmail.

The procmail program has a built-in ability to deliver into MH-style folders. Don't use it!

Nothing bad will happen if you use it but your mail will not be marked as "unseen". You must deliver mail into your folders using the MH/nmh rcvstore program for messages to be marked unseen.

When you have procmail filtering and delivering your mail into your folders it is normally no longer useful to run the "inc" program either from an xterm or from exmh. You should set your exmh background processing to "flist" and select an interval (see the Preferences panel for Background Processing in exmh).

An additional page about procmail is SpamAssassin via procmail


Instructions to the procmail program are placed in a file named .procmailrc in your home directory.

Example 1: The bare minimum

Here is a minimum ~/.procmailrc file for use with MH, nmh, and exmh:

 STORE=/usr/lib/mh/rcvstore
 LOCKEXT=.lock

 # Just store everything in the inbox
 :0 w :inbox/$LOCKEXT
 | $STORE +inbox

But what does it all mean? The first two lines just set values for a couple of useful variables. You see references to those variables in the last two lines. The line that begings with a "#" is, obviously, a comment. Only the last two lines do anything useful.

The ":" begins what is called a "recipe" in procmail. Just ignore the "0", apparently it's there, and is required, for historical reasons. The rest of the line consists of flags ("w" in this case) followed by an optional ":" and a local lockfile.

The "w" flag means wait for the filter or program to finish and check its exitcode (normally ignored).

Using a lockfile with procmail is very important! None of the MH/nmh programs do any locking. The most common result of that is getting your sequences damaged, which among other things means you won't have a reliable way of telling what mail is unread.


Recipe syntax

If that was all procmail could do it'd be pretty useless. The power of procmail comes from using conditions to select specific mail messages. Here's the generic format of a procmail recipe (from the procmailrc man page):

 :0 [flags] [ : [locallockfile] ]
 <zero or more conditions (one per line)>
 <exactly one action line>

Conditions start with a leading `*', everything after that character is passed on to the internal egrep literally, except for leading and trailing whitespace. These regular expressions are completely compatible to the normal egrep(1) extended regular expressions. See also Extended regular expressions.

By default the regular expression match is case insensitive and only processes the message's headers. There is a recipe flag to make it case sensitive and another recipe flag to process the body or entire message.

Conditions are anded; if there are no conditions the result will be true by default.

Example 2: A simple condition

Here's an example:

 # Trash Outlook autoreplies
 :0 w
 * ^subject:.*Out of Office AutoReply
 /dev/null

This example shows a condition that matches "out of office autoreply" in the subject header. If the condition is true then the message is '"delivered"' to a file named /dev/null.

Example 3: A simple but useful complete .procmailrc

Putting that together with the previous recipe gives this complete .procmailrc file:

 STORE=/usr/lib/mh/rcvstore
 LOCKEXT=.lock

 # Trash Outlook autoreplies
 :0 w
 * ^subject:.*Out of Office AutoReply
 /dev/null

 # Just store everything in the inbox
 :0 w :inbox/$LOCKEXT
 | $STORE +inbox

Which brings us to the subject of order in a .procmailrc file. Procmail takes each incoming email message and starts processing the recipes in the .procmailrc file at the top. Processing continues until an error occurs or until the message is delivered.


Example 4: A filtering recipe

There are two types of actions in procmail recipes, 'delivering' and 'non-delivering'. Delivering recipes "deliver" the message to a mailbox or program. Non-delivering recipes are such things as filters. For example:

 # Change the annoying back-to-list Reply-to
 :0 wf
 * ^reply-to*:.*exmh-(workers|announce|users)
 | formail -f -b -R Reply-to X-List-ReplyTo

This recipe uses the "f" flag to indicate that the pipe is a filter and does not deliver the message. Procmail processing will continue after this recipe using the output of the pipe to replace the input. The condition checks for a reply-to header addressed to a specific set of addresses. If that's found then the formail program, which is part of the procmail package, is used to change that header to "X-List-ReplyTo".

Note that the "w" flag with filters additionally implies that if the filter is unsuccessful, then the text will not have been filtered. Hmm - that's a quote from the man page. Basically, if the filter craps out, it doesn't do anything to the message.


Example 5: More complex ways filtering

Here's an example combination of a non-delivering recipe and a delivering recipe:

 # Blacklist. The file ~/Mail/blacklist contains a list of addresses (one per
 # line) that are matched against the sender. If there is a match, then
 # the sender is blacklisted and we send the mail to the bit bucket
 #
 BLACKLIST=$HOME/Mail/blacklist
 LOCKEXT=.lock
 :0 Whic :$BLACKLIST$LOCKEXT
 | (formail -x received: -x X-Envelope-From: -x from: -x sender:
 -x reply-to: -x return-path:| fgrep --quiet --ignore-case --file=$BLACKLIST)
 #
 :0 Wa
 /dev/null

More flags! In the first recipe you see the flags "Whic". "W" is the same as "w" but suppresses any "program failure" messages that would otherwise occur if the pipe ended with a non-zero return code. "h" causes the header to be fed to the pipe, the absence of "b" means that only the header is going to the pipe. "i" ignores write errors on the pipe, possibly due to the pipe being closed early.

The last flag is "c" which means "copy" or "clone" the message. That means that one copy of the message is used for the action in the current recipe and a copy is used for any following recipes. Contrast this with "f" where the output of the pipe is used in following recipes. See the comments of the recipe for a description of what the pipe in the first recipe does.

The second recipe of the pair also has a new flag, "a". The "a" flag is used to chain a recipe to the preceding recipe. A recipe with the "a" flag will only be executed if the preceding recipe executed and was successful (ended with a zero return code).

This pair of recipes tests for the presence of a member of a blacklist by matching against a number of headers. If there is a match, the message is "delivered" to /dev/null. Otherwise processing will continue with the next recipe.

On some systems it might be necessary to check what kind of options can be passed to fgrep, e.g. SunOS might require you to supply the above fgrep switches in the following manner: fgrep -s -i -f $BLACKLIST . This means exactly the same as above but otherwise fgrep raises some errors and the recipe is skipped.


Where to go next

For all the details on the .procmailrc file, have a look at the procmailrc man page that comes with the procmail distribution. There are a lot of useful examples in the procmailex man page but most of the examples show delivery into a mail spool type file.,.


Updated on 12 Oct 2004, 02:58 GMT
Search - Recent Changes - 2 References - Index - Go to Beedub's Wiki - Help