Home Index Search Links About Us
  News   Archives

Managing Your Mail with procmail

by Angel Lopez


Installation

Basic Functions

Configuration

Mailing Lists

Responding Mail

Infinite Loops

Decoding Files

Conclusion

Installation

The first step is to get the latest version of procmail. When this article was started the last version was 3.11pre7.

After getting the source code for the program, in order to install it it will be necessary to uncompress and unpack it using the following command: tar -xzvf procmail.tar.gz

The next step is to edit the files Makefile and config.h. Since this article is only an introduction and to keep things simple in this first introduction, we will not explain the various configuration options of these files. The interested reader can consult the manual pages and the documentation provided with the sources.

Nevertheless, it is convenient to mention the existence of the option BASENAME in the Makefile. With this option we indicate the directory base where procmail will be installed. From the basename directory we indicate will hang other directories as bin and man.

Finally, to compile the package we must execute the command make install.

Procmail can be installed for the whole system and then be called through some rule of sendmail(8) or it can be by some user for his personal use. In the later case, the user will indicate the use of procmail in his .forward, where a line like the following should be present:

|IFS=' ' && exec /home/juan/procmail/bin/procmail -f- || exit 75 #juan

In this line I assumed that the user juan has installed procmail in his HOME. For this particular line the BASENAME that should have been specified during compilation is /home/juan/procmail.

Basic Functions

Procmail reads from its standard input. It checks the file .procmailrc which is a configuration file that the user should have in his HOME. This file defines certain rules that will tell procmail what to do after reading a message. It can be directed to check for certain strings in the header of the message, in order to decide whether to save the message, ignore it, reply automatically, etc..

Procmail also let us deal automatically with the arriving mail or the mail stored in a file.

Configuration

The configuration file used is .procmailrc and it must be placed in HOME.

Every line started with # is considered a comment.

Lines started with :0 or :0: indicate the beginning of a new rule which tells procmail what to do with a message.

The lines started with * indicate a condition to be satisfied for a rule to apply. This is the mechanism procmail uses to select which messages require processing with the rule and which do not.

The remaining lines, that is, those not starting with a :, or * are considered commands, in other words the action to be applied by procmail to the message satisfying the condition. Some possible actions or commands are deleting a message, forwarding a message, saving a message, saving a message...

The first thing to be indicated in a .procmailrc are some of the environment variables, here are some of the variables I would recommend to define in your .procmailrc

MAILDIR
Indicates the directory where procmail saves the files with mail messages. This variable usually point to $HOME/mail or $HOME/Mail. Whether is one or the other is a matter of the kind of mail reader being used.

LOGFILE
Indicates the name of a log file where procmail leaves record of all the transactions carried out.

SENDMAIL
Indicates where to find sendmail, which will be used to automatically reply messages.

FORMAIL
Indicates where to find formail. This program is distributed together with procmail and its purpose is to modify the mail headers or to reformat a message before sending or storing a message.

DEFAULT
File where a message is saved if procmail was not able to apply any of the rules defined.

Anywhere in .procmailrc one can define an environment variable. If the variable is written without the symbol = follow by a value, such variable is removed.

Regarding rules, they come in two groups: Rules that consider the message delivered after applying their action and rules that do not.

The first rules are simple, after applying their action then assume no further rules should apply to this message and therefore deliver it.

The second type of rules, those that do not consider the message delivered, upon applying their action are very useful when one wishes the possibility of applying multiple rules and actions to the same message before delivery.

The general syntax for a rule is the following:

 
           :0 [options] [ : [exclusion file] ] 
           * condition 1 
           * condition 2 
                 . 
                 . 
                 . 
           * condition N 
           command 
           

Lets go by parts analyzing this construction. First every rule starts with a :0, after it may follow any of these options:

H The condition is applied to the mail header.
B The condition is searched in the body of the message.
D When the condition is investigated, upper and lower cases are distinguishable.
A This rule is applied only if the previous one was.
a Like A, except that the execution of the previous rule must have been carried out without errors.
E This rule is executed if the previous one was not.
e This rule will be executed if the previous one was executed but exit with some error.
h The message header is passed to the command.
b The message body is passed to the command.
f The command is interpreted as a filter.
c Generate a carbon copy cc of the message. When executing a rule that considers the message delivered with this flag, then one accomplishes a work around its delivery, and further rules can be applied to the carbon copy of the message.
w Wait until the command finish executing to receive its exit code.
W As the previous option but in case of error does not emit any messages.
i Ignore the possible typing errors.
r Writes the message such as it is. It does not test whether it ends with a blank line.

By default, if no options are specified, the condition is tested on the mail header (option H). The command receives in its standard input both header as boy of the message (options h and b). There is no distinction between upper and lower case.

After :0 and the possible options, a second : may follow, if it does it indicates that the destination file where the message is going to be written should be blocked to avoid two processes writing simultaneously over the file. Optionally one can indicate the exclusion file which is used as a lock.

Next follow the conditions, one per line and preceded by a * character. Conditions are usually written as regular expressions in order to find character string within the header or body of a message. Regular expressions use the following symbols among others:

^ Beginning of a line.
$ End of a line . Any character except a carriage return
* Zero or more times.
+ One or more times.
? Zero or more times.
[a-z] Range of characters, in this example from a to z.
[^a-z]Any character outside the range a to z.
a|b Either 'a' or 'b'

After the conditions come a single command. If the first character of the command is any of the following then a special behavior onsets:

