On this page i will describe how to use procmail to sort your incoming emails into separate mailboxes, for use with your favorite Mail User Agent (MUA). Althoug some MUAs have builtin support for filters, there is good reasoning behind using procmail to support this task. Also, my favorite MUA, mutt, works very well with this system.
For more information on a complete system, also take a look at my Mutt Configuration and Extremely Short Fetchmail Guide.
First of all, we need to make sure that procmail is used for local delivery. If you are using postfix (like I am), this is accomplished by having the following line in /etc/postfix/main.cf:
Now, to configure procmail, the file .procmailrc should be created in your home directory. The first configuration options are as follows:
SHELL=/bin/sh PATH=/bin:/usr/bin MAILDIR=$HOME/Mail DEFAULT=$MAILDIR/Mailbox LOGFILE=$MAILDIR/procmail.log
This will make procmail deliver incoming mails in ~/Mail/. Next in .procmailrc comes the rules (in procmail-lingo called recipes) that are used to match each email. The format of a rule is:
:0 [flags] [ : [locallockfile] ] <zero or more conditions (one per line)> <exactly one action line>
In the most simple case, you should not need any flags.
Conditions consist of a * followed by a regular expression, matching the mail.
By default (eg. with no flags), procmail will try match the condition to the mail header, which is fine for most tasks. You can use the 'B'-flag to look in the body of the mail.
Last is the action line. This tells procmail what to do with any mail that matches the condition. The action line can have a special character as the first character, which will trigger special behavior of the action line. The ! character means that procmail will forward the message to all the following email-addresses, and the | character will cause the entire email to be piped into command, executed by SHELL. For more information on the special behavior, see the procmailrc (5) man page.
If the action line does not start with a special character, the action line will be treated as the name of a mailbox, which is exactly what we want to sort our mails. Our simple rule looks like this:
:0: * <regexp> <mailbox>
Where regexp is matched against the mail headers, and if a match is found, the mail will be delivered to mailbox. If no rule in .procmailrc matches, the mail will be delivered to the default mailbox, as specified above (eg. ~/Mail/Mailbox).
Now lets get a little more precise, with an example:
:0: * ^To.*sslug-announce@sslug\.dk sslug
This will cause all mail send to the sslug-announce mailing list to be saved in ~/Mail/sslug. Similairly, if you have email forwarded from other domains, you may use something like:
:0: * ^To.*@teamwww\.(com|net|dk) teamwww
Of course you can match on other mail headers, like the sender:
:0: * ^From.*(solit\.dk|cohaesio\.com) cohaesio
Which will cause mails from solit.dk and cohaesio.com to be delivered to the mailbox cohaesio.
Finally there is an example of matching the recipient or the subject:
:0: * ^To:.*advancemame-users@lists\.sourceforge\.net|^Subject:.*\[advancemame-users\] advancemame-users
Using procmail for email-notification was an idea I came up with, since some email-programs have a feature like this, and mutt only has a simple beep. With this scheme, email notification will start whenever a mail is delivered to your mailbox, even if your mail program (MUA) is not started. Another good reason is the ability to have separate sounds for various events.
Let's get right down to business. My first attempt to create an email notification system looked something like this:
# Play default sound on receive
:0 ic
| /usr/bin/play /usr/share/sounds/gnibbles/teleport.wavThis rule is put at the top of .procmailrc, and since it contains no action-lines, everything will match it. This causes the email to be piped to /usr/bin/play, but play ignores stdin, so the important part here is that play is executed. Notice the usage of the flags 'i' and 'c'. The i-flag is used to tell procmail not to complain about an early closed pipe. This is important since play will not read stdin. The c-flag means that the mail should continue traversing the rules, even if it matches this one. If the c-flag is not used, the mail will not be saved to any mailbox, so don't forget it.
If you only want notification for some emails, you can put rules for the ones you don't want notification for above this rule, and everything that goes below will be notified.
Although the above approach works, it has the annoying feature of playing the sound for every email received. This means that getting 10 emails at the same time will cause the system to play the sound 10 times, all messed up. After living with this annoying feature for a couple of months, I decided to do something about it. I made a little Perl-script to handle the problem (download mailnotify.pl here):
#!/usr/bin/perl # mailnotify.pl - play a sound (mail notification message), unless it # has already been played within the last minute $homedir=$ENV{"HOME"}||$ENV{"LOG_DIR"}||(getpwuid($<))[7]; if ($ARGV[0]) { $soundfile=$ARGV[0]; unless ($soundfile =~ /\//) { $soundfile=$homedir."/.mailnotify/sounds/".$soundfile; } } unless (-f $soundfile) { $soundfile="/usr/share/licq/sounds/icq/Message.wav"; } $lockfiledir=$homedir."/.mailnotify/lock/"; if ($ARGV[1]) { $lockfile=$lockfiledir.$ARGV[1]; } else { $lockfile=$lockfiledir."default"; } $seconds=60; $now=time(); ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)=stat $lockfile; `/bin/touch $lockfile`; if ($mtime<$now-$seconds) { `/usr/bin/play $soundfile`; # play sound }
To use this script, first save the file as ~/bin/mailnotify.pl. Now create the directories ~/.mailnotify, ~/.mailnotify/sounds and ~/.mailnotify/lock. Put your favourite wav-sound in ~/.mailnotify/sounds/, and test it:
cd ~/bin/ ./mailnotify.pl test.wav
(NOTE: You should of course change test.wav to whatever your soundfile is called).
If everything works as expected, you should hear the sound. If you try to run the program again immediately, nothing should happen, since the script checks for the file ~/.mailnotify/lock/default, and if it is less than 60 seconds old, it will skip playing the sound.
Now, replace the rule in .procmailrc with the following:
# Play default sound on receive
:0 ic
| $HOME/bin/mailnotify.pl transfer.wav default &>/dev/nullYou can also make more advanced rules, to have special sounds for some mailboxes:
:0:
* ^(To|Cc).*webmaster@
{
:0 ic
| $HOME/bin/mailnotify.pl violin.wav web &>/dev/null
:0:
web
}As you can see, this rule matches email send to webmaster. Any mail matching, will trigger the mail notification using the sound violin.wav and the lock-file web. The mail will then be delivered to the mailbox named web.