Book HomeCGI Programming with PerlSearch this book

9.7. procmail

If your CGI scripts send out email, procmail is a very handy tool to learn, but it is only available for Unix. If you are on a Unix system and you do not have it, you can download it from http://www.procmail.org. procmail is a filtering application that allows you to automatically process email based on virtually any criteria. It's not simple, of course; few powerful tools are. And again, like the other tools presented in this chapter, we won't be able to discuss it in great detail here. Instead, we'll look at a couple configurations that should handle your basic needs. If you want to learn more, you can find links to several useful resources including quick-start guides and FAQs at http://www.iki.fi/era/procmail/. Also, don't forget to review the manpage; most of these online resources assume you have done this already. You may not normally enjoy reading manpages, but the procmail man pages are very well written and include numerous examples.

In order to run procmail, you need to create two files in your home directory (or the home directory of the user whose mail you want to forward). The first file, .forward , is used by sendmail when it delivers mail to your account. That file should be set up to it to direct sendmail to run procmail, and procmail uses the .procmailrc file to process the message. It is possible to have procmail set up as the mail transport agent on your system, instead of sendmail; in that case, you do not need the .forward file. Check with your system administrator to see if this is the case.

Your .forward file needs to include only the following line:

"|IFS=' '&&exec /usr/local/bin/procmail -f-||exit 75 #YOUR_USERNAME"

All of the quotes are necessary, there is only one space between the single quotes, you must supply the full path to procmail, and you should of course replace YOUR_USERNAME with your own username (or something to make this line different from the line in other users' .forward files).

9.7.1. Autoreply from nobody

Now all we need to do is create a .procmailrc file. The .procmailrc file contains rules and a command to execute if the rule matches. In this example, we will create only one rule that sends an autoreply to all incoming messages. This would be handy if messages sent to the user that the web server runs as are not redirected. If your web server runs as a valid user named nobody, you could place this in nobody's home directory. Here is the .procmailrc file:

## This is your email address
EMAIL_ADDRESS=nobody@your-domain.com

## Uncomment and edit this line if sendmail isn't at /usr/lib/sendmail
#SENDMAIL=/path/to/sendmail

## If we get a message, verify that it wasn't sent by a mail daemon
## or isn't one of our marked messages. If not, then reply to it using
## the contents of the autoreply.txt file as the body of the message
## and mark the message by adding an X-Loop header.
:0 h
* !^FROM_DAEMON
* !^X-Loop: $EMAIL_ADDRESS
| ( formail -r -A"X-Loop: $EMAIL_ADDRESS"; \
    cat "$HOME/autoreply.txt"            ) | $SENDMAIL -t

## Throw away the messages we're not replying to
:0
/dev/null

We'll briefly review what this file does. For more detailed information, refer to one of the references listed earlier. First, it sets the $EMAIL_ADDRESS variable to the email address of the account receiving this mail. Next, it should specify the path to sendmail if it is something other than the path that procmail defaults to (typically either /usr/lib/sendmail or /usr/sbin/sendmail ). The remaining lines are rules.

All rules start with :0. The first rule also has an h option indicating that we are only interested in the message headers of the incoming message; its body will not be included in our reply. All the lines that begin with * are conditions. Basically, any message that doesn't look like it was generated by a daemon process (this includes bounced mail, mailing lists, etc.) and doesn't include an X-Loop header with our email address in it should be processed by this rule. We'll see why we check for this header in a moment.

The message is processed by piping the headers through formail , a helper application included with procmail. It constructs a reply to the given headers and adds an X-Loop header containing our email address. The reason for adding this to our replies and checking for it in incoming messages is to avoid endless loops. If our CGI script sends a message that bounces (because of an invalid email address, a full account, etc.) and comes back to us, and we automatically reply to it, our reply will also bounce. This could go on forever, but if we add an X-Loop header, that should be maintained within replies so we will know if we see it that we have already replied to this message and to not process another reply. The check for whether the message was generated by a daemon should actually prevent us from replying to a bounce, but the daemon check isn't foolproof, so the X-Loop check is a good way to be safe.

formail takes care of the headers for us, and then we cat the contents of the autoreply.txt file in our home directory. You should create a message in this file appropriate to your site, saying something to the effect that this email address is not used and providing an alternative email address to the recipient. The final results of both the headers and the body are piped to sendmail, which reads the headers and delivers our new reply.

The remaining rule in the file has no conditions. It catches all messages that are not processed by the preceding rule, in other words, all messages that are sent by daemons or that have already been replied to. These messages are simply discarded by moving them to /dev/null.

9.7.2. Forwarding to Another User

It is also possible to simply forward all messages to another user. There are better alternatives than procmail for doing this. Specifically, sendmail allows aliases to be created to redirect mail sent from one email address to another. However, if you cannot get your system administrator to create an alias for you, here is a .procmail file that forwards all incoming mail to another email address:

## This is the email address to forward to
FORWARD_TO=webmaster@your-domain.com

## Uncomment and edit this line if sendmail isn't at /usr/lib/sendmail
#SENDMAIL=/path/to/sendmail

## Forward all messages
:0
! $FORWARD_TO

As you can see, procmail provides you with a number of options for automatically processing email. In one of our examples earlier, we piped the headers of incoming messages through formail. We could have just as easily piped the headers, the body, or the whole message through a Perl script and thus be able to react to every email that arrives. For example, you might want to flag or delete a database record when mail you send to that user is returned as undeliverable. That's just one example; you can probably think of others specific to your site.



Library Navigation Links

Copyright © 2001 O'Reilly & Associates. All rights reserved.