! The message is redirected to all the mail addresses indicated.
| If this symbol is continued by an executable then it is run whenever the condition is satisfied. If nothing follows the symbol the full text of the message goes to the standard output. If instead the name of a variable follows |, then the result of the indicated command is saved into that variable.

Mailing Lists

A situation where procmail can be very useful is in the management of our mail. Let us suppose that we are subscribed to three Linux mailing lists. each list is identified by the address of origin, for instance we could have the following addresses

 
           l-linux@calvo.teleco.ulpgc.es 
           linux@nuclecu.unam.mx 
           linux-security@redhat.com 
         

Under normal circumstances the messages from these mailing lists will arrive together, at the same mail box, and if nothing is done they will remain mixed up. It would be much easier if as the mail were arriving if was sorted and stored in appropriate files.

Procmail can solve this problem easily. We could use a file .procmailrc with the following simple rules to sort our mail from the Linux mailing lists:

 
:0 
* ^From.*l-linux@calvo.teleco.ulpgc.es 
l-linux 
 
:0 
* ^From.*linux@nuclecu.unam.mx 
linux-mx 
 
:0 
* ^From.*linux-security@redhat.com 
linux-security 

Let us examine carefully one of the rules. If you understand the inner workings of a rule, then is easy to understand the rest because the basic mechanism is always the same.

First one finds a :0 string that indicates the beginning of a new rule. There are no further options so procmail will take the default options for this rule: upper and lower case are indistinguishable, the condition applies only to the mail header, the command receives both header and body of the message.

In the next line one finds the condition, that as it was previously mentioned is always identifiable because its first character is a *. The condition is the following regular expression:

^From.*linux@nuclecu.unam.mx

The substring ^From tells procmail to search for those lines beginning by the substring From

.

The following .* character, means any number of characters. We saw before that in regular expressions a "." character is equivalent to any character and that * refers to zero or more. Then .* means that after the initial From there may be zero or more characters.

Next should come linux@nuclecu.unam.mx, which is the address from where the messages originate.

Thinking a bit about the regular expressions, you will see that the following lines would be recognize by this rule:

 
From: linux@nuclecu.unam.mx 
From:linux@nuclecu.unam.mx 
FROM linux@nuclecu.unam.mx 

With this rule one can already distinguish messages coming from this address and the others. So now that one has the message what shall be done with it?.

The next line is the command (or action), and it indicates what to do with the message. In this case it is supposed to be deliver to the file linux-mx where it should be stored. In case of not indicating the absolute path to the file, by default it will be considered relative to the environment variable $MAILDIR.

Clearly messages arriving from different lists can now be distributed to various files according to their origin (From field).

Automatic Reply

Other situation where procmail will be useful is for automatic replies. It comes often handy, for example, if you wish to send your public PGP key automatically to anyone that requests it by E-Mail

To do this, write a rule that will consider as a petition for our PGP public key any message with the string PGP in its subject. This rule can be written as:

 
0: 
* ^Subject.*PGP 
| (formail -r ; cat $HOME/key.asc) | sendmail -t 

This same idea can be applied to write the typical program that lets people known we are off on vacation and that we will reply to their E-Mail after coming back:

 
0: 
| (formail -r; cat $HOME/vacations.txt) | sendmail -t 

In the last case there is no condition since all messages should be sent the same notice.

Avoiding Infinite Loops in Automated Replies

In the previous examples no attempt was made to handle possible infinite loops that sometimes occur when mail is answered automatically.

If a message whose origin is our own E-Mail address, the program would reply to that address, then the reply would come back to us. This message would be replied once more and so on in an infinity loop. In order to avoid it, when answering the message one should add an extra line in the header to indicate that message was already answered. Using the option -A of formail:

formail -r -A"X-Loop: dir@email.es"

Where dir@email.es would be your own E-Mail address. This way when generating the header for the reply the line X-Loop is added so that later on one can check for it with a new rule:

 
:0 
* !^X-Loop: dir@email.es 
| (formail -r -A"X-Loop: dir@email.es" ;  
    cat $HOME/vacation.txt) | sendmail -t 

This rule prevents an infinite loop because any message containing in the header a line X-Loop will not satisfy the condition and as a result will not be answered by procmail.

Decoding Files

Another interesting rule for our .procmailrc is that which decodifies the incoming mail encoded with uuencode(1) automatically. The rule could be given as:

 
:0 B 
* ^begin 644 .* 
{ 
	MAILDIR=$HOME/files 
	 
	:0 
	| uudecode 
} 

Here it is explicitly indicated with the option B that the rule's condition should only be tested on the body of the message.

If the rule finds a line beginning with the string "begin 644" it means that it has found the beginning of a file encoded with uuencode(1) so it establishes the environment variable MAILDIR, which is equivalent to changing the directory pointed by that variable. From that moment on, all the print or display actions will be perform taking the base directory indicated. In our case we are interested on saving the received messages in $HOME/files.

Next there is a rule, without condition, that only pipes the message to uudecode(1) for decodification. The original file will go to $HOME/files.

Conclusion

Hopefully after this brief introduction to procmail, it is clear that procmail is extremely versatile and it can help to manage your mail easy and conveniently. I recommend to experiment with the regular expressions and the rules, adapt them to your needs because procmail possibilities go well beyond what I have been able to discuss in this short introduction.


For more information:
  • Consult procmail's manual page
  • Read other articles by the same author:PGP under Linux.


© 1998 Angel Lopez
This website is mantained by Miguel A Sepulveda.