Some systems with MH can't use the mhook utilities because the MTA doesn't support them, because the MTA runs on another computer, and so on. You may want your mail processed in batches, late at night -- instead of one by one, with .maildelivery.
Besides, the .maildelivery file and mhook programs can't do everything:
One of the most popular replacements for a .maildelivery file is procmail. This widely-available program by Stephen R. van den Berg is a very powerful and flexible way to filter incoming mail. The syntax is even worse than .maildelivery, but the end result is really worthwhile if you have the patience to learn. If you have nmh version 0.23 or above, look for the MAIL.FILTERING file at the top of the source tree; it has a brief introduction and suggested setup for using procmail with nmh. You'll find more information at www.procmail.org, in Procmail Quick Start, on the newsgroup comp.mail.mh, and the FAQ.
Here's another possibility. Your system's MTA may be able to start a program of yours for each new message you get. I think it's safer (for beginners, at least) not to do this. If your handler fails, your mail could bounce. Instead, run your mail handler from the .maildelivery file, as the Section Running Your Own Mail Handler explains. But that's your choice, not mine!
How to Set Up
If your system uses the popular sendmail or smail MTAs, you can probably start your own mail-handling program by putting its pathname in your .forward file. For example, this line in my .forward file will start the program /u/jerry/bin/inmail:
"| /u/jerry/bin/inmail"If your system handles executable files that start with #! (see the Section How Does Your System Execute Files?), you can probably execute shell scripts that way by just giving the script's name. Otherwise, start scripts by giving the pathname to the interpreter -- for example:
"| /bin/sh /u/jerry/bin/inmail"The MTA will start the program and feed the incoming message to the program's standard input. When the program finishes and returns a zero exit status, the message will have been delivered.
Gotchas: UID, GID, Permissions...
If your mail handler is run directly by the system MTA, you can run into some tough problems making it work correctly. On our Sun with SunOS 4.1, for instance, the sendmail MTA will run a private mail handler in several ways:
Example: Mail handler for debugging
#! /bin/sh exec > /tmp/inmail$$.log 2>&1 # Send all output to log file set -xv # Make shell show debugging output /bin/id # On BSD systems, use "whoami" and "groups" instead /bin/env # On BSD systems, use "printenv" instead /bin/cat > /tmp/inmail$$.stdin # Grab incoming message exit 0 # Important to set a zero status if handler succeeds
\jerry, "| /usr/ucb/vacation jerry"If you just want to acknowledge incoming mail or send a standard reply, vacation can be a good way to do it. The details about the format of the reply, as well as who will get replies and how often, should be in your online vacation(1) manual page.
WARNING: Your version of vacation may require that you let it make a .forward file for you before it will enable itself (by creating its .vacation.dir and .vacation.pag database files).
This happened to me on Solaris: I ran vacation from the command line to enable the vacation system. It asked if I wanted to delete my existing .forward file (which was running slocal) and disable the vacation feature. I answered "no." Then, when I used vacation from my .maildelivery file (see below), it started a mail loop that filled my system mailbox. The fix was to:
- Quickly remove the .forward to stop the looping,
- Let vacation create a .forward file (and, more important, .vacation.dir and .vacation.pag).
- Edit the .forward file to run slocal again.
You may also be able to run vacation from your .maildelivery file. This lets you tailor when vacation will run -- for instance, to send vacation replies only to messages with the subject "lunch." The problem with this is that vacation expects the first line of each mail message to start with "From " and the sender's address -- but, typically, when slocal sees a message, its first line isn't "From ". The fix depends on your system. Here's how Bill Wohler fixed his problem: piping each incoming message through the sed stream editor. This changes the shielded ">From ". line to the "From " that vacation expects:
# # Uncomment when on vacation # #to wohler | R "sed -e '1s/>From /From /' | /usr/ucb/vacation wohler" #cc wohler | R "sed -e '1s/>From /From /' | /usr/ucb/vacation wohler"But that may not be enough; your MH setup may completely remove the incoming "From " line. In that case, the next example shows another way to build a new line. It uses the $(sender) variable to expand the user's address (this is the same address that slocal took from the original "From " line). It needs the version of the UNIX date command that has formatting escapes. The five date escapes %a %b %e %T %Y give the day of the week, the month, the day of the month, time, and four-digit year. If your date command doesn't have formatting, you can probably omit the argument starting with +. The cat command reads the message from the slocal pipe and passes it to the output of the subshell (and the pipe to vacation). The subshell (the parenthesis operators) and the semicolon (;) collect the output of echo and cat and pass them, in order, to the pipe to vacation.
default - > R /var/mail/luis default - | ? "(echo \"From $(sender) `date +'%a %b %e %T %Y'`\"; cat) | vacation luis"If you're having trouble, add a pipe through the UNIX command tee -a the before vacation; you'll see the message that vacation is getting. Note that you may need to use absolute pathnames (like /usr/ucb/vacation) if executable commands aren't in the search path that slocal sets.
To feed all of your mail to your handler, put a entry in your .maildelivery file like one of the three below. Use the first entry if your handler can be executed directly. The second entry runs awk; the third runs a Bourne shell:
* - ^ A /u/jerry/bin/inmail * - ^ A "/usr/bin/awk -f /u/jerry/bin/inmail" * - | A ". /u/jerry/bin/inmail"Of course, you can use fields besides * to control what messages are passed to your handler -- and results besides A to control what other entries in .maildelivery are executed.
The exit status that your handler returns is important. If your handler returns a nonzero status, .maildelivery will act as if that the handler failed. Try to make your handler set a zero status when it succeeds. (The section Using Exit Status explains. The exit 0 command sets a zero status in Bourne shell scripts.)
Printing Incoming Mail
You can print incoming mail from .maildelivery. For instance, the following entry would print all messages sent to the company-standards address. As always, the R means that messages won't be marked "delivered" when they're printed:
to company-standards ^ R "/usr/ucb/lpr -Plaser"The print job may come out with a banner page that says it was printed by daemon or some other user you wouldn't expect. (See the Section on Gotchas.)
If you don't need a pop-up window, you might look at the script anyway. It uses a technique for running programs from .maildelivery that's good to know.
The script should probably be run only for important mail. It opens a red xterm (X terminal emulator) window in the top-right corner of an X display. The title bar will say (depending on your window manager):
Important mail. Press q to quit.There'll be a copy of the mail message inside the window, shown by a pager program like less or pg. (Note that, to keep the window from closing too soon, the pager program can't exit until you select the window and type a command like q. The more pager quits at the end of the file, so it won't do.)
The script is simple on purpose: to make it easy to customize for your window system, and to make it easy to understand. The environment inside your .maildelivery file has almost no information about where you're logged on. So, I hard-coded most of the information into the script. If you need help understanding the script, see the Chapter Introduction to UNIX Programming with MH. To run it, put an entry like the one below in your .maildelivery file. (If your system can directly execute files that start with #!, you can omit the /bin/sh.)
From root | R "/bin/cat >/tmp/m$$; /bin/sh /x/y/rcvxterm /tmp/m$$ &"The script reads a file named on its command line. It could read its standard input, the message from the .maildelivery file. But actions in .maildelivery that don't finish after a reasonable amount of time are killed automatically. To be sure your window stays there, and to avoid blocking other actions in .maildelivery, run rcvxterm in the background as shown above. Use cat to copy the message into a temporary file. (Note that, during .maildelivery, your umask is set at 077. That keeps other users from reading the temporary file.)
The script is below. (You can also get the script from this book's online archive. It's at download/split/mh/bin/rcvxterm.) If you haven't installed a shell script before, there's help in the Section Writing Shell Scripts for MH.
NOTE: If you leave this simple-minded demonstration script running while the display is unattended for long periods, it can overload your system with too many processes and/or open windows. You might hack the script to count the number of rcvxterm processes -- with ps and grep -c, for instance -- and quit without opening an xterm if there are too many running already.
#! /bin/sh # $Id: rcvxterm,v 188.8.131.52 92/08/02 18:19:27 jerry book2 $ ### rcvxterm - HACK script to notify you about new mail ### Usage in .maildelivery: "/bin/cat >/tmp/m$$; /x/y/rcvxterm /tmp/m$$ &" trap '/bin/rm -f $1' 0 1 2 15 # REMOVE TEMP FILE BEFORE EXITING # USE less BECAUSE IT DOESN'T QUIT UNTIL YOU TYPE q. pg WORKS, TOO. # USE FULL PATHS; REMEMBER THAT .maildelivery ENVIRONMENT IS LIMITED. /usr/bin/X11/xterm -display hostname:0.0 \ -geometry 80x24-0+0 -bg red -fg white \ -title "important mail. Press q to quit" \ -ut -e /usr/local/bin/less $1
A handler can read your system mailbox file directly, usually with inc. I think it's easier to do that, splitting your messages into a folder -- then have my handler run MH programs like scan and pick to handle the messages.
Most handlers are probably shell or perl scripts. A script can be run by hand when you type its name at a shell prompt, or your computer can run it automatically with at or cron. One automatic handler is the autoinc shell script.
After you write a script like autoinc, add an entry to your personal crontab file or start an at job to run your script whenever you want. It's probably a good idea to run it late at night, if you can. The load on the system might be less then. Also, and more important, there's less chance of the handler being executed while you're logged on and might be reading mail -- it could change your current folder and current message while you weren't expecting it. (You can avoid that by making the handler use a different MH profile, context, and sequences file. The rmmer script uses most of those tricks.) If you haven't used crontab or at before, there are examples. Also, be sure to check the exit status of commands like inc to see if something has gone wrong -- the Section Using Exit Status has tips.
[Table of Contents] [Index] [Previous: Storing in Mailbox Files: rcvpack] [Next: Practical Tips]
This file is from the third edition of the book MH & xmh: Email for Users & Programmers, ISBN 1-56592-093-7, by Jerry Peek. Copyright © 1991, 1992, 1995 by O'Reilly & Associates, Inc. This file is freely available; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. For more information, see the file copying.htm.
Suggestions are welcome: Jerry Peek <email@example.com>