Using Procmail

Table of Contents

1. Concepts

1.1. What is Procmail?

Procmail is a utility that allows you to filter your incoming mail according
to pretty much any parameters you choose. In its most simple usage, it filters
based on pattern matching. A procmail "recipe" is basically a set of regular
expressions that should or should not be matched in an incoming email, along
with a folder to place the email into if it is matched.

Some people (like me) have multiple email addresses that are all handled by
the same server, and they want to keep the emails separate from each other for
one reason or another. Procmail will allow you to filter into different
inboxes based on which address an email was sent to.

1.2. What are Procmail’s capabilities?

Procmail can filter mail using several methods:

  • Pattern matching against a fixed regular expression
  • Negating a pattern match
  • Piping the email to a command and taking its exit status

    (If the command exits with a failure exit code, the recipe conditions are
    not satisfied)
  • Checking the length of the email

Procmail can take one of three actions with the text of an email once it has
determined the email to match the recipe specification:

  • Append the text to a file
  • Feed the text to the standard input of another program
  • Forward the email to another address
  • Process the text of the email using an external program

    The modified text will now be considered as if it were the original email,
    and Procmail will continue to test this text against the rest of the
    recipies.

The first three rules are delivering recipies, whereas the latter is
a non-delivering recipe. Non-delivering recipies are useful for
modifying the content of an incoming email before it’s delivered.

2. Basic Configuration

2.1. Setting up your .procmailrc

The file that will contain all your procmail recipes is
~/.procmailrc. Most systems are already configured with sendmail
or another MTA that is procmail-aware, but just to make sure your mail
actually gets filtered through procmail rather than directly delivered, you
must place the following line in your ~/.forward file:

|/usr/bin/procmail

That should be all you have in the file. Any special forwarding you want to do
can be done from within the procmailrc file. Of course, if procmail doesn’t
live in /usr/bin on your system, correct the path appropriately.

2.2. Global procmailrc settings

There are some variables that can be set from within the .procmailrc, whose
values determine specific behavior of procmail while delivering your mail.
Here is a list of the more commonly used ones. Don’t get overwhelmed. Most of
these have reasonable default values:

MAILDIR
Current directory while procmail is executing (that means
that all paths are relative to $MAILDIR).

DEFAULT
Default mailbox file (if not told otherwise, procmail will
dump mail in this mailbox). Procmail will automatically use
$DEFAULT$LOCKEXT as lockfile prior to writing to this mailbox. You do
not need to set this variable, since it already points to the standard
system mailbox.

LOG
Anything assigned to this variable will be appended to $LOGFILE.
Useful for debugging purposes.

