UNIX and Linux

Procmail Tutorial


elflord@panix.com

Tutorials

Useful information mostly written by me, the conspicuous exception being the bash manpage ...

Intro to Unix
UNIX command summary
grep tutorial powerful search tool
sed tutorial scripts to edit text files
Autofs in Linux automatically mounting removable media
procmail tutorial well known email filter
bash manpage the man page for the bash shell. Warning: this is long (~210k)

Contents


(1) The .forward file

Back to top First you need a ~/.forward file It goes like this:
"|IFS=' ' && exec /usr/local/bin/procmail || exit 75 #your_user_name"
Be warned that procmail might not be installed in /usr/local/bin. To find out where procmail is installed, type which procmail

(2) The .procmail directory

Make a directory ~/.procmail

(3) The .procmailrc File

(3) ~/.procmailrc
VERBOSE=off
MAILDIR=$HOME/mail # elm users might use $HOME/Mail instead
PMDIR=$HOME/.procmail
DEFAULT=/var/spool/mail/elflord
LOGFILE=$PMDIR/log
INCLUDERC=$PMDIR/general.rc
# INCLUDERC=$PMDIR/other.rc
# add as many INCLUDERC's as you like
# end of .procmailrc

(4) Syntax For INCLUDERC Files

Back to top
Now .procmail/general.rc should look something like this :

So the basic syntax is
:0
* case-insensitive-egrep-regex
* case-insensitive-egrep-regex
folder_name

:0 
* another-case-insensitive-egrep-regex
folder_name

A "regex" is a regular expression. See the appendix for details as to how an egrep regex works (and then play it by ear), or if you really want to nail it down, read the grep tutorial.

the regex's are anded (you can have as few as zero, or as many as you would dream of having). If you have zero, the action specified on the next line (usually save to folder) is automaticall taken. Make sure you put the "*" in front of each regex.

One thing the procmail man pages tell you to do is use From:.* as your expression to search for a sender. However, I have found that this does not work. I recommend using From.* instead.

(5) Examples

Back to top

Saving Mail to a Folder

Back to top Firstly, I know someone who's mail I want to keep on my ISP's account.
:0
* ^From.*bill@andromeda\.rutgers\.edu
bill

Saving Mail to My INBOX


Back to top I also want all of the mail from the domain pegasus.rutgers.edu to go to my inbox
:0
* ^From.*pegasus\.rutgers\.edu
$DEFAULT

Note that I need a \ before the "." since a "." matches any character, but I want to really match a "." , not just any character. In practice, the "." without the \ will probably work though , however it seems a little risky, and it is incorrect in a sense.

Another Example of Saving Mail to A Folder

Back to top
Here's a useful one. I get mail from lists and I don't want it cluttering my inbox. Better to put it in a folder. It goes like this: :0
* ^From.*redhat.*list.*list.*@
redhat-lists
This saves all of my mail from addresses containing Redhat in the user name to the redhat lists file

Unwanted Mail/Spam

Back to top

Unwanted Sources

Deleting mail from an unwanted source: ...

:0
* ^From.*big-jerk
/dev/null

Saving your SPAM (so you can report them !!!)

However, for spammers, I use a different approach: :0
* ^From.*spammer
spam
Then I can go through the folder when I am bored and report them to their ISPs. It's a great way to let of steam !!!

A Smarter Way of Detecting Spam

However, it's difficult to identify spammers since they often mail from fake addresses and they change accounts frequently (since their ISP's kick them out all the time). So you need something smarter to bust them. The best wy to do this is to kill all mail that satisfies the following
(a) Doesn't have your address(es) on the To or Cc part of the header
(b) It is not from a "trusted source" or a mailing list you subscribe to
Frankly, anyone who is not in either of the above categories had better put me on the To or Cc part of the header!
:0
* !(To|Cc).*my_address		# this is my account here
* !(To|Cc).*my_address_2	# I get mail forwarded from here
* !From.*my\.domain\.edu	# I trust the locals not to spam
* !From.*list.*@			# don't trash anything from mail lists
* !From.*good-buddy		# sometimes Bcc's me person mail to his sig-other
spam

Those Annoying Jokes! Arrggghhh, Save Me !!!

And something a little more advanced. You know that friend who keeps sending you those annoying jokes ? Try this one out:
:0
* ^From.*my-buddy
* ^Subject.*(Fwd|Forward|joke) /dev/null

Forwarding Mail

Back to top To forward mail, you use a "!" symbol in the action line: :0
* ^Subject.*something-or-other
! another@address.com

Doing More than One Thing With a Message

Back to top Suppose I want to forward the message and do something else with it. The way to do this is use the c flag in the first recipe, to tell procmail to keep going ...
:0
* ^Cc.*joe@somewhere.org
* ^Cc.*me
{
	:0 c
	$DEFAULT

	:0
	SOME_FOLDER
}

Sending Output to a Program

Back to top Here's an example that I use: I do not have CGI access, so I have my web forms mailed to me and have procmail send them to the right programs, so that they are processed correctly. What you might think of as "virtual CGI". What this does is spit the message to a file, then run a program on that file,

How the | works on the action line is that it starts the program following it, and sends the message to STDIN. In other words, it pipes to the program.

Subject:.*Form Posted
| cat&>$HOME/guestmail && \
$HOME/bin/guestscript $HOME/guestmail

(6) Putting it all Together

Back to top OK, so now , we are going to put it all together. We will use the following INCLUDE rc's: So ~/.procmailrc looks like this : VERBOSE=off
MAILDIR=$HOME/mail # elm users might use $HOME/Mail instead
PMDIR=$HOME/.procmail
DEFAULT=/var/mail/elflord
LOGFILE=$PMDIR/log
INCLUDERC=$PMDIR/default.rc
INCLUDERC=$PMDIR/general.rc
INCLUDERC=$PMDIR/lists.rc
INCLUDERC=$PMDIR/guestbook.rc
INCLUDERC=$PMDIR/spam.rc
# add as many INCLUDERC's as you like

Note that the order DOES matter, as the rules are applied in the order of that the rc files are included. It's a good idea to put your spam killer last, because the whole point of it is to trash mail you don't recognise, and any mail that gets grabbed by the other rules will be mail that you recognise in some sense.

Now all of these INCLUDERC files go in the ~/.procmail directory.


default.rc

looks something like this (anything we want to go straight to the inbox, no questions asked:
	
	:0
	* ^From.*pegasus\.rutgers\.edu
	$DEFAULT
	

general.rc



:0
* ^Cc.*joe@somewhere.org
* ^Cc.*me
{
	:0 c
	$DEFAULT

	:0
	SOME_FOLDER
}

:0
* ^Subject.*something-or-other
! another@address.com


lists.rc


:0
* ^From.*redhat.*list.*list.*@
redhat-lists

:0
* ^From.*owner@independence
independence-list

spam.rc


	  
:0
* ^From.*my-buddy
* ^Subject.*(Fwd|Forward|joke)
/dev/null

:0
* !(To|Cc).*my_address		# this is my account here
* !(To|Cc).*my_address_2	# I get mail forwarded from here
* !From.*my\.domain\.edu	# I trust the locals not to spam
* !From.*list.*@			# don't trash anything from mail lists
* !From.*good-buddy		# sometimes Bcc's me person mail to his sig-other
spam

:0     
* ^From.*big-jerk 
/dev/null


guestbook.rc


Subject:.*Form Posted
| cat&>$HOME/guestmail && \
$HOME/bin/guestscript $HOME/guestmail

Appendix: egrep regular expressions

Back to top
^ matches the beginning of the line
$ matches the end of the line
. Matches any single character
(character)* match arbitrarily many occurences of (character)
(character)? Match 0 or 1 instance of (character)
[abcdef] Match any character enclosed in [] (in this instance, a b c d e or f) ranges of characters such as [a-z] are permitted. The behaviour of this deserves more description. See the page on grep for more details about the syntax of lists.
[^abcdef] Match any character NOT enclosed in [ ] (in this instance, any character other than a b c d e or f)
(expression) Group operator. Contents of parentheses treated as one character with respect to * , + , ? and | concatenation operators
\n Backreference - matches the contents of the nth set of parentheses
expression1|expression2 Matches expression1 or expression 2.