1Please read the README file in this directory first.
2.ex
3.Id $Id: procmailex.man,v 1.54 2001/08/04 06:08:20 guenther Exp $
4.TH PROCMAILEX 5 \*(Dt BuGless
5.na
6.SH NAME
7procmailex \- procmail rcfile examples
8.SH SYNOPSIS
9.B @PROCMAILRC@ examples
10.ad
11.SH DESCRIPTION
12For a description of the rcfile format see
13.BR procmailrc (5).
14.PP
15The weighted scoring technique is described in detail in the
16.BR procmailsc (5)
17man page.
18.PP
19This man page shows several example recipes.  For examples of complete rcfiles
20you can check the NOTES section in
21.BR procmail (1),
22or look at the example rcfiles part of the procmail source distribution
23(procmail*/examples/?procmailrc).
24.SH EXAMPLES
25Sort out all mail coming from the scuba-dive mailing list into the mailfolder
26scubafile (uses the locallockfile scubafile.lock).
27.Sx 3
28:0:
29* ^TOscuba
30scubafile
31.Ex
32Forward all mail from peter about compilers to william (and keep a copy
33of it here in petcompil).
34.Sx 10
35:0
36* ^From.*peter
37* ^Subject:.*compilers
38{
39   :0 @CONTINUE@
40   ! william@somewhere.edu
41
42   :0
43   petcompil
44}
45.Ex
46An equivalent solution that accomplishes the same:
47.Sx 7
48:0 @CONTINUE@
49* ^From.*peter
50* ^Subject:.*compilers
51! william@somewhere.edu
52
53   :0 @ALSO_NEXT_RECIPE@
54   petcompil
55.Ex
56An equivalent, but slightly slower solution that accomplishes the same:
57.Sx 9
58:0 @CONTINUE@
59* ^From.*peter
60* ^Subject:.*compilers
61! william@somewhere.edu
62
63:0
64* ^From.*peter
65* ^Subject:.*compilers
66petcompil
67.Ex
68If you are fairly new to procmail and plan to experiment a little bit
69it often helps to have a
70.I safety net
71of some sort.  Inserting the following two recipes above all other recipes
72will make sure that of all arriving mail always the last 32 messages will
73be preserved.  In order for it to work as intended, you have to create
74a directory named `backup' in $MAILDIR prior to inserting these two recipes.
75.Sx 5
76:0 @CONTINUE@
77backup
78
79:0 @IGNORE_WRITERR@@CONTINUE@
80| cd backup && rm \-f dummy `ls \-t msg.* | sed \-e 1,32d`
81.Ex
82If your system doesn't generate or generates incorrect leading `@FROM@'
83lines on every mail, you can fix this by calling up procmail with
84the \-@FROMWHOPT@@REFRESH_TIME@ option.  To fix the same problem by
85different means, you could have inserted the following two
86recipes above all other recipes in your rcfile.  They will filter the header
87of any mail through formail which will strip any leading `@FROM@', and
88automatically regenerates it subsequently.
89.Sx 2
90:0 @FILTER@@PASS_HEAD@@WAIT_EXIT@
91| formail \-@FM_DEL_INSERT@ "@FROM@" \-@FM_ADD_IFNOT@ "@FROM@"
92.Ex
93Add the headers of all messages that didn't come from the postmaster
94to your private header collection (for
95statistics or mail debugging); and use the lockfile `headc.lock'.  In order
96to make sure the lockfile is not removed until the pipe has finished,
97you have to specify option `@WAIT_EXIT@'; otherwise the lockfile would be
98removed as soon as the pipe has accepted the mail.
99.Sx 3
100:0 @PASS_HEAD@@WAIT_EXIT@@CONTINUE@:
101* !@FROMMkey@
102| uncompress headc.Z; cat >>headc; compress headc
103.Ex
104Or, if you would use the more efficient gzip instead of compress:
105.Sx 3
106:0 @PASS_HEAD@@WAIT_EXIT@@CONTINUE@:
107* !@FROMMkey@
108| gzip >>headc.gz
109.Ex
110Forward all mails shorter than 1000 bytes to my home address (no lockfile
111needed on this recipe).
112.Sx 3
113:0
114* < 1000
115! myname@home
116.Ex
117Split up incoming digests from the surfing mailing list into their individual
118messages, and store them into surfing, using surfing.lock as the locallockfile.
119.Sx 3
120:0:
121* ^Subject:.*surfing.*Digest
122| formail @FM_SKIP@1 \-@FM_DIGEST@@FM_SPLIT@ >>surfing
123.Ex
124Store everything coming from the postmaster or mailer-daemon (like bounced
125mail) into the file postm, using postm.lock as the locallockfile.
126.Sx 3
127:0:
128* @FROMMkey@
129postm
130.Ex
131A simple autoreply recipe.  It makes sure that neither mail from any daemon
132(like bouncing mail or mail from mailing-lists), nor autoreplies coming from
133yourself will be autoreplied to.  If this precaution would not be taken,
134disaster could result (`ringing' mail).  In order for this recipe to autoreply
135to all the incoming mail, you should of course insert it before all other
136recipes in your rcfile.  However, it is advisable to put it
137.I after
138any recipes that process the mails from subscribed mailinglists; it generally
139is not a good idea to generate autoreplies to mailinglists (yes, the
140!@FROMDkey@ regexp should already catch those, but if the mailinglist
141doesn't follow accepted conventions, this might
142.I not
143be
144.IR enough ).
145.Sx 6
146:0 @PASS_HEAD@ @CONTINUE@
147* !@FROMDkey@
148* !^X-Loop: your@own.mail.address
149| (formail \-@FM_REPLY@ \-@FM_DEL_INSERT@"Precedence: junk" \e
150    \-@FM_ADD_ALWAYS@"X-Loop: your@own.mail.address" ; \e
151   echo "Mail received.") | $SENDMAIL \-t
152.Ex
153A more complicated autoreply recipe that implements the functional equivalent
154of the well known
155.BR vacation (1)
156program.  This recipe is based on the same principles as the last one (prevent
157`ringing' mail).  In addition to that however, it maintains a vacation database
158by extracting the name of the sender and inserting it in the vacation.cache
159file if the name was new (the vacation.cache file is maintained by formail
160which will make sure that it always contains the most recent names, the size
161of the file is limited to a maximum of approximately 8192 bytes).  If the name
162was new, an autoreply will be sent.
163.PP
164As you can see, the following recipe has comments
165.B between
166the conditions.
167This is allowed.  Do
168.B not
169put comments on the same line as a condition though.
170.Sx 18
171SHELL=/bin/sh    # for other shells, this might need adjustment
172
173:0 @WAIT_EXIT_QUIET@@PASS_HEAD@@CONTINUE@: vacation.lock
174 # Perform a quick check to see if the mail was addressed to us
175* $^To:.*\e<$\eLOGNAME\e>
176 # Don't reply to daemons and mailinglists
177* !@FROMDkey@
178 # Mail loops are evil
179* !^X-Loop: your@own.mail.address
180| formail \-@FM_REPLY@@FM_DUPLICATE@ 8192 vacation.cache
181
182  :0 @ERROR_DO@@PASS_HEAD@@CONTINUE@         # if the name was not in the cache
183  | (formail \-@FM_REPLY@@FM_DEL_INSERT@"Precedence: junk" \e
184       \-@FM_ADD_ALWAYS@"X-Loop: your@own.mail.address" ; \e
185     echo "I received your mail,"; \e
186     echo "but I won't be back until Monday."; \e
187     echo "-- "; cat $HOME/.signature \e
188    ) | $SENDMAIL \-oi \-t
189.Ex
190Store all messages concerning TeX in separate, unique filenames, in a directory
191named texmail (this directory has to exist); there is no need to use lockfiles
192in this case, so we won't.
193.Sx 3
194:0
195* (^TO|^Subject:.*)TeX[^t]
196texmail
197.Ex
198The same as above, except now we store the mails in numbered files (MH mail
199folder).
200.Sx 3
201:0
202* (^TO|^Subject:.*)TeX[^t]
203texmail/.
204.Ex
205Or you could file the mail in several directory folders at the same time.
206The following recipe will deliver the mail to two MH-folders and one
207directory folder.  It is actually only one file with two extra hardlinks.
208.Sx 3
209:0
210* (^TO|^Subject:.*)TeX[^t]
211texmail/. wordprocessing dtp/.
212.Ex
213Store all the messages about meetings in a folder that is in a directory
214that changes every month.  E.g. if it were January 1994, the folder
215would have the name `94-01/meeting' and the locallockfile would be
216`94-01/meeting.lock'.
217.Sx 3
218:0:
219* meeting
220`date +%y-%m`/meeting
221.Ex
222The same as above, but, if the `94-01' directory wouldn't have existed, it
223is created automatically:
224.Sx 9
225MONTHFOLDER=`date +%y-%m`
226
227:0 @WAIT_EXIT_QUIET@@IGNORE_WRITERR@@CONTINUE@
228* ? test ! \-d $MONTHFOLDER
229| mkdir $MONTHFOLDER
230
231:0:
232* meeting
233${MONTHFOLDER}/meeting
234.Ex
235The same as above, but now by slightly different means:
236.Sx 6
237MONTHFOLDER=`date +%y-%m`
238DUMMY=`test \-d $MONTHFOLDER || mkdir $MONTHFOLDER`
239
240:0:
241* meeting
242${MONTHFOLDER}/meeting
243.Ex
244If you are subscribed to several mailinglists and people cross-post to
245some of them, you usually receive several duplicate mails (one from every
246list).  The following simple recipe eliminates duplicate mails.  It tells
247formail to keep an 8KB cache file in which it will store the Message-IDs of
248the most recent mails you received.  Since Message-IDs are guaranteed to
249be unique for every new mail, they are ideally suited to weed out duplicate
250mails.  Simply put the following recipe at the top of your rcfile, and
251no duplicate mail will get past it.
252.Sx 2
253:0 @WAIT_EXIT_QUIET@@PASS_HEAD@: msgid.lock
254| formail \-@FM_DUPLICATE@ 8192 msgid.cache
255.Ex
256.B Beware
257if you have delivery problems in recipes below this one and procmail tries
258to requeue the mail, then on the next queue run, this mail will be considered
259a duplicate and will be thrown away.  For those not quite so confident in
260their own scripting capabilities, you can use the following recipe instead.
261It puts duplicates in a separate folder instead of throwing them away.
262It is up to you to periodically empty the folder of course.
263.Sx 5
264:0 @WAIT_EXIT_QUIET@@PASS_HEAD@@CONTINUE@: msgid.lock
265| formail \-@FM_DUPLICATE@ 8192 msgid.cache
266
267:0 @ALSO_N_IF_SUCC@:
268duplicates
269.Ex
270Procmail can deliver to MH folders directly, but, it does not update
271the unseen sequences the real MH manages.  If you want procmail to
272update those as well, use a recipe like the following which will file
273everything that contains the word spam in the body of the mail into an
274MH folder called spamfold.  Note the local lockfile, which is needed
275because MH programs do not lock the sequences file.  Asynchronous
276invocations of MH programs that change the sequences file may therefore
277corrupt it or silently lose changes.  Unfortunately, the lockfile
278doesn't completely solve the problem as rcvstore could be invoked while
279`show' or `mark' or some other MH program is running.  This problem is
280expected to be fixed in some future version of MH, but until then,
281you'll have to balance the risk of lost or corrupt sequences against
282the benefits of the unseen sequence.
283.Sx 3
284:0 :spamfold/$LOCKEXT
285* @BODY_GREP@ ?? spam
286| rcvstore +spamfold
287.Ex
288When delivering to emacs folders (i.e., mailfolders managed by any emacs
289mail package, e.g., RMAIL or VM) directly, you should use emacs-compatible
290lockfiles.  The emacs mailers are a bit braindamaged in that respect, they get
291very upset if someone delivers to mailfolders which they already have in their
292internal buffers.  The following recipe assumes that $HOME equals /home/john.
293.Sx 5
294MAILDIR=Mail
295
296:0:/usr/local/lib/emacs/lock/!home!john!Mail!mailbox
297* ^Subject:.*whatever
298mailbox
299.Ex
300Alternatively, you can have procmail deliver into its own set of mailboxes,
301which you then periodically empty and copy over to your emacs files using
302.BR movemail .
303Movemail uses mailbox.lock local lockfiles per mailbox.  This actually is
304the preferred mode of operation in conjunction with procmail.
305.PP
306To extract certain headers from a mail and put them into environment
307variables you can use any of the following constructs:
308.Sx 5
309SUBJECT=`formail \-@FM_EXTRACT@Subject:`    # regular field
310FROM=`formail \-@FM_REPLY@@FM_TRUST@ \-@FM_EXTRACT@To:`        # special case
311
312:0 @PASS_HEAD@                            # alternate method
313KEYWORDS=| formail \-@FM_EXTRACT@Keywords:
314.Ex
315If you are using temporary files in a procmailrc file, and want to make
316sure that they are removed just before procmail exits, you could use
317something along the lines of:
318.Sx 2
319TEMPORARY=$HOME/tmp/pmail.$$
320TRAP="/bin/rm \-f $TEMPORARY"
321.Ex
322The TRAP keyword can also be used to change the exitcode of procmail.
323I.e. if you want procmail to return an exitcode of `1' instead of its
324regular exitcodes, you could use:
325.Sx 3
326EXITCODE=""
327TRAP="exit 1;"   # The trailing semi-colon is important
328                 # since exit is not a standalone program
329.Ex
330Or, if the exitcode does not need to depend on the programs run from
331the TRAP, you can use a mere:
332.Sx 1
333EXITCODE=1
334.Ex
335The following recipe prints every incoming mail that looks like a postscript
336file.
337.Sx 3
338:0 @BODY_GREP@@PASS_BODY@
339* ^^%!
340| lpr
341.Ex
342The following recipe does the same, but is a bit more selective.  It only
343prints the postscript file if it comes from the print-server.  The first
344condition matches only if it is found in the header.  The second condition
345only matches at the start of the body.
346.Sx 4
347:0 @PASS_BODY@
348* ^From[ :].*print-server
349* B ?? ^^%!
350| lpr
351.Ex
352The same as above, but now by slightly different means:
353.Sx 7
354:0
355* ^From[ :].*print-server
356{
357  :0 @BODY_GREP@ @PASS_BODY@
358  * ^^%!
359  | lpr
360}
361.Ex
362Likewise:
363.Sx 4
364:0 @HEAD_GREP@@BODY_GREP@ @PASS_BODY@
365* ^^(.+$)*From[ :].*print-server
366* ^^(.+$)*^%!
367| lpr
368.Ex
369Suppose you have two accounts, you use both accounts regularly, but they are
370in very distinct places (i.e., you can only read mail that arrived at either one
371of the accounts).  You would like to forward mail arriving at account one to
372account two, and the other way around.  The first thing that comes to mind is
373using .forward files at both sites; this won't work of course, since you will
374be creating a mail loop.  This mail loop can be avoided by inserting the
375following recipe in front of all other recipes in the @PROCMAILRC@ files on
376both sites.  If you make sure that you add the same X-Loop: field at both
377sites, mail can now safely be forwarded to the other account from either of
378them.
379.Sx 4
380:0 @CONTINUE@
381* !^X-Loop: yourname@your.main.mail.address
382| formail \-@FM_ADD_ALWAYS@ "X-Loop: yourname@your.main.mail.address" | \e
383   $SENDMAIL \-oi yourname@the.other.account
384.Ex
385If someone sends you a mail with the word `retrieve' in the subject, the
386following will automatically send back the contents of info_file to the
387sender.  Like in all recipes where we send mail, we watch out for mail
388loops.
389.Sx 6
390:0
391* !^@FROM@+YOUR_USERNAME
392* !^Subject:.*Re:
393* !@FROMDkey@
394* ^Subject:.*retrieve
395| (formail \-@FM_REPLY@ ; cat info_file) | $SENDMAIL \-oi \-t
396.Ex
397Now follows an example for a very simple fileserver accessible by mail.
398For more demanding applications, I suggest you take a look at
399.B SmartList
400(available from the same place as the procmail distribution).
401As listed, this fileserver sends back at most one file per request, it
402ignores the body of incoming mails, the Subject: line has to look
403like "Subject: send file the_file_you_want" (the blanks are significant),
404it does not return files that have names starting with a dot, nor does
405it allow files to be retrieved that are outside the fileserver directory
406tree (if you decide to munge this example, make sure you do not inadvertently
407loosen this last restriction).
408.Sx 18
409:0
410* ^Subject: send file [0-9a-z]
411* !^X-Loop: yourname@your.main.mail.address
412* !^Subject:.*Re:
413* !@FROMDkey@
414* !^Subject: send file .*[/.]\e.
415{
416  MAILDIR=$HOME/fileserver # chdir to the fileserver directory
417
418  :0 fhw                   # reverse mailheader and extract name
419  * ^Subject: send file \e/[^ ]*
420  | formail \-@FM_REPLY@@FM_ADD_ALWAYS@ "X-Loop: yourname@your.main.mail.address"
421
422  FILE="$MATCH"            # the requested filename
423
424  :0 ah
425  | cat \- ./$FILE 2>&1 | $SENDMAIL \-oi \-t
426}
427.Ex
428The following example preconverts all plain-text mail arriving in certain
429encoded MIME formats into a more compact 8-bit format which can be used
430and displayed more easily by most programs.  The
431.BR mimencode (1)
432program is part of Nathaniel Borenstein's metamail package.
433.Sx 17
434:0
435* ^Content-Type: *text/plain
436{
437  :0 @FILTER@@PASS_BODY@@WAIT_EXIT@
438  * ^Content-Transfer-Encoding: *quoted-printable
439  | mimencode \-u \-q
440
441     :0 @ALSO_NEXT_RECIPE@@FILTER@@PASS_HEAD@@WAIT_EXIT@
442     | formail \-@FM_DEL_INSERT@ "Content-Transfer-Encoding: 8bit"
443
444  :0 @FILTER@@PASS_BODY@@WAIT_EXIT@
445  * ^Content-Transfer-Encoding: *base64
446  | mimencode \-u \-b
447
448     :0 @ALSO_NEXT_RECIPE@@FILTER@@PASS_HEAD@@WAIT_EXIT@
449     | formail \-@FM_DEL_INSERT@ "Content-Transfer-Encoding: 8bit"
450}
451.Ex
452The following one is rather exotic, but it only serves to demonstrate a
453feature.  Suppose you have a file in your HOME directory called ".urgent",
454and the (one) person named in that file is the sender of an incoming mail,
455you'd like that mail to be stored in $MAILDIR/urgent instead of in any of the
456normal mailfolders it would have been sorted in.  Then this is what you could
457do (beware, the filelength of $HOME/.urgent should be well below $LINEBUF,
458increase LINEBUF if necessary):
459.Sx 5
460URGMATCH=`cat $HOME/.urgent`
461
462:0:
463* $^From.*${URGMATCH}
464urgent
465.Ex
466An entirely different application for procmail would be to conditionally
467apply filters to a certain (outgoing) text or mail.  A typical example
468would be a filter through which you pipe all outgoing mail, in order
469to make sure that it will be MIME encoded only if it needs to be.
470I.e. in this case you could start procmail in the middle of a pipe like:
471.Sx 1
472cat newtext | procmail ./mimeconvert | mail chris@where.ever
473.Ex
474The
475.B mimeconvert
476rcfile could contain something like (the =0x80= and =0xff= should
477be substituted with the real 8-bit characters):
478.Sx 10
479DEFAULT=|     # pipe to stdout instead of
480              # delivering mail as usual
481:0 @BODY_GREP@@FILTER@@PASS_BODY@@WAIT_EXIT@
482* [=0x80=-=0xff=]
483| mimencode \-q
484
485  :0 @ALSO_NEXT_RECIPE@@FILTER@@PASS_HEAD@@WAIT_EXIT@
486  | formail \-I 'MIME-Version: 1.0' \e
487     \-I 'Content-Type: text/plain; charset=ISO-8859-1' \e
488     \-I 'Content-Transfer-Encoding: quoted-printable'
489.Ex
490.SH "SEE ALSO"
491.na
492.nh
493.BR procmail (1),
494.BR procmailrc (5),
495.BR procmailsc (5),
496.BR sh (1),
497.BR csh (1),
498.BR mail (1),
499.BR mailx (1),
500.BR binmail (1),
501.BR uucp (1),
502.BR aliases (5),
503.BR sendmail (8),
504.BR egrep (1),
505.BR grep (1),
506.BR biff (1),
507.BR comsat (8),
508.BR mimencode (1),
509.BR lockfile (1),
510.BR formail (1)
511.hy
512.ad
513