ORGMAIL
Usually the system mailbox (ORiGinal MAILbox). If, for some
obscure reason (like `filesystem full’) the mail could not be delivered,
then this mailbox will be the last resort. If procmail fails to save the
mail in here (deep, deep trouble :-), then the mail will bounce back to
the sender.

TRAP
When procmail terminates it will execute the contents of this
variable. A copy of the mail can be read from stdin. Any output
produced by this command will be appended to $LOGFILE. Possible uses
for TRAP are: removal of temporary files, logging customised abstracts,
etc.

INCLUDERC
Names an rcfile (relative to the current directory) which
will be included here as if it were part of the current rcfile.
Nesting is permitted and only limited by systems resources (memory and
file descriptors). As no checking is done on the permissions or ownership
of the rcfile, users of INCLUDERC should make sure that only trusted
users have write access to the included rcfile or the directory it is in.

DROPPRIVS
If set to `yes’ procmail will drop all privileges it might
have had (suid or sgid). This is only useful if you want to guarantee
that the bottom half of the /etc/procmailrc file is executed on behalf of
the recipient.

See the procmailrc manpage for the default values assigned to these variables.

2.3. The format of a procmail recipe

A procmail recipe takes the following format:

:0 [flags] [ : [locallockfile] ]
* condition-regex1
* condition-regex2
exactly one action line

There can be 0 or more condition regexes, each preceeded by a *. The
conditions are ANDed, so if a message does not match them all, it will not
match the recipe.

By the way, the 0 following the : that marks the start of a
new rule has no significance. In older versions of procmail, the digit was
used, but due to changes in the functionality of procmail, it has become
obsolete. Therefore, we always use 0.

The condition REs can be preceeded by a ! (negate the RE), ?

(Use the exit code of the specified program), , or >
(Ensure that the message size is less than or greater than the number of bytes
specified as the expression).

2.4. Recipe flags

There are several flags that can be placed after the :0 that affect the
behavior of the recipe. When no flags are specified, a default flag set of
"Hhb" is assumed. Any combination of the following flags can be specified, and
the new flag set will override the default flag set. Here is a list of
commonly used flags:

H
Egrep the header against the specified REs (default)
B
Egrep the body against the specified REs
D
Be case sensitive (default is case insensitive)
h
Feed the mail header to the action (default)
b
Feed the mail body to the action (default)
f
Filter program will modify the mail’s text
c
Send mail to this rule, but continue through procmailrc

The last option, c, is used on rules that do things such as send a response to
the email, or send a carbon copy of the email to another address, for example.

2.5. Types of patterns to look for

To filter a message by sender, use a rule such as:

* ^From .*sender@somedomain

Note that there are two From fields in a typical email header. The
one with no colon following it is where the mail really came from,
wheras the one with the colon after it is the address that the sender claims
to be sending from.

To filter a message by recipient, use a rule such as:

* ^To: .*your@address

Subjects also have some good information you may want to use to filter. See my
example procmailrc file for different ways I egrep the Subject.

3. More advanced recipe tricks

3.1. Multi-tiered recipies

If you have one recipe that is a base requirement for many other recipes, you
can nest them. Say you have two email addresses and you want to filter
differently for each:

:0
* To:.*joe.blow@somecompany.com
{
:0
* From:.*boss@somecompany.com

urgent-mail

:0
INBOX
}

:0
* To:.*jblow@home.com
{
:0
* From:.*boss@somecompany.com

/dev/null

:0
INBOX
}

3.2. Formail

formail is a program that takes mail headers on standard input and
modifies them in some way and prints them back onto standard output. This is
useful for auto responders that respond using the same subject as the email
you were initially sent. See my procmailrc below for an example.

4. Some Examples

4.1. Generic Examples

The best place to look for examples is the procmailex(1) manpage. It has a
much more complete set of examples than I can put in this document.

4.2. My procmailrc

Here is my procmailrc. Mail to my runslinux.net address comes into the same
box as my jehsom.com address, and I’d like to treat them differently. Sorry
the comments are sparse and the file isn’t cleaned up as much as I would have
liked, but I’m short on time, so it’s all I can do:

Download the sample procmailrc (Text format, 2.9 KB).

# Moshe's procmailrc
# This procmailrc processes email coming in on several email addresses. Mail
# for jehsom@jehsom.com should be filed separately from all other mail.

MAILDIR=$HOME/var/mail
LOGFILE=$HOME/.procmail.log
VERBOSE=on

# trash advertisements
:0
* ^Subject: \[?ADV?[] ]?:?\b
/dev/null

# Killfile billie pendleton parker
:0
* ^From: .*(billiee.*pendleton.*parker)
* ^To: .*(apo|bp4@prism.gatech.edu)
/dev/null

# Killfile ruffside
:0
* ^From:.*ruffside
/dev/null

# Trash lugatgt listproc stupidness
:0 HB
* signoff lugatgt-list
/dev/null

# Remove any duplicate emails (mailing list Cc:'s and stuff)
:0 Wh : $MAILDIR/.idcache.lock
| formail -D 1000 $MAILDIR/.idcache

# Tack on a header to togetherweb mail
:0 hbf
* ^(To|Cc): .*@[^ ]*togetherweb.com
| $HOME/bin/addtotop " *** NOTICE: This mail was sent to togetherweb.com ***\n"

# Remove yahoo advertisements
:0 hbf
* ^From:.*yahoo
| sed '/^_\{50\}$/,$ d'

# Fix incorrect sigdashes
:0 Bfwhb
* ^--$
| sed 's/^--$/-- /'

# Remove cyberbuzz ad
:0 hbf
* ^Message-ID:.*cyberbuzz
| sed '/^-\{49\}$/,$ d'

# Send autoresponse to @togetherweb mail, saying I've changed my address.
:0 chw
* !^FROM_DAEMON
* !^X-Loop: .*moshe@runslinux\.net
* ^(To|Cc): .*(moshe|jehsom)@togetherweb\.com
* !^From: .*(moshe|jehsom|togetherweb\.com)
| { formail -r -I "From: Moshe Jacobson moshe@runslinux.net" \

-a "Date: `date -R`" \
-A "X-Loop: moshe@runslinux.net"; \
cat $HOME/.autoreply.togetherweb; \
cat $HOME/.sig.moshe; \

} | sendmail -oi -t

:0
* ^(To|Cc): .*jehsom
{
:0 BH
* !^FROM_DAEMON
* !^X-Loop: .*jehsom@jehsom.com
* zipscript|debug( mode|ging)|glftpd|\b0day\b|file_id.diz|\brels\b|racers

{
:0 c
* !^From: .*maestro
! maestro@dv8.org

:0 :
jehsom/INBOX-zipscript

}

:0 BH
* !^FROM_DAEMON
* !^X-Loop: jehsom@jehsom\.com
* \b(ftp.(account|server)|serial|vcd|iso|bin.*cue|irc|key|cd[123])\b
jehsom/INBOX-scene

:0 :
jehsom/INBOX
}

# Vacation Autoresponder for moshe@*
#:0 chw
#* ^(To|Cc):.*moshe
#* !^X-Loop: moshe@runslinux\.net
#| { formail -r -I "From: Moshe Jacobson moshe@runslinux.net" \
#-A "X-Loop: moshe@runslinux.net" \
#-a "Date: `date -R`"; \
#cat $HOME/.autoreply.vacation
#cat $HOME/.sig.moshe
#} | sendmail -oi -t

# Mail from my website
:0 hb :
* ^X-Mail-Gateway:.*Doug
moshe/INBOX-web

# Put list mailings in a separate folder
:0 hb :
* ^Subject: (Re: )?\[[^]]*\] .*
* !^(To|Cc): .*(jehsom|moshe)
moshe/INBOX-lists

