The .maildelivery File in Detail
[previous]
[next]
[table of contents] [index]
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:
-
When an action writes to a file, the action succeeds if the
file is written successfully.
When an action runs a command, the action succeeds if the command
returns a zero (normal) exit status.
-
If an action succeeds, the message will usually be marked as delivered.
The next item explains what I mean by "usually."
-
Entries in .maildelivery can test to see whether a message was
delivered by previous entries.
For instance, the ? on line 6 of the Example
Simple .maildelivery file
tests for delivery.
If either line 2 or line 4 delivered the message, line 6 won't add
the message to my system mailbox.
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.
-
The versions of slocal I've used have some rough edges.
Some things don't work quite the way the manual page says they will.
Others are undocumented.
There are some small differences in the way that .maildelivery
files are handled by MMDF and by slocal.
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:
- addr
-
Matches the address that was used to cause delivery to the recipient.
It's typically your username (mine is jerry).
This is explained in the Section
System Aliases, the to and addr Fields.
- source
-
Matches the out-of-band sender information, the envelope sender.
This is an address, supplied by the system's mail transfer agent.
You'll usually see it as the first line of a message file starting
with From somewhere, or stored in a Return-Path:
header field.
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 mh-users-request@ics.uci.edu Mon Jan 09 23:43:16 1995
Date: Mon, 09 Jan 1995 23:43:16 GMT
From: Some Person <someperson@somewhere.org>
Subject: Some random subject
You 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 mh-users-request@ics.uci.edu -- 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 mh-users-request@ics.uci.edu ...
- default
-
Matches any message that hasn't been delivered by previous entries.
For instance, look back at the Example
Simple .maildelivery file:
If either line 2 or line 4 delivers the message, line 6 won't.
Otherwise, the message will always go into my mailbox.
- *
-
An asterisk as the first argument matches every message, whether it's
been delivered by other .maildelivery entries or not.
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 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 joe@foo.unsd.edu > ? somefile
from joebob@ > ? otherfile
Of course, that first entry would also match moejoe@foo.unsd.edu,
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:
-
Two rows of CTRL-A characters.
This is an MMDF-style separator:
...End of previous message...
^A^A^A^A
^A^A^A^A
...New message...
The
packf(1)
command uses that format.
-
A blank line followed by a standard From separator line.
This is what the standard UNIX mail command expects:
...End of previous message...
From mh-users-request@ics.uci.edu 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.
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.
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/rcvtty
Here'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 rcvtty
There 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
- $(sender) (typical value: xandra@x.y)
- The "return address" for the message.
This is usually supplied by the system mail transfer agent.
Can be set as third argument on the slocal command line.
The address where you'll want to send replies, instead,
is probably $(reply-to).
- $(address) (typical value: jerry)
- The address that was used to deliver the message to you.
That's usually your username.
Can be set as the first argument on the slocal command line.
- $(size) (typical value: 12345)
- The size of the message, in bytes.
- $(reply-to) (typical value: "J. Doe" <jd@x.y>)
- The address where you should send replies.
If the incoming message has a Reply-To: field, that address is used.
Otherwise, this variable will contain the From: field.
- $(info)
- Miscellaneous out-of-band information.
What you get depends on your system and the situation.
Can be set as the second argument on the slocal command line.
For example, to make rcvtty print the message
Mail: nnn bytes each time new mail comes in, use:
*,-,^,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 first command runs /bin/echo (with its full pathname because
echo isn't built into my Bourne shell) and pipes a reply message
to the standard input of the /bin/mail command.
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" <ruthl@fcpe.ie>
The shell will execute the command:
echo "Thanks ... --Jerry" | /bin/mail '"Ruth A. Lee" <ruthf@fcpe.ie>'
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 (Section Sending Files; Using mhmail and viamail) is fine, too -- but
it runs more slowly than /bin/mail (on my system, at least).
-
The first command line didn't read standard input from the shell
(/bin/mail read its stdin from /bin/echo).
So the second command, rcvpack, can read the new message from its
standard input -- and store it in the gripes file in my home directory.
This chapter shows lots of ways to use the pipe or | action;
browse through the examples below.
destroy Action
(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/rcvtty
If 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:
A Result
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").
R Result
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.
? Result
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.
N Result
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:
-
The message hasn't been delivered yet, and
-
The previous action succeeded.
If this action (with an N result) succeeds, then the message
is marked delivered.
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 message hasn't been delivered yet, and
-
The previous action:
-
Succeeded, and
-
That previous action didn't have an * (asterisk) field.
Of course, I could have missed something.
(The C code is fairly complex.
It's a collection of C switch structures that fall through from
case to case, several flags that test and store information
about previous actions and delivery, continue commands that suddenly
skip to the next .maildelivery entry, and so on.
I've tried to summarize what the code does; see the Section
slocal Documentation vs. Real Life.)
Also, that description could change in other versions of MH.
You may want to be careful if you use
the N result.
Test your .maildelivery file to be sure it does what you expect.
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 endtime
Type 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:
-
The current time is between starttime and endtime, or
-
You are logged on to the host that runs slocal.
So, for example:
# 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:00
To ignore the time restrictions, set both times to something like 0:00
(midnight); then the action will happen whenever you aren't logged in.
|