=head1 NAME proctut1 - Anatomy of a Procmail Recipe, Part I =head1 SYNOPSIS This tutorial will discuss the three core components of a procmail recipe and how they are used. =head1 DESCRIPTION As we discussed in L, procmail uses I to scan and decide what to do with mail. We looked at a simple recipe: :0: * ^From:.*joe@schmoe\.org joe We mentioned that any mail passing through this recipe will be scanned for the email address 'joe@schmoe.org' in the 'From:' header (i.e., the message will be from joe@schmoe.org). Any mail matching this criterion will be delivered to a file called F. What's this first line ':0:' business? To be brief, all procmail recipes have three components: B, B, and an B. To be precise, only flags and actions are necessary (conditions are optional). The procmailrc(5) manpage states: A line starting with ':' marks the beginning of a recipe. It has the following format: :0 [flags] [ : [locallockfile] ] But we prefer brevity over rigorous technical detailsL<[1]|proctut1.pod/Note_1>. (That's a little humor, folks.) We will be as accurate as we can for an introductory tutorial, but we may I certain information until later tutorials. We will attempt to note those absences when they appear and flesh them out in later tutorials. =head1 Flags You've seen this in all procmail recipes: :0 What does it mean? Simply put, the procmail program needs to look for I in your recipe file to distinguish between recipes. B<:0> is the official start of a procmail recipeL<[2]|proctut1.pod/Note_2>. All of your recipes should begin with (at least) B<:0>. =head2 Header and Body After B<:0> it gets tricky. Here is where you decide, in general, I of the mail will be scannedL<[3]|proctut1.pod/Note_3>. For example, procmail distinguishes between the email I
and the email I. Knowing this distinction is important. The I
is everything from the very first line beginning with 'From ' (without a colon) down to the first empty line. Here is a very simple email message: From scott@perlcode.org Fri Aug 22 22:41:40 2003 Received: from localhost (localhost) by perlcode.org (8.12.9/8.12.9) id h7N4emRF047843; Fri, 22 Aug 2003 22:40:48 -0600 (MDT) Date: Fri, 22 Aug 2003 22:40:47 -0600 From: Scott Wiersdorf To: Scott Wiersdorf Subject: test Hi! -- Scott Wiersdorf The header consists of the top 'From 'L<[4]|proctut1.pod/Note_4> lineL<[5]|proctut1.pod/Note_5> all the way down to the line beginning 'Subject:' The body of the email message is the line beginning 'Hi!' down to the signature 'Scott Wiersdorf' (yes, your author is rather vain). =head2 More about flags By default, procmail scans only the I of the email message. This means that if you want your recipe to scan the body of the message, you'll need to use the B flag: :0B: * Hi! /var/mail/scott You may wish to put spaces after B<:0>, like this: :0 B: * Hi! /var/mail/scott That's a little easier to read. Now we're scanning the I of the message (not the header). What if we want to scan both the body and the header? :0 HB: * Hi! /var/mail/scott Now any messages that have the word 'Hi!' in I the headers (for example, the Subject line) I the body of the message will match this recipe. There are many other flags that we will discuss in other tutorials. See L for details. =head1 Conditions Now that we've covered what the flags do and how to use them, we need to move on to the meat of a procmail recipe. Procmail I are where you do all of your fancy footwork to make your recipes match just the messages you want (not too much, not too little). Condition lines are optional, as we have previously seenL<[1]|proctut1.pod/Note_1>. A recipe that has no condition lines will match all email messages (you can think of having no conditions as being "unconditional" and the action of the recipe will always triggerL<[6]|proctut1.pod/Note_6>). Most useful recipes have conditions, however, and all conditions begin with an asterisk: B<*>. Here is an example of a single condition: * ^Subject: In the context of a recipe, it might appear like this: :0 * ^Subject: delete me /dev/null If a recipe has multiple condition lines, B of the conditions must be true for the recipe to match. If any one of the conditions is not true, procmail skips the remaining conditions and moves to the next recipe. For example: :0 * ^From: Unwanted Spammer * ^Subject: delete me /dev/null If we receive an email with the phrase "delete me" as the subject, the first recipe above would dump the email message to F (deleting it forever). The second recipe, however, also requires that the email message be sent from "Unwanted Spammer". If the message does not meet I of these requirements, the recipe will not match and procmail will move on to the next recipe (if there is one--if not, the mail will be delivered to its default mailbox as discussed in L). More about conditions in L and in later tutorials. =head1 Action Every procmail recipe has exactly one action lineL<[7]|proctut1.pod/Note_7>. Most often, the action is the name of a file to deliver the mail to if all the conditions are met: :0: * ^From: Joe Schmoe $HOME/Mail/joe The first line after the conditions (remember, all conditions start with a '*') is the I line. This action line will deliver mail from Joe Schmoe to the F mailbox in my (the recipient's) home directory. We've seen other examples where mail was delivered to F, the bottomless pit of Unix. There are a few other things you can do with an action line. For example, you can redirect an incoming email to someone else by inserting an exclamation point (B) at the start of the action line: :0 ! bob@perlcode.org The exclamation point tells procmail that we are going to be forwarding this email message to the email address specified next. Any email I get will be sent along to Bob instead. You can get this same effect with sendmail's virtusertable feature. However, one thing you can't get with the virtusertable feature is scanning: :0 * ^Subject: Send this to Bob ! bob@perlcode.org Now I only forward selected messages to Bob. That's harder to do with just sendmail. Many more examples of action lines, including blocks, pipes, and filters can be found in L and L and later tutorials. =head1 SUMMARY A procmail recipe is comprised of three basic components: a B line (which always begin with B<:0>), zero or more B lines (which always begin with B<*>), and an action line. =head1 NOTES =over 4 =item Note 1 Because conditions are optional (zero or more), a minimal recipe could be: :0 /dev/null which will dump all email into F. You could also have: :0: /var/mail/foo which will dump all email into F. Notice the trailing colon on the flag line. This tells procmail that it should I /var/mail/foo> so that other email messages that may be coming in don't try to write to the file at the same time (causing mailbox corruption; imagine one message interleaving with another message!). F is a device and does not need a lock, since it can accept concurrent writes without any corruption at all. That's a little more humor, folks. =item Note 2 Historically, the zero could be any digit, but since 1993 or so, the digit is almost always zero. The digit once referred to the number of conditions in the recipe, but the syntax has since solidified and obsoleted the necessity of counting conditions. Thank goodness! =item Note 3 There are actually built-in procmail variables that you can use in the conditions themselves to scan different parts of the email (e.g., body and header). These are introduced in L and in later tutorials. =item Note 4 Notice there are two lines that begin with 'From'; the first one is inserted by your MTA (e.g., sendmail, qmail, postfix, etc.) to help it distinguish between messages (i.e., 'From ' is the official start of a new message). It contains what is called the I. This is the email address that sendmail received when the sender's email client spoke SMTP to the receiving server (well, that's an oversimplification, but it's generally true). The second 'From' header has a colon in it; this is part of the email message that the sender actually inserted. Rather, the sender's email client (e.g., Eudora, pine, mutt, Netscape Mail, etc.) inserted it for the sender, but the sender specified them as part of their email client settings. =item Note 5 'From ' is the de-facto way to refer to the MTA-added mbox format line. It is often different than I, which the sender's email client sets. 'From ' is set by the receiving server from the envelope sender. This is getting way too technical, but suffice it to say that these headers are two different things; the 'From ' header is how nearly all mail readers separate one email message from another in mbox format. Lines in email messages that begin with 'From ' are often commented with '>' by the MTA so they don't cause problems. =item Note 6 We recall from L that after the first matching and delivering recipe is found, procmail immediately stops processing this email message. So if you have two recipes: :0: /var/mail/joe :0: /var/mail/bob only the first one will ever get triggered because it matches all emails unconditionally and procmail stops processing. =item Note 7 Actually, it can also be a I, which is one or more recipes. A block begins and ends with curly braces ( '{ }' ) and may span multiple lines. For example, to avoid scanning the body (which can be very inefficient, depending on what you're looking for and how large the email message is) of an email message unless you absolutely have to, you can look for tell-tale headers first: :0 * ^Subject: scan the body { :0 B * delete this message! /dev/null } =back =head1 PREVIOUS L =head1 NEXT L =head1 SEE ALSO procmail(1), procmailrc(5), procmailex(5) =head1 AUTHOR Scott Wiersdorf =head1 COPYRIGHT Copyright (c) 2003 Scott Wiersdorf. All rights reserved. =head1 REVISION $Id: proctut1.pod,v 1.7 2003/09/17 13:16:08 deep Exp $