Alternatives to mhook Programs

[previous] [next] [table of contents] [index]

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:

I hope that gives you an idea of what's possible. You can replace part or all of the mhook utilities with utilities that you develop or get from someone else. This chapter explains the basic concepts and shows a few examples. Another example is the autoinc script. For more about shell programming and using MH utilities like scan in your programs, see the Chapter Introduction to UNIX Programming with MH, and any good shell programming book (try the Reference List). With shell programming, as well as utilities like awk and perl, you can develop your own ways of handling mail automatically.

Replacing All of Your .maildelivery File

You may not need to use the .maildelivery file at all. 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:

The rules are different in some other versions of sendmail. So, running your handler this way may mean some careful programming. You might run your handler from .maildelivery (see the Section Running Your Own Mail Handler) -- this is a safer but maybe less efficient way to do it. To find out more about the environment set in your handler, start with a Bourne shell script like the one in the Example below, Mail handler for debugging. It stores the incoming message in one temporary file. It also opens a temporary log file. The log file stores the verbose output from the shell and the output of two commands that help you see the environment while the handler runs. Both files are created in /tmp; you can list them with ls -l to see what permissions and ownership your handler will give files it creates.

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

The vacation Mail Handler

Many UNIX systems come with the Berkeley vacation program. It's designed to run from a .forward file, sending automatic replies when you're away from the office. When I run it, my .forward file looks like this:
\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.

Running Your Own Mail Handler

Do you want to have all incoming messages processed by your own mail handler? It's probably safer to run your handler from a entry in a .maildelivery file than to have the MTA run your handler directly (see the Section Replacing All of Your .maildelivery File). That's because, if no entry in your .maildelivery file delivers a message, the system defaults will be used; you'll still get the message and it won't "bounce back" to the sender. Also, when your MTA delivers a message through .maildelivery, the environment doesn't have so many inconsistencies.

Setting Up

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.)

Replacing rcvtty with Pop-Up Windows

If you use a window system like X, rcvtty will tell you about new mail in a window where you're logged in. That window might be buried behind other windows, iconified, or full of other text when important mail comes in. Will you see the notice? This script, rcvxterm, makes sure that you will. It's designed for the X Window System, but it should be easy to adapt for other window systems.

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. 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 1.2.1.2 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

Processing with at or cron or by Hand

Instead of running your handler separately each time a new message comes in, it can be better to run a separate handler periodically. On systems where you can't run a handler for each new message, this is your only choice!

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]


Last change $Date: 1996/06/06 15:07:48 $

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 <jpeek@jpeek.com>