Procmail

Procmail allows you to filter email as it is received from a remote email server, or placed in your spool file on a local or remote email server. It is powerful, gentle on system resources, and widely utilized. Procmail, commonly referred to as a Local Delivery Agent (LDA), plays a small role in delivering email to be read by an MUA.

In order to use Procmail, it must first be installed. Type the rpm -q procmail command to see if the procmail package is installed. If, for some reason, Procmail is not on your system, install it from the Red Hat Linux installation CD-ROMs.

Procmail can be invoked in several different ways. As email is placed on your email spool file, Procmail can be configured to start up, filter the email to locations configured for use with your MUA, and quit. Or, your MUA could be configured to bring up Procmail any time a message is received so that messages are moved into their correct mailboxes. In many cases, the presence of a .procmailrc file in the user's home directory will invoke Procmail, if Sendmail is being used.

The actions Procmail takes with an email are dependent upon instructions from particular recipes, or rules, that messages are matched against by the program. If a message matches the recipe, then the email will be placed in a certain file, deleted, or otherwise processed.

When Procmail starts, it reads the email message and separates the body from the header information. Next, Procmail looks for the /etc/procmailrc file and rc files in the /etc/procmailrcs directory for default, system-wide, Procmail environmental variables and recipes. Then, Procmail looks for a .procmailrc file in the user's home directory to find rules specific to that user. Many users also create additional rc files of their own for Procmail that are referred to by their .procmailrc file but may be turned on or off quickly if a mail filtering problem develops.

By default, no system-wide rc files exist in the /etc directory, and no user .procmailrc files exist. To begin using Procmail, you will need to construct a .procmailrc file with particular environment variables and recipes explaining what you would like to do with certain messages.

In most configurations, the decision as to whether Procmail starts and attempts to filter your email is based the existence of a user's .procmailrc file. To disable Procmail, but save your work on the .procmailrc file, move it to a similar file's name using the mv ~/.procmailrc ~/.procmailrcSAVE command. When you are ready to begin testing Procmail again, change the name of the file back to .procmailrc. Procmail will begin working again immediately.

Procmail Configuration

Procmail configuration files, most notably the user's .procmailrc, contain important environmental variables. These variables tell Procmail which messages to sort, what to do with the messages that do not match any recipes, and so on.

These environmental variables usually appear in the .procmailrc file at the beginning, in the following format, each on their own line:

<env-variable>="<value>"

Figure 16-7. Structure of an environmental variable line

In this example, the <env-variable> is the name of the variable, and the <value> section defines the variable.

Many environment variables are not used by most Procmail users, and many of the more important environment variables are already defined a default value. Most of the time, you will be dealing with the following variables:

Other important environmental variables are pulled from your shell, such as LOGNAME, which is your login name, HOME, which is the location of your home directory, and SHELL, which is your default shell.

A comprehensive explanation of all environments variables, as well as their default values, is available on the procmailrc man page.

Procmail Recipes

New users often find the construction of recipes the most difficult part of learning to use Procmail. To some extent, this is understandable, as recipes do their message matching using regular expressions, which is a particular format used to specify qualifications for a matching string. However, regular expressions are not very difficult to construct and even less difficult to understand when read. Additionally, the consistency of the way Procmail recipes are written, regardless of regular expressions, makes it easy to figure out what is going on.

A thorough explanation of regular expressions is beyond the scope of this chapter. The structure of Procmail recipes is more important, and useful sample Procmail recipes can be found at various places on the Internet, including http://www.iki.fi/era/procmail/links.html. The proper use and adaptation of the regular expressions found in these recipe examples depends upon an understanding of Procmail recipe structure. Introductory information specific to basic regular expression rules can be found on the grep man page.

A Procmail recipe takes the following form:

:0<flags>: <lockfile-name>

* <special-condition-character> <condition-1>
* <special-condition-character> <condition-2>
* <special-condition-character> <condition-N>

<special-action-character><action-to-perform>

Figure 16-9. Structure of a Procmail recipe

The first two characters in a Procmail recipe are a colon and a zero. Various flags can optionally be placed after the zero to control what Procmail does when processing this recipe. A colon after the <flags> section specifies that a lockfile will be created for this message. If a lockfile is to be created, you specify its name in the <lockfile-name> space.

A recipe can contain several conditions to match against the message. If it has no conditions, every message will match the recipe. Regular expressions are placed in some conditions in order to facilitate a match with a message. If multiple conditions are used, they must all match in order for an action to be performed. Conditions are checked based on the flags set in the recipe's first line. Optional special characters placed after the * character can further control the condition.

The <action-to-perform> specifies what is to happen to a message if it matches one of the conditions. There can only be one action per recipe. In many cases, the name of a mailbox is used here to direct matching messages into that file, effectively sorting the email. Special action characters may also be used before the action is specified.

Delivering vs. Non-Delivering Recipes

The action used if the recipe matches a particular message determines whether recipe is considered delivering or non-delivering. A delivering recipe contains an action that writes the message to a file, sends the message to another program, or forwards the message to another email address. A non-delivering recipe covers any other actions, such as when a nesting block is used. A nesting block is an action contained in braces { } that designates additional actions to perform on messages that match the recipe's conditions. Nesting blocks can be nested, providing greater control for identifying and performing actions on messages.

Delivering recipes that match messages causes Procmail to perform the action specified and stop comparing the message against any other recipes. Messages that match conditions in non-delivering recipes will continue to be compared against other recipes in the current and following rc files. In other words, non-delivering recipes cause the message to continue through the recipes after the specified action is taken on it.

Flags

Flags are very important in determining how or if a recipe's conditions are compared to a message. The following flags are commonly used:

  • A — Specifies that this recipe will only be used if the last previous recipe without an A or a flag also matched this message.

    To ensure that the action on this last previous matching recipe was successfully completed before allowing a match on the current recipe, use the a flag instead.

  • B — Parse the body of the message and look for matching conditions.

  • b — Use the body in any resulting action, such as writing the message to a file or forwarding it. This is the default behavior.

  • c — Generate a carbon copy of the email. This is useful with delivering recipes, since the required action can be performed on the message and a copy of the message can continue being processed in the rc files.

  • D — Makes the egrep comparison case-sensitive. By default, the comparison process is not case-sensitive.

  • E — Similar to the A flag, except that the conditions in this recipe are only compared to the message if the immediately preceding recipe without an E flag did not match. This is comparable to an else action.

    Use the e flag instead if you only want this recipe checked if the preceding recipe matched but the action failed.

  • f — Uses the pipe as a filter.

  • H — Parses the header of the message and looks for matching conditions. This occurs by default.

  • h — Uses the header in a resulting action. This is the default behavior.

  • w — Tells Procmail to wait for the specified filter or program to finish and report whether or not it was successful before considering the message filtered.

    If you would like to ignore "Program failure" messages when deciding whether a filter or action succeeded, use the W option instead.

Additional flags can be found in the procmailrc man page.

Specifying a Local Lockfile

Lockfiles are very useful with Procmail to ensure that more than one process does not try to alter a certain message at the same time. You can specify a local lockfile by placing a colon (:) after any flags on a recipe's first line. This will create a local lockfile based on the destination filename plus whatever has been set in the LOCKEXT global environment variable.

Alternatively, you can specify the name of the local lockfile to be used with this recipe after the colon.

Special Conditions and Actions

Particular characters used before Procmail recipe conditions and actions change the way they are interpreted.

The following characters may be used after the * character at the beginning of a recipe's condition line:

  • ! — Inverts the condition, causing a match to occur only if the condition does not match the message.

  • < — Checks to see if the message is under the specified number of bytes.

  • > — Checks to see if the message is over a particular number of bytes.

The following characters are used to perform special actions:

  • ! — Tells Procmail to forward the message to the specified email addresses

  • $ — Refers to a variable set earlier in the rc file. This is usually used to set a common mailbox that will be referred to by various recipes.

  • | — The pipe character tells Procmail to start a specific program to deal with this message.

  • { and } — Constructs a nesting block, used to contain additional recipes to apply to matching messages.

If no special character is used at the beginning of the action line, then Procmail assumes that the action line is specifying a mailbox where the message should be written.

Recipe Examples

Procmail is an extremely flexible program, allowing you to match messages with very specific conditions and then perform detailed actions on them. As a result of this flexibility, however, composing a Procmail recipe from scratch to achieve a certain goal can be difficult for new users.

The best way to develop the skills to build Procmail recipe conditions stems from a strong understanding of regular expressions combined with looking at many examples built by others. The following very basic examples exist to serve as a demonstration of the structure of Procmail recipes and can provide the foundation for more intricate constructions.

The most basic recipes does not even contain conditions, as is demonstrated in Figure 16-10.

:0:
new-mail.spool

Figure 16-10. Example with no conditions

The first line starts the recipe by specifying that a local lockfile is to be created but does not specify a name, leaving Procmail to use the destination filename and the LOCKEXT to name it. No condition is specified, so every message will match this recipe and, therefore, will be placed in the single spool file called new-mail.spool, located within the directory specified by the MAILDIR environment variable. An MUA can then view the messages in this file.

This basic recipe could go at the end of all rc files to direct messages to a default location. A more complicated example might grab messages from a particular email address and throw them away, as can be seen in Figure 16-11.

:0
* ^From: spammer@domain.com
/dev/null

Figure 16-11. Example of email sent to /dev/null

With this example, any messages sent by spammer@domain.com are immediately moved to /dev/null, deleting them.

CautionCaution
 

Be very careful that a rule is working correctly before moving messages matching it to /dev/null, which is a permanent deletion. If your recipe conditions inadvertently catch unintended messages, you will not even know you are missing those messages unless the sender tells you.

A better solution is to point the recipe's action to a special mailbox that you can check from time to time in order to look for false positives, or messages that inadvertently matched the conditions. Once you are satisfied that no messages are accidentally being matched, you can delete the mailbox and direct the action to send the messages to /dev/null.

Procmail is primarily used as a filter for email, automatically placing it in the right place so that you do not have to sort it manually. The recipe in Figure 16-12 grabs email sent from a particular mailing list and puts in the correct folder for you.

:0:
* ^(From|CC|To).*tux-lug
tuxlug

Figure 16-12. Example of list filtering

Any messages sent from the tux-lug@domain.com mailing list will be placed in the tuxlug mailbox automatically for your MUA. Note that the condition in this example will match the message if it has the mailing list's email address on the From, CC, or To lines.

Procmail can also be used to block spam, although this is not a good long-term solution for junk mail. Consider the following temporary spam filtering solution in Figure 16-13, where multiple recipes are set to use a common mailbox to store the junk.

SPAM=junk

:0:
* To??^$
$SPAM

:0:
* ^(To|CC):.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,
$SPAM

:0:
* ^Message-Id:.*<[^@]*>
$SPAM

Figure 16-13. Example of a basic spam filter

In this example, the junk mailbox is associated with the SPAM variable, so that you can change the mailbox that holds your spam in one place. Then, three recipes look for messages to send to the junk mailbox.

The first recipe looks for messages that have no recipient in the To line. The second recipe matches any messages with 12 or more recipients. The third recipe looks for messages with a bad message ID.

These simple examples are provided to help get you started creating recipes. Consult the many Procmail online resources available from the Section called Additional Resources to see more detailed and powerful recipes.