Before we get started, this is a good place (as good as any...) to mention an nmh feature. slocal will add a Delivery-Date: header field as it delivers each message -- no matter how it's delivered. MH only adds them to messages delivered to a file. Delivery-Date: can be handy with scan, pick, and other commands that let you act on any header field. For instance, you could write a scan format file to display the date and time a message was sent as well as the delivery date and time.
Each entry of .maildelivery has five arguments (except with the undocumented slocal select feature). There's either a comma or one or more spaces between each argument. If an argument has space or a comma in it, put double quotes (") around the argument. To include a literal double quote, type \" (put a backslash first).
This chapter uses eight normal words precisely, with an exact meaning. Because those words are used so often, I decided not to italicize them anywhere except where they're defined. The words are: argument, field, pattern, action, result, string, succeed, and delivered. The definitions are below.
The five arguments on a .maildelivery entry, explained in the following five sections, are:
field pattern action result string
There are a few other things to mention first:
But -- just because an action succeeds, that does not mean the message has been marked "delivered." For instance, I could add a new line 5 to the Example Simple .maildelivery file. The entry would run rcvtty to tell me about new messages that come in. I wouldn't want this action to "deliver" the message; if it did, the messages I'd been notified about would never get into my system mailbox. As you'll see later in this section, using an R result on an entry means that even a successful action won't mark a message delivered.
Simple .maildelivery files usually work just fine. If yours doesn't work the way you think it should, the tips in the Section Debugging Tips may help.
NOTE: Many pathnames in these examples start with /x/y. That pathname is system-dependent; it's typically the MH library directory. If you can't find rcvstore and other commands in this chapter, ask your system administrator.
Now, let's look at the five arguments in each entry.
The first argument, field, refers to a header field in the message. In line 2 of the Example Simple .maildelivery file, for instance, the field argument from will match the From: field in a message header. You can specify any field that might be in a message header, including ones you make up arbitrarily (like X-auto-m-p: in the Section Handing Periodic Mail).
You can't always do what you need to by matching header fields, though. Maybe you get mail from several addresses or aliases, and you want to match any of those messages with one entry. Or, you might want to match all messages. So, the field can also have one of these four special values:
The source is handy for matching mail from mailing lists. This doesn't work for all mailing lists, but it works for many. I'll use the mh-users list as an example. Message headers in mh-users have header fields like these:
From firstname.lastname@example.org Mon Jan 09 23:43:16 1995 Date: Mon, 09 Jan 1995 23:43:16 GMT From: Some Person <email@example.com> Subject: Some random subjectYou can't count on finding the address mh-users in any particular field (though it's usually somewhere on To:, Cc:, or Sender:). But you can bet that the out-of-band sender information, shown in the first line above, will have the address firstname.lastname@example.org -- because that's the distribution point for the mailing list. So, an entry in .maildelivery that begins with the following two arguments will catch mail from the mh-users list:
source email@example.com ...
If the first argument has an * (asterisk), the action will always happen when the result (in the fourth argument) is A or R. A result of N or ? can cause the entry to be skipped when those conditions are met. The Section Fourth .maildelivery Argument: Result explains the result argument.
The second argument, pattern, is the expression you want to match in the field selected by the field argument. For instance, line 4 of the Example Simple .maildelivery file searched for the expression "vax digest", in any combination of uppercase and lowercase, anywhere in the message Subject: field.
If the first argument is default or *, this second argument should be a dash (-).
The pattern argument is not a regular expression like the UNIX grep command uses; it's just a sequence of characters to match literally (such as the UNIX command fgrep). You can do regular expression matching with the rcvsearch program.
You can take advantage of the "substring matching" in the second argument. You might be looking for mail from root on any computer. Using root as a second argument will match mail from root with or without a hostname. You can also match mail from all users at a certain hostname (say, anyone at xyz.com).
The downside is that you can match some messages you weren't planning on. For instance, a search for mail from root might catch mail from Joe Grootenheimer.
One helpful trick takes advantage of the order that your .maildelivery file is read: from first entry to last. If you're trying to match more than one similar name, like joebob and joe, put the longest name first. The first entry that matches marks the message "delivered," so the entries below it won't deliver the message too:
from joebob destroy A - from joeb qpipe A "/x/y/rcvstore +read_now" from joe qpipe A "/x/y/rcvstore +read_later"Depending how your mail comes in, you may be able to add @ or ! to mark the start or end of the address. For example, to match mail from joe on a particular host and joebob@anyhost, use entries like the ones below. The joebob@ will never match mail from joe on any host:
from firstname.lastname@example.org > ? somefile from joebob@ > ? otherfileOf course, that first entry would also match email@example.com, but it's a start.
Whenever I use a destroy action (see the Section Third .maildelivery Argument: Action), I'm always very careful about what I match. The part of that Section about destroy shows a safer way with a temporary folder.
The third argument is the action: how to deliver the message. There are four different actions. Each action can be written in two ways, as a word or as a symbol. (MH 6.8 added a new mbox action, a version of the file action. It can't be written as a symbol.) The actions are:
file or > (right angle bracket) Action
The file or > action appends the message to a file. (That's usually a file on the mail server computer; it may not be the same computer where you do most of your work. You might write the message into a filesystem that's shared between the two computers.) Put the filename in the fifth argument. Without a pathname, the file will be in your home directory. Typical mailbox names are /usr/mail/yourname or /usr/spool/mail/yourname.
The message is appended in "mailbox format." It's separated from the previous message in the file by either:
...End of previous message... ^A^A^A^A ^A^A^A^A ...New message...The packf(1) command uses that format.
...End of previous message... From firstname.lastname@example.org Mon Jan 09 19:55:43 1995 ...New message...The packmbox(1) command uses that format.
In some cases, until MH 6.7.1, the slocal From separator didn't work right. Sometimes, a group of messages stored this way would come in as a single long message when people ran inc. If you have that problem, upgrade MH to Version 6.7.1 or later if you can. Otherwise, try using rcvstore to deliver your messages.
mbox and mmdf Actions
The MH 6.8 version of slocal added a new mbox action. It works like the file or > action except that it always uses the MMDF-style separators. There's no symbol (such as >) for mbox; you have to spell it out.
NOTE: Under nmh, mbox appends messages in mailbox format instead of MMDF format! nmh has an mmdf action that appends messages in MMDF format.
folder or + (plus) Action (nmh only)
This action puts a message into a folder by piping the message to rcvstore. It's only available in nmh; to do this in MH, use one of the pipe actions below.
qpipe or ^ (caret) Action
This starts a program (rcvstore, other mhook programs, or almost any UNIX program). The program reads the incoming message from its standard input. If the program succeeds and returns a zero exit status, then the action has succeeded. For example, to tell you when new mail comes in, set .maildelivery to pipe the message to rcvtty, like this:
* - ^ R /x/y/rcvttyHere's the difference between the qpipe or ^ action and the pipe or | action: using the pipe or | action doesn't execute a program directly -- it starts a Bourne shell; the shell runs the program.
Are you using a simple command string, one that has no special characters like a semicolon (;) or ampersand (&) for a Bourne shell to interpret? Then it's more efficient to use qpipe or ^ instead of pipe or |. That efficiency can be helpful on busy mail server computers.
There's no command-search path set, so be sure to give the pathname for any command you list. For instance, this command probably won't work:
* - ^ R rcvttyThere are special variables that you can use in the fifth argument (the string) with the qpipe or ^ action. The easiest place to find typical settings of these variables is to run slocal -debug and look for the lines starting with vars[n]:, as shown in the Example Sample slocal -debug -verbose output. The variables are listed in the Table below.
Table: Variables Set for pipe and qpipe
*,-,^,R,"/x/y/rcvtty -format \"Mail: $(size) bytes\""The message size is filled in before rcvtty is invoked. The escaped double quotes (\") group the words between them into a single argument. With the quotes, rcvtty prints a message like Mail: 1232 bytes on the terminal. Without them, it would print just Mail: and drop the rest -- that's because there has to be just a single argument after the -format option.
Single quotes (') won't perform quoting inside double quotes. They will work inside double quotes with the pipe or | action, though.
Also watch out for variables like $(reply-to) that might have quotes buried in their values -- they can cause real trouble here. There's more about quoting in the pipe section below.
pipe or | (vertical bar) Action
The pipe or | action starts a Bourne shell to execute the command(s) in the fifth argument, string. The message is piped as standard input to the shell (and the command it runs). If you're running just one command, you may be able to save some execution time by using the qpipe or ^ action (explained above). But if you really need a shell, use pipe or |.
For example, I wanted to add a timestamp to a log file each time a message came in. I used the following entry in my .maildelivery file:
From,uucp,|,A,"/bin/date >> uucp.msglog; /x/y/rcvstore +uucp_logs"What is that fifth argument? The argument has two commands. The first command, /bin/date, appends a line with the current date and time (when a message is delivered) to the file uucp.msglog in my home directory. There's a shell semicolon (;) operator to separate the commands. The first command doesn't read its standard input, but the second command does -- so rcvstore reads the message that is piped to the shell. You can chain a series of commands with semicolons, as long as only one command reads the message from its standard input. (If more than one command needs to read the message, use a temporary file as shown in the Section Replacing rcvtty with Pop-Up Windows.)
The Table Variables Set for pipe and qpipe lists special variables that are set for the qpipe or ^ action. Those variables are also set for pipe and |. Here's an example. To send an automatic reply when I get mail from a user (sent to my system's gripe alias), I can add the following long entry to my .maildelivery file. This has two commands, separated by a semicolon:
To,gripe,|,A,"/bin/echo \"Thanks for your $(size)-character message. I'll handle it ASAP. --Jerry\" | /bin/mail '$(reply-to)'; /x/y/rcvpack gripes"
The quoting (single quotes (') around the $(reply-to) address) is very important here. Let's say my command is building a reply to a message with the following field:
From: "Ruth A. Lee" <email@example.com>The shell will execute the command:
echo "Thanks ... --Jerry" | /bin/mail '"Ruth A. Lee" <firstname.lastname@example.org>'In this case, the single quotes (which aren't very common in mail addresses) surrounded the double quotes (which are common) and things were fine. If the address had single quotes in it, though, the reply would have failed. What would happen if I had used double quotes (") instead of single quotes, like "$(reply-to)"? Or worse, what if I hadn't used quotes? Part or all of the address would have been unquoted and the shell could have been very confused. For more reliable automatic replies (and simpler command strings in your .maildelivery file, too), use a separate shell script; see the Section Running Your Own Mail Handler. (For more about quoting, check UNIX Power Tools or any good shell programming book in the Reference List.)
NOTE: Some mail-sending commands, like /usr/ucb/mail, will break correctly-quoted addresses into single words at the spaces. Don't use commands like UCB Mail or mailx here. The versions of /bin/mail I've seen are okay. The mhmail command (in the Section Send Non-MIME Files: mhmail) is fine, too -- but it runs more slowly than /bin/mail (on my system, at least).
(Before you read this section, take a look back at the definitions of succeeds and delivered at the start of the Section The .maildelivery File in Detail.)
The destroy action does nothing with the message, and always succeeds. This action only makes sense with the result argument A that marks the message as "delivered." (See the Section Fourth .maildelivery Argument: Result.) That's the whole point of destroy: to mark the message as delivered without actually delivering it to a file or program.
If this is the only entry in your .maildelivery file that matches the message, the text of the message will go nowhere. But if another entry has an * (asterisk) field, the message can still be given to a command or stored in a file.
Instead of using destroy, you might use rcvstore or rcvpack to write the message to a temporary folder or file instead. Clean out the temporary storage every so often -- use scan or msh to be sure no messages were "destroyed" that shouldn't have been. The Section Experimenting? Make Backups! has more about making backup copies of mail.
Want an example? Here's a short .maildelivery file with an example of destroy:
From uucp destroy A - default - > ? /usr/spool/mail/jerry * - ^ R /x/y/rcvttyIf the message is from uucp, the first entry matches it and "delivers" the message (to nowhere). The result argument, A, is important here: it means that if the destroy action succeeds (as it always does), the message is marked "delivered." The first entry works with the second entry and its ? result argument. The second entry only writes to my system mailbox file if the message has not been delivered yet. Any message from uucp will have been delivered (to nowhere) already, so it won't go into my system mailbox.
The third entry has an * (asterisk) field, which matches all messages. The R result means that rcvtty always runs to tell me about the message, whether the message has been delivered or not. So, even though messages from uucp have been "destroyed" and aren't delivered to my system mailbox, rcvtty will notify me about them anyway.
The fourth argument in a .maildelivery entry is a single-character result. (As before, the definitions at the start of the Section The .maildelivery File in Detail are important.) These results are:
This result argument is probably the most common. If the field and pattern are matched, an A performs the action. If the action succeeds, the message is marked "delivered."
You'll usually use A actions toward the start of your .maildelivery file to match certain messages. Toward the bottom, you'll use ? to match messages that A didn't match (and "deliver").
Like the A result, an R will perform the action if the field and pattern on an entry match a message. But R never marks a message as "delivered."
If any entry above an R result marks the message delivered, using R can't undo that delivery. In fact, nothing can undo a "delivered" mark. The R is probably most useful at the start of .maildelivery for actions you want to run on some or all messages -- and not mark the message delivered, so that other entries can act on it.
The ? (question mark) will perform an action only if the message hasn't been delivered by some previous entry in .maildelivery. If the ? delivers a message, the message is marked "delivered."
Use ? in places where you've got a series of entries that might deliver a message -- you want the entry with the ? to deliver only if entries above didn't deliver.
The N result was added to slocal in MH 6.7.2. The N result is a little harder to explain. According to the MH 6.8.3 slocal manual page, using an N result performs the action only if both of these things are true:
That's not quite the way N works for me. I looked at the source code (the usr_delivery() function in the file uip/slocal.c) and came up with this more accurate (I hope!) description:
The N result performs the action only if:
The fifth argument, string, is a filename (for the file or > action) or a command line (for the qpipe or ^ and pipe or | actions). As for other arguments, if the filename or command line have any spaces or commas (,), surround the argument with double quotes (").
Because there are example strings all through this chapter, I won't give another example here.
The slocal command with MH 6.6 through 6.8.3 (and possibly in earlier versions) has an undocumented feature that lets you control actions by the time of day and whether you're logged in. (Because they're undocumented, don't depend on this feature in all MH versions.) The three undocumented arguments, which must be used together, are:
select starttime endtimeType the word select literally. starttime and endtime are two times in the format hh:mm, where hh is hours on a 24-hour clock (0 to 23) and mm is minutes.
If you use these optional arguments, the action will not happen if:
# if I'm not logged on and it's not between 8 AM and 5 PM, # send my mail to dan: * - | R "/x/y/rcvdist dan" select 8:00 17:00To ignore the time restrictions, set both times to something like 0:00 (midnight); then the action will happen whenever you aren't logged in.
By default, the .maildelivery file matches fixed strings in the message header. For example, to match messages with bin in the To: field, you could use:
to,bin,|,R,"/x/y/rcvdist operator"But this matches any address that contains the address bin -- including, for example, robin. The rcvsearch script handles this problem and more. It does full regular expression matching on a message header or body. You run rcvsearch from a pipe or | action in the .maildelivery file. rcvsearch compares the entire message to an egrep regular expression. If egrep returns a zero exit status (meaning the search succeeded), rcvsearch runs a command like rcvdist. (rcvsearch also returns a zero status so that the pipe or | action will succeed.) Here's the previous example rewritten to match any From: field containing bin (and nothing else) or bin@:
*,-,|,R,"/x/y/rcvsearch '^From: bin(@?|$)' /x/y/rcvdist operator"Here's a way to refile messages whose bodies contain "make money" or "sex" into the spam-check folder:
*,-,|,A,"/x/y/rcvsearch 'make money|sex' /x/y/rcvstore +spam-check"Once you see rcvsearch, you'll see that the idea is easy to adapt to do other things. For instance, you could rewrite the program in Perl to get more searching power -- or write a small program that does a specific test. Just remember that the program will be run for every incoming message; if you make it complex, it can slow down your incoming mail processing. The Section Explanation of rcvsearch has details.
This file is from the third edition of the book MH & xmh: Email for Users & Programmers, ISBN 1-56592-093-7, by Jerry Peek. It 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 COPYING.
Copyright © 1991, 1992, 1995 O'Reilly Media, Inc.
Copyright © 1996, 1997, 1999, 2000, 2002, 2004 Jerry Peek
Last modified: 2006-05-31 15:13:43 -0700