# Catch mail from root/daemons and put it in a separate folder
:0 hb :
* ^From:.*\(MAILER-DAEMON|root|bugzilla-daemon)@
moshe/INBOX-daemons

# Mail from alert scripts
:0 :
* ^To:.* alert@togetherweb.com
moshe/INBOX-daemons

# Orchstra and list/chat lists
:0 hb :
* ^(To|Cc): .*(orchestra|-(list|chat))@
moshe/INBOX-lists

:0 :
moshe/INBOX

5. Resources

  • man pages: procmail(1), procmailrc(5), procmailex(5), procmailsc(5)

    The man pages for (respectively) procmail itself, the procmailrc file and
    its format, a lot of good examples of procmail recipies, and procmail
    scoring. procmailrc(5) and procmailex(5) should provide pretty much all
    the information you’ll need on how to use procmail. For some really
    advanced scary stuff on mail scoring using procmail (not covered in this
    document), see procmailsc(5).
  • http://www.procmail.org/
    This is the official Procmail website.
  • http://www.iki.fi/era/procmail/mini-faq.html

    This is a very well-written FAQ on Procmail. It should answer the most
    common questions concerning problems you may run into while using
    Procmail.

  • http://www.spambouncer.org/
    The SpamBouncer is a set of procmail instructions that search the headers
    and text of your incoming email to see if it meets one or more of a list
    of conditions for probable spam. It will then either tag the suspected
    spam and return it to your main incoming mailbox, tag the suspected spam,
    delete spam from known spam sources, and file suspected spam in a separate
    folder, send a simulated MAILER-DAEMON daemon "bounce", complain to the
    "upstream providers" of known spammers or spam sites/domains, etc.
  • http://junkfilter.zer0.org/
    junkfilter is a procmail -based filter system for electronic mail. It
    filters sex spam, MLM schemes, and all other types of unsolicited
    commercial e-mail (UCE).
  • http://ceti.pl/~kravietz/spamrc/

    Spamrc is a set of Procmail scoring rules that try to eliminate spam from
    your incoming email based on scoring. Spamrc checks a number of commong
    spam signatures, giving the email some points for each matching rule. The
    points are added and the result is used to decide the probability that the
    message is spam. The scheme works quite well, though it has some false
    positives and misses.