Chapter 12. Maintain Aliases
Aliasing is the process of replacing one
recipient address with one or more different recipient addresses.
The replacement address can be that of a single user, a list of
recipients, a program, a file, or any mixture of these. In this
chapter, we cover the aliases(5) file, one of
the three methods of aliasing available with the
sendmail program. We will cover the
other two forms, :include: (for
including separate files from within the
aliases file) and
~/.forward (the user’s personal
:include: file), in the
next chapter.
Aliasing can be used to handle several complex delivery problems:
Delivering mail to a single user under a variety of usernames
Distributing a mail message to many users by specifying only a single recipient name
Appending mail to files for archival and other purposes
Filtering mail through programs and shell scripts
All the information that is needed to perform these tasks is contained in the aliases(5) file (which is often also stored in database format to expedite the lookup process).
The aliases(5) File
The aliases(5) file is one of several sources that can supply system mail aliases. We describe it first because it is the most traditional and because it illustrates the syntax and limitations common to all techniques.
The aliases(5) file is composed of lines
of text. Any line that begins with a # is a comment and is
ignored. Empty lines (those that contain only a newline
character) are also ignored. Any line that begins with a
space or a tab is joined (appended) to the line above it.
All other lines of text are viewed as alias lines. The
format for an alias line is:
local: alias
The local must begin a
line. It is an address in the form of a local recipient
address (we will discuss this in more detail soon). The
colon follows the local
on the same line and can be preceded with spaces or tabs. If
the colon is missing, sendmail prints
and syslog(3)s the following error
message, and skips that alias line:
missing colon
The alias (to the right of
the colon) is one or more addresses on the same line.
Indented continuation lines are permitted. Each address
should be separated from the next by a comma and optional
space characters. A typical alias looks like this:
root: jim, sysadmin@server,
gunther
↑
indenting whitespaceHere, root is the local
address to be aliased. When mail is to be locally delivered
to root, it is looked up
in the aliases(5) file. If found,
root is replaced
with the three addresses shown earlier, and mail is instead
delivered to those other three addresses.
This process of looking up and possibly aliasing local
recipients is repeated for each recipient until no more
aliases are found in the aliases(5)
file. That is, for example, if one of the aliases for
root is jim and if jim also exists to the
left of a colon in the aliases file, he
too is replaced with his alias:
jim: jim@otherhost
The list of addresses to the right of the colon can be mail
addresses (such as gunther or
jim@otherhost), the name of a
program to run (such as
/etc/relocated), the name of a file
onto which to append (such as
/usr/share/archive), or the
name of a file to read for additional addresses (using
:include:, which
will be covered in the next chapter).
The aliases(5) File’s Location
The location of aliases(5) is
specified with the ServiceSwitchFile option (ServiceSwitchFile on page 1088) and
the AliasFile
option (AliasFile on page 970) in
the configuration file. Be aware that because these
two options interact, it might not suffice to simply
declare one or the other. Also be aware that some
systems (such as Solaris) supply service-switch
files that will override the ServiceSwitchFile
option’s setting.
Note that the service-switch file merely specifies the
order in which various methods should be used to
look up aliases, not the specific files. If it lists
files as a
method:
aliases files
all the files declared with the AliasFile option will be
looked up in the order in which they were
declared:
If the
AliasFileoption specifies a file and if a service-switch file omits thefilesspecification, theAliasFileoption is ignored.If the
AliasFileoption specifies a file and if a service-switch file omits thealiasesline, theAliasFileoption is used.If the
AliasFileoption specifies a file and if there is no service-switch file, theAliasFileoption file is used, except on systems that implement their own service-switch files.If the
AliasFileoption is omitted and if there is no service-switch file or if there is a service-switch file but it omits analiasesline, sendmail silently presumes that it should not do aliasing.
Note that service-switch files and the AliasFile option can
list other techniques for obtaining aliases in
addition to, or instead of, an
aliases(5) file. But this can
lead to a side effect. For example, if your
configuration file declares:
O AliasFile=/etc/aliases,nis:
and if the service-switch file aliases line
specifies:
aliases nis files
sendmail looks up aliases first with nis, then in the /etc/aliases file, then with nis a second time.
Local Must Be Local
The local part of
an alias must be in the form of a local
recipient.[195] This restriction is enforced each time
sendmail reads the
aliases(5) file. For every
name to the left of a colon that it finds,
sendmail performs the
following normalization and verification
steps.
To begin, sendmail normalizes each address by removing everything but the address part. For example, consider the following two alias lines:
george (George Washington): gw George Washington <george>: gw
When sendmail reads these lines, it normalizes each into its address part:
george (George Washington) becomes → george George Washington <george> becomes → george
Afterward, the address part is extracted and rewritten
by the canonify
rule set 3 and the parse rule set 0, to see whether it
causes any delivery agent with the F=A flag set (F=A on page 767) to be
selected. Generally, local addresses select the
local delivery
agent, which normally has the F=A flag set. Nonlocal
addresses (such as
gw@another.host) generally
select one of the smtp delivery agents, which normally do
not have the F=A
flag set.
Prior to V8.7 sendmail, an
address had to select the local delivery to allow itself to be
aliased.
If the selected delivery agent has the F=u flag set (F=u on page 780), the address
will be converted to lowercase before being looked
up in the aliases
database.
In the earlier example, the address george (after
processing) selects the local delivery agent, and so these
alias lines are legal. Internally (or in its
database), sendmail stores the
earlier alias as:
george: gw
When mail arrives that is addressed for delivery to
george,
sendmail rewrites that
address with the canonify rule set 3 and the parse rule set 0. The
parse rule set
0 selects the local delivery agent (or, for V8.7 and
above, any agent with F=A set). The address george is looked up and
replaced with gw.
Internally, sendmail marks the
recipient george
as defunct, having been replaced with an alias, and
then adds gw to
the list of recipients.
The new recipient, gw, is then processed for delivery. The
canonify rule
set 3 and the parse rule set 0 are called once more
and again select a local delivery agent. As a
consequence, gw
is also looked up. If it is found to the left of a
colon in the aliases file, it
too is replaced with yet another address (or
addresses). This process repeats until no new local
addresses are found.
Note that the entry george is marked defunct rather than
being deleted to detect alias loops. To illustrate,
consider the following two mutually referencing
aliases:
george: gw gw: george
The sendmail program first
replaces george
with gw, marking
george as
defunct. It goes to mark gw as defunct but notices that a loop
has been formed. If sendmail is
running in verbose mode (Verbose
on page 1117), it prints:
aliasing/forwarding loop broken
and bounces the message.
Note also that aliases can get pretty complex. As a consequence, when one address aliases to many new addresses, this autodetection of loops can fail (but the problem will be caught later with “hop counting;” see MaxHopCount on page 1046).
Alias Nonlocal Addresses
As distributed, a normal configuration file will disallow certain addresses on the left side of the aliases file. Consider the following two addresses:
Bob@our.host: bob Bob@another.host: bob@home.isp
In both examples, the intention is for mail to bob at the local host (our.host) to be delivered to the local mailbox for the user bob. This will happen in the first example (assuming a normal configuration file) because the @our.host part of the address will be removed by rule sets:
canonify input: Bob @ our.host Canonify2 input: Bob < @ our.host > Canonify2 returns: Bob < @ our.host . > canonify returns: Bob < @ our.host . > parse input: Bob < @ our.host . > Parse0 input: Bob < @ our.host . > Parse0 returns: Bob < @ our.host . > ParseLocal input: Bob < @ our.host . > ParseLocal returns: Bob < @ our.host . > Parse1 input: Bob < @ our.host . > Parse1 returns: $# local $: Bob parse returns: $# local $: Bob 2 input: Bob 2 returns: Bob EnvToL input: Bob EnvToL returns: Bob final input: Bob final returns: Bob mailer local, user Bob
Because the local
delivery agent was selected, and because that
delivery agent has the F=A flag set (F=A on page 767), mail to
Bob@our.host will be aliased
for local delivery to the user
bob.
The second address, Bob@another.host,
however, selects an esmtp delivery agent:
canonify input: Bob @ another . host Canonify2 input: Bob < @ another . host > Canonify2 returns: Bob < @ another . host > canonify returns: Bob < @ another . host > parse input: Bob < @ another . host > Parse0 input: Bob < @ another . host > Parse0 returns: Bob < @ another . host > ParseLocal input: Bob < @ another . host > ParseLocal returns: Bob < @ another . host > Parse1 input: Bob < @ another . host > MailerToTriple input: < > Bob < @ another . host > MailerToTriple returns: Bob < @ another . host > Parse1 returns: $# esmtp $@ another . host $: Bob < @ another . host > parse returns: $# esmtp $@ another . host $: Bob < @ another . host > 2 input: Bob < @ another . host > 2 returns: Bob < @ another . host > EnvToSMTP input: Bob < @ another . host > PseudoToReal input: Bob < @ another . host > PseudoToReal returns: Bob < @ another . host > MasqSMTP input: Bob < @ another . host > MasqSMTP returns: Bob < @ another . host > EnvToSMTP returns: Bob < @ another . host > final input: Bob < @ another . host > final returns: Bob @ another . host mailer esmtp, host another.host, user Bob@another.host
Because the esmtp
delivery agent does not have the F=A flag set, the
presence of the address
Bob@another.host will be disallowed
on the lefthand side of the
aliases file:
% newaliases
/etc/mail/aliases: line 2: Bob@another.host... cannot alias nonlocal namesIn the rare circumstance that you need to be able to
alias nonlocal addresses, you can do so by adding
the F=A flag to
the smtp class of
delivery agents. You do this by editing your
mc configuration file and
adding the following line above the definition for
that class of delivery agents:
APPENDDEF(`SMTP_MAILER_FLAGS', `A') ← prior to V8.10 MODIFY_MAILER_FLAGS(`SMTP', `+A') ← V8.10 and above MAILER(smtp) ← this must follow flag modifications
After that, build a new configuration file from this new mc file and install it. Thereafter, you will be able to successfully alias nonlocal addresses without errors.
Before undertaking this step, however, see FEATURE(virtusertable)
on page 645 for a description of the FEATURE(virtusertable)
which also allows nonlocal addresses to be
transformed into inside or outside addresses. Note,
too, that the User Database (userdb on page 942) allows
recipient addresses to be changed so that they can
be delivered to new hosts, and that the FEATURE(genericstable)
in FEATURE(genericstable)
on page 622 allows sender addresses to be changed to
appear to be coming from new hosts. Clearly, there
are many ways to achieve the same result, and one of
those might be more suitable to your needs than the
F=A
flag.
Forms of Alias Delivery
Addresses in the righthand side of an alias entry can take four forms:
LHS: user LHS: /file LHS: |program LHS: :include: file
The user specifies final delivery
to a user’s mail spool file (subject to change by the user’s
~/.forward file), or delivery
to a new address (e.g., newuser or
user@newsite). The
/file specifies delivery
by appending to a file. The |program
specifies delivery by piping the message through a program.
The :include: specifies
processing of a mailing list. The first three are covered
here. The last is covered in the next chapter.
These righthand sides can be combined on a single line, where one is separated from another by a comma. For example:
LHS: user,/file
Delivery to Users
Any address in the list of addresses to the right of
the colon that does not begin with a /, |, or : character is
considered to be the address of a user. The address
can be local or remote.
If that user address to the right of the colon is
prefixed with (or contains) a backslash character
(\) and the
address is a local one, all further aliasing is
suppressed (including reading the user’s
~/.forward file), and the
message is delivered with the local delivery
agent.
Delivery to Files
When any of the addresses to the right of a colon in
the alias list begin with a / character, delivery is made by
appending the mail message to a file. This is
automatic with all modern configuration files, but
there are exceptions.[196] Beginning with V8.7
sendmail, any delivery agent
for which the F=/
flag (F=/ (forward slash) on page 766) is set can also append messages to
files. If you want to disable this ability, delete
the F=/ flag from
all delivery agent declarations in your
configuration file.
In the list of addresses to the right of the colon,
sendmail considers any local
address that begins with the / character to be the
name of a file.[197] Whenever the recipient address is a
file, sendmail attempts to
deliver the mail message by appending it to the
file. This ability to deliver mail to files is
included in sendmail primarily
so that failed mail can be saved to a user’s
~/dead.letter file. It can
also be used (through use of aliases) to deliver
mail to other files, but that use is less than
optimal, as you will see.
To deliver to a file, sendmail
first performs a fork(2) and
gives the child the task of delivery. The
fork is necessary so that
sendmail can change its
effective uid and
gid, as we will show. The
child then performs a stat(3)
on the file. If the file exists, its file
permissions are saved for later use. If it doesn’t
exist, the saved permissions are defaulted to 0600.
Under V8.7, the decision to use
stat(2) versus
lstat(2) to obtain the
permissions is determined by the SafeFileEnvironment
option (SafeFileEnvironment on
page 1084). Beginning with V8.9, the decision to use
stat(2) versus
lstat(2) depends on the
FileDeliveryToSymLink setting (DontBlameSendmail=FileDeliveryToSymLink on page 1012) for the DontBlameSendmail option.
If the saved permissions have any execute bit set, the
child exits with EX_CANTCREAT as defined in
<sysexits.h>. If the
file has a controlling user associated with it, any
set-user-id and
set-group-id bits are
stripped from the saved permissions. If the file was
listed in a ~/.forward file,
the controlling user is the owner of the
~/.forward file. If it was
listed in an :include:'d file, the controlling user
is the owner of the included file. If the message is
being processed from the queue, the controlling user
can be specified in the qf file (C line on
page 447).
Then, the queue df
file (D line on page 449) is
opened for reading (if it is not already open). If
that file cannot be opened,
sendmail prints the following
error message but continues to attempt
delivery:
mailfile: Cannot open df for file from sender
Here, the df is the name of
the queue datafile that cannot be opened. The
file is the name of the
file to which sendmail is
attempting to deliver the message. The
sender is the address
of the sender of the mail message.
Next, if the SafeFileEnvironment option (SafeFileEnvironment on page 1084) was
declared, sendmail performs a
chroot(2) into the directory
specified. If the chroot(2)
fails, sendmail prints and logs
the following error and the child exits with
EX_CANTCREAT:
mailfile: Cannot chroot(directory)Next, regardless of whether the df file is opened,
sendmail changes its
gid:
If there is a controlling user, sendmail sets its gid to that of the controlling user.
Otherwise, if the set-group-id bit is set in the file’s saved permissions, sendmail changes its gid to that of the group of the file.
Otherwise, sendmail checks to see whether the
U=equate is set for this delivery agent (U= on page 755). If theU=equate is set, sendmail changes its gid to that specified.Otherwise, sendmail changes its gid to that specified by the
DefaultUseroption (DefaultUser on page 1000).
After this, sendmail changes its uid, using the same rules that it used for the gid.
The file (and possibly the path to it) is then checked
to see whether it is safe to write to. See the
-d44 debugging
switch (-d44.4 on page 569) for a
description of this process.
If safe, the file is then opened for writing in append mode. If sendmail cannot open the file, it prints the following error message, and the child exits with EX_CANTCREAT:
cannot open: reason for error hereIf an open fails for a retryable reason, it is attempted 10 more times (sleeping progressively longer between each try)[198] on the assumption that on busy systems there might be a temporary lack of resources (such as file descriptors). The open includes file locking with flock(2) or fcntl(2) to prevent simultaneous writes.
Once the file is opened, the header and body of the
mail message are written to it. Note that
translations are controlled by the F= flags of the prog delivery agent for
all but V8 sendmail. V8
sendmail uses the F= flags of the *file* delivery agent.
For example, F=l
(F=l (lowercase L) on page 774) marks this as final delivery.
If any write error occurs, sendmail prints the following error message, truncates the file to its length before any writes started, and quits trying to write to that file:
I/O error
Finally, the file’s permissions are restored to those that were saved earlier, and the file is closed with fclose(3). If the set-user-id or set-group-id bits were stripped because there was a controlling user, they are restored here.[199] If the file didn’t originally exist, its permissions become 0600.
Delivery Via Programs
When any of the addresses to the right of a colon in
the alias list begin with a | character, delivery is made by piping
the mail message through a program. This is
automatic with modern configuration files.[200] Beginning with V8.7
sendmail, any delivery agent
for which the F=|
flag (F=| (vertical bar) on page 765) is set can also pipe messages
through programs. To disable this ability, simply
remove the F=|
flag from all delivery agent declarations in your
configuration file.
The forms that a program address can legally take in the aliases(5) file (or ~/.forward file; see Piping Through Programs on page 504) are as follows:
|prg "|prg args" |"prg args"
Here, prg is the
full path of the program to be run (the environment
variable PATH is not available). If command-line
arguments are needed for the program, they must
follow prg, and
the entire expression must be quoted. The leading
full quotation mark can either precede or follow the
|. If the
address is quoted with full quotation marks, the
leading quotation mark is ignored in determining the
leading |
character.
To execute the program, sendmail
executes the command in the P= equate of the prog delivery agent.
That command is usually one of the following:
/bin/sh -c /usr/bin/smrsh -c
These tell sendmail to run
/bin/sh (the Bourne shell) or
/usr/bin/smrsh (the
sendmail restricted shell) to
execute the program specified by prg. The -c tells that shell to
take any arguments that follow and execute them as
though they were commands typed interactively to the
shell. These arguments are constructed by removing
the leading |
from the program address and appending what remains,
quotation marks and all, to the P= command. For example,
if an alias looked like this:
jim: "|/etc/local/relo jim@otherhost"
the Bourne shell would be executed with the following command line:
/bin/sh -c "/etc/local/relo jim@otherhost"
The result of all this is that sendmail runs the Bourne shell and then the Bourne shell runs the /etc/local/relo program.
Mail is delivered under this scheme by attaching the output of sendmail to the standard input of the shell and attaching the standard output and standard error output of the shell to the input of sendmail. The sendmail program simply prints the mail message to the shell and reads any errors that the shell prints in return.
Although this process appears to be fairly straightforward, many things can go wrong. Failure usually results in the mail message being bounced.
Possible failures
To communicate with the P= program (the Bourne
shell), sendmail creates two
communications channels using
pipe(2). This can fail
because the system is out of file descriptors or
because the system file table is full. Failure
results in one of the following errors:
openmailer: pipe (to mailer) openmailer: pipe (from mailer)
Next, sendmail executes a
fork(2). The child later
becomes the P=
program. This can fail because the system limit on
the maximum allowable number of processes has been
exceeded or because virtual memory has been
exhausted. Failure causes the following error
message to be printed:
openmailer: cannot fork
In establishing a communications channel, the sendmail child process creates a copy of its standard input file descriptor. This can fail because the system limit on available file descriptors has been exceeded. When this happens, the following message is printed (note that not all dup(2) failures produce error messages):
Cannot dup to zero!
Finally, the child transforms itself into the
A= program with
execve(2). If that
transformation fails, the following error message
is produced, where program is
argv[0] for the
A= program (in
this case, usually
/bin/sh):
Cannot exec programFailure can be caused by a wide range of problems. If a retryable error occurs, the message is queued for a later try.
Programs in the aliases
file are run with the prog delivery agent. As a consequence,
that delivery agent should have the F=s (strip quotes) flag
set.
Write a Delivery Agent Script
The program that is driven by the prog delivery agent can be a compiled
executable binary, a shell script, or even a
perl(1) script. The limitation
on the kind of program that can be run is made by the
sh(1) shell (if sh -c is used in the
A=) or by
execve(2) (if it is launched
directly from the P=).
You need to read the manuals on your system to determine
your limitations. For example, not all versions of
sh(1) allow constructs such as
the following in scripts:
#!/usr/local/bin/perl
When this appears as the first line of a script, the #! tells
sh(1) or
execve(2) to run the program
whose pathname follows, to execute the commands in the
script.[201]
In writing a program for mail delivery using the prog delivery agent, some
unexpected problems can arise. We will illustrate, using
fragments from a Bourne shell script.
Duplicates Discarded
When sendmail gathers its list of recipients, it views a program to run as just another recipient. Before performing any delivery, it sorts the list of recipients and discards any duplicates. Ordinarily, this is just the behavior that is desired, but discarding duplicate programs from the aliases(5) file[202] can cause some users to lose mail. To illustrate, consider a program that notifies the system administrator that mail has arrived for a retired user:
#!/bin/sh /usr/ucb/mail -s gone postmaster
This script reads everything (the mail message) from
its standard input and feeds what it reads to the
/usr/ucb/mail program. The
command-line arguments to mail
are a subject line of gone and a recipient of postmaster. Now consider
two aliases that use this program:
george: "|/usr/local/bin/gone" ben: "|/usr/local/bin/gone"
When mail is sent to both george and ben, sendmail
aliases each to the program |/usr/local/bin/gone. But because both
of the addresses are identical,
sendmail discards one.
To avoid this problem, design all delivery programs to require at least one unique argument. For example, the previous program should be rewritten to require the user’s name as an argument:
#!/bin/sh
if [ ${#} -ne 2 ]; then
echo $0 needs a username.
exit
fi
/usr/ucb/mail -s "$1 gone" postmasterBy requiring a username as an argument, the once-faulty aliases are made unique:
george: "|/usr/local/bin/gone george" ben: "|/usr/local/bin/gone ben"
Although the program paths are still the same, the addresses (names and arguments together) are different, and neither is discarded.
Correct exit(2) Values
The sendmail program expects its
A= programs to
exit with reasonable exit(2)
values. The values that it expects are listed in
<sysexits.h>. Exiting
with unexpected values causes
sendmail to bounce mail and
gives an unclear message:
554 5.0.0 Unknown status valHere, val is the unexpected
error value. To illustrate, consider the following
rewrite of the previous script:
#!/bin/sh
EX_OK=0 # From <sysexits.h>
EX_USAGE=64 # From <sysexits.h>
if [ ${#} -ne 2 ]; then
echo $0 needs a username.
exit $EX_USAGE
fi
/usr/ucb/mail -s "$1 gone" postmaster
exit $EX_OKHere, if the argument count is wrong, we exit with the value EX_USAGE, thus producing a clearer (two-line) error message:
/usr/local/bin/gone needs a username. /usr/local/bin/gone... Bad usage.
If all goes well, we then exit with EX_OK so that sendmail knows the mail was successfully delivered.
Is It Really EX_OK?
When sendmail sees that the
A= program
exited with EX_OK, it assumes that the mail message
was successfully delivered. It is vital for programs
that deliver mail to exit with EX_OK only if
delivery was 100% successful. Failure to take
precautions to detect every possible error can
result in lost mail and angry users. To illustrate,
consider the following common C-language
statement:
(void)fclose(fp);
If the file that is being written to is remotely
mounted, the written data can be cached locally. All
the preceding write statements will have succeeded,
but if the remote host crashes after the last write
(but before the close), some of the data can be
lost. The fclose(3) fails, but
the (void)
prevents detection of that failure.
Even in writing small shell scripts, it is important to include error checking. The following rewrite of our gone program includes error checking but does not handle signals. We leave that as an exercise for the reader.
#!/bin/sh
EX_OK=0 # From <sysexits.h>
EX_USAGE=64 # From <sysexits.h>
EX_TEMPFAIL=75 # From <sysexits.h>
if [ ${#} -ne 2 ]; then
echo $0 needs a username.
exit $EX_USAGE
fi
if /usr/ucb/mail -s "$1 gone" postmaster >/dev/null 2>&1
then
exit $EX_OK
fi
exit $EX_TEMPFAILNote that by using EX_TEMPFAIL, we cause the message to be requeued if this script fails. That way, a bug in the script can be fixed, and the next queue run will succeed.
Special Aliases
The behavior of the sendmail program requires that two specific aliases (postmaster and MAILER-DAEMON) be defined in every aliases file.[203] Beginning with V8.7 sendmail, aliases that contain a plus character can be used to route mail on the basis of special needs. Also, beginning with V8.7 sendmail, databases that allow duplicates can be declared to help automate the creation of those files.
The Postmaster Alias
RFC2822 requires every site to accept for delivery mail that is addressed to a user named postmaster. It also requires that mail accepted for postmaster always be delivered to a real human being—someone who is capable of handling mail problems. If postmaster is not an alias, or a real user, sendmail syslog(3)s the following error:
can't even parse postmaster!
Unless a site has a real user account named postmaster, an alias is required in every aliases file for that name. That alias must be a list of one or more real people, although it can also contain a specification for an archive file or filter program. One such alias might look like this:
postmaster: bill, /mail/archives/postmaster,
"|/usr/local/bin/notify root@mailhost"Here, postmaster is
lowercase. Because all aliases are converted to
lowercase for lookup, Postmaster or even POSTMASTER could have
been used for equal effect.
Note that there are three aliases to the right of the
colon: a local user named bill,
the full path of a file onto which mail messages
will be appended, and a program to notify the user
root at the machine
mailhost that
postmaster mail has arrived
on the local machine. Naturally, a user should not
have to be root to read mail,
so on mailhost there would be a
further alias of root to the
address of a normal user.
As a convention, the special name
postmaster can also be that
of the user who gets duplicate copies of some
bounced mail. This is enabled by using the PostmasterCopy option
(PostmasterCopy on page 1064) in
the configuration file:
OPpostmaster ← pre-V8.7 O PostmasterCopy=postmaster ← V8.7 and above define(`confCOPY_ERRORS_TO', user) ← mc configuration (V8.7 and later)
To disable sending copies of bounced mail to a special user (perhaps to protect privacy), omit this option from the configuration file.
Note that V8 sendmail does not
send a copy of error mail to the postmaster if the
error mail includes a Precedence: header with a value less
than zero, such as junk,
bulk, or
list used by mailing
lists.
Also note that some sites define this user as one who
is always aliased to a filter program in the
aliases file. For example, if
the PostmasterCopy option is declared
as:
OPmail-errors ← pre-V8.7 O PostmasterCopy=mail-errors ← V8.7 and above define(`confCOPY_ERRORS_TO', mail-errors) ←mc configuration (V8.7 and later)
and the corresponding aliases file entry is declared as:
mail-errors: "|/etc/mail/filter postmaster"
a program filter
can be designed that discards all common error
messages, such as mistyped addresses, and forwards
what remains to postmaster.
Many sites have developed just such filters. One is distributed with the V8 sendmail source in the file contrib/mmuegel. Written by Michael S. Muegel of Motorola’s Corporate Information Office, it is a shar(1) file of several useful perl(1) scripts. One (postclip.pl) is a tool that filters out the body of bounced mail messages to prevent postmasters from potentially violating the privacy of senders.[204] It tries to retain all headers, regardless of how deeply they are buried in what appears to be the message body.
RFC2142 Common Mailbox Names
The name postmaster is required by RFC2822 and all sites must accept mail to that address. Another RFC, RFC2142, takes the concept of having a generalized postmaster address one step further by recognizing other roles, such as abuse, info, and marketing. For example, most web sites that sell products also accept email to the address sales, which is now a frequently used, generalized email address.
Table 12-1 shows all the newly required addresses defined by RFC2142. Of these, only postmaster is treated in a case-insensitive manner by sendmail.[205] That is, mail to postmaster, Postmaster, POSTMASTER, and PoStMaStEr will all be delivered to the same person.
|
Address |
RFCs |
Description |
|
|
RFC2142 |
Accepts reports of unacceptable behavior |
|
|
RFC959 |
Accepts mail reporting FTP needs or problems |
|
|
RFC1033 through RFC1035 |
Accepts mail reporting needs or problems with DNS |
|
|
RFC2142 |
Replies to requests for information about the business, its products, and its services |
|
|
RFC2142 |
Handles marketing communications |
|
|
RFC977 |
A synonym for Usenet |
|
|
RFC2142 |
Accepts mail for the network operations center, which deals with network infrastructure problems and requests |
|
|
RFC2821 and RFC2822 |
Accepts mail describing email problems |
|
|
RFC2142 |
Replies with product or service information |
|
|
RFC2142 |
Sends or receives security notices, answers security concerns |
|
|
RFC2142 |
Accepts mail describing problems with products or services |
|
|
RFC977 |
Accepts email notification of problems with the Usenet News system (abuse should be reported to abuse, however) |
|
|
RFC976 |
For sites that support UUCP, accepts mail describing problems with that service |
|
|
RFC2068 |
Accepts mail describing problems with or requests for changes in web services |
|
|
RFC2068 |
A synonym for webmaster |
Note that each of these “required” addresses is actually required only if you offer the service indicated in the description (in Table 12-1). For example, if you do not run UUCP (as few do), you may safely ignore mail to uucp. If you later add UUCP services, you should add an alias for uucp.
RFC2142, then, suggests that a well-formed aliases file might contain the following entries:
info:recipientmarketing:recipientsales:recipientsupport:recipientabuse:recipientnoc:recipientsecurity:recipientpostmaster:recipienthostmaster:recipientusenet:recipientnews:recipientwebmaster:recipientwww:recipientuucp:recipientftp:recipient
Note that recipient will be
a person in some instances, and in others it will be
a program or a file.
In addition to requiring specific recipient addresses,
RFC2142 also requires that mailing lists always have
a mailbox that can be reached using the literal
suffix -request.
That is, if a mailing list is named
bobs, the administrative
address must be
bobs-request.
This behavior is easy to maintain using sendmail and could be implemented in an aliases file entry that looks like this:
bobs: :include:/mail/lists/bobs.list owner-bobs: postmaster bobs-request: bob
Here, the first line defines the actual mailing list
as a list of addresses read from the file /mail/lists/bobs.list.
The second line defines the address that should
process bounced email generated by this list. The
third line defines the -request address that will receive
administrative email concerning the list.
The MAILER-DAEMON Alias
When mail is bounced, the notification of failure is
always shown as being from the sender whose name is
defined by the $n
sendmail macro ($n on page 836). Traditionally,
that macro is given the value mailer-daemon. The
following, for example, shows how to use the
confMAILER_NAME
mc macro to assign the value
mailer-daemon
to the $n
sendmail macro:
define(`confMAILER_NAME', `mailer-daemon')
That tradition is enforced by the fact that if
$n is not
defined, it defaults to mailer-daemon.
There needs to be an alias for whatever name is
defined for $n
because users occasionally make the mistake of
replying to bounced mail. Two typical choices (one
or the other) are:
mailer-daemon: postmaster mailer-daemon: /dev/null
Here, the name to the left of the colon should be
whatever was defined for $n in the configuration file,
traditionally (and recommended to be) mailer-daemon. The first
alias forwards all mailer-daemon reply mail to the
postmaster. Many site administrators prefer the
second, which discards such mail by using
/dev/null.
Plussed Detail Addressing
Plussed detail addressing is a simple way to achieve more versatile aliasing. It is available only with V8.7 sendmail and above, and it requires that you use a configuration file that comes with V8 sendmail. To illustrate its use, consider the need to have mail routed to different sets of administrators depending on how the address root is augmented:
root: hans, george root+db: root, dbadmin@server.db.here.edu root+*: root, root@here.edu
Here, the first line shows a normal sort of alias in which mail sent to root will instead be delivered to the local users hans and george. The second line is still not all that special because we could as easily have used an alias such as root_db to accomplish the same thing. It sends mail to root+db to the local root users and to the database administrators in another department, dbadmin@server.db.here.edu.
The third line is where things start to get
interesting. The +* in it will match anything or nothing
following the plus, so mail sent to
root+ will be sent both to
the local root users and to the
central administrators at
root@here.edu. But so will
anything following the plus that is not db, such as
root+foo.
If the +* form is
omitted:
root: hans, george root+db: root, dbadmin@server.db.here.edu
the default for plussed addresses other than root+db becomes root. That is, when sendmail looks up a plussed address (for example, root+foo) it does so in the following order:
Look for an exact match. Does root+foo match root+db?
Look for a wildcard match. Does root+
*exist? If so, use that alias for root+foo.Look for a base match. Does the root of root+foo exist as an alias? If so, use that alias for root+foo.
Note that plussed users is a simple mechanism that is intended to solve simple needs. In distributing a common aliases file to many machines, for example, plussed users can furnish a hook that allows customization based on simple alias extensions. Because plussed users is simple, attempts to extend it to handle complex needs will likely fail. If your needs are complex, consider using the User Database (userdb on page 942) or writing custom hooks in checkcompat( ) (Appendix C on page 1248) instead.
Beginning with V8.12, a new mc
feature allows you to preserve the plus sign and
what follows it, and to pass that whole address to
your delivery agent. FEATURE(preserve_local_plus_detail)
(FEATURE(preserve_local_plus_detail) on page 637) is useful with
cyrusbb,
cyrus, and other delivery
agents.
Duplicate Entries and Automation
Ordinarily, duplicate local names on the lefthand side of the colon in an aliases file will result in an error. For example, consider this abstract from an aliases file:
staff: bob staff: george
Running newaliases on this file would produce the following error message and would cause the first entry to be ignored:
Warning: duplicate alias name georgeSometimes, however, it is advantageous to produce an aliases file with duplicates. Consider this abstract from a script that adds new users:
if [ $GROUP = "staff" ]
then
echo "staff: $USER" >> /etc/aliasdir/groups
fiHere, we seek to add the user whose login name is
stored in $USER
to the mailing list called staff. To prevent
sendmail from complaining, we
declare the
/etc/aliasdir/groups file
like this in the configuration file:
define(`ALIAS_FILE', `dbm:-A /etc/aliasdir/groups')
Here, the dbm tells
sendmail this is a
ndbm(3)-type file (it could
also be btree or
hash for
db(3)-type files). The
-A switch tells
sendmail to append duplicates
rather than rejecting them. To illustrate, revisit
the earlier aliases
file:
staff: bob staff: george
The first alias line is read and stored normally with this key and value pair:
staff bob ↑ ↑ key value
The second line is then appended to the first line,
because of the -A
switch, to form:
staff bob,george ↑ ↑ key value
The comma is intelligently inserted by sendmail.
Although this technique can simplify the maintenance of some alias files, it should not be overused. Each append requires the prior entry to be read, the space for it and the new entry to be allocated, the old and new entries to be concatenated, and the result to be stored in such a way as to replace the original. This process slows down sendmail noticeably when it rebuilds large files with many duplicates.
As an alternative, consider using the :include: mechanism
described in the next chapter (:include: Mailing Lists on
page 486).
The aliases Database
Reading the aliases file every time sendmail begins to run can slow mail delivery and create a lot of unnecessary computational overhead. To improve efficiency, sendmail has the ability to store aliases in a separate database format on disk. In this format, sendmail rarely needs to read the aliases file. Instead, it merely opens the database and performs lookups as necessary.
The sendmail program builds its database files by reading the aliases(5) file and rewriting that file in database format. Usually, the aliases file is called aliases. With that name, ndbm(3) database files are called aliases.pag and aliases.dir, and the db(5) database file is called aliases.db.
The sendmail program offers several forms of database, one of which is chosen at compile time (confMAPDEF on page 88).
Rebuild the Alias Database
You tell sendmail to rebuild its
database files by running it in -bi mode. This mode can
be executed in two different ways:
%newaliases%/usr/sbin/sendmail -bi
The first form is shorthand for the second. Either causes sendmail to rebuild those files. If the database is successfully built, sendmail prints a single line:
895 aliases, longest 565 bytes, 30444 bytes total
This shows that 895 entries appeared to the left of colons in the aliases file. The longest list of addresses to the right of a colon was 565 bytes (excluding the newline). And there were 30,444 total bytes of noncomment information in the file.
V8 sendmail supports multiple
alias database files (see the AliasFile option, AliasFile on page 970). Consequently,
each line of its output is prefixed with the name of
the aliases file being rebuilt.
For example:
/etc/aliasdir/users: 895 aliases, longest 565 bytes, 30444 bytes total /etc/aliasdir/lists: 34 aliases, longest 89 bytes, 1296 bytes total
Beginning with V8.11, sendmail
allows only root and the user
listed with the TrustedUser option (TrustedUser on page 1112) to rebuild
the aliases database.[206] If you are neither, you will see the
following error message, and the database rebuild
will fail:
Permission denied (real uid not trusted)
Check the Right Side of Aliases
When V8 sendmail rebuilds the
alias database files, it can optionally be told to
check the legality of all addresses to the right of
the colons. The CheckAliases option (CheckAliases on page 982) turns on
this check:
define(`confCHECK_ALIASES', true) ← mc configuration (V8.7 and later) -on ← command-line shorthand (V8.7 and later)
Each address is validated by running it through the canonify rule set 3, and then the parse rule set 0. Rule set parse must select a delivery agent for the address. If it does, the address is silently validated and accepted. If not, the address is skipped, and the following warning is printed:
address... bad addressOther errors might be printed before this line that indicate more specific reasons for the failure. For example:
... Unbalanced '<'
The -d20.1
debugging switch (-d20.1 on page
553) can be used to gain a better idea of why the
address failed. But be
forewarned: the -d20.1 switch can produce many screens
of output.
In general, we do not recommend setting the CheckAliases option to
true in the configuration file because it can cause
each right-side address to be resolved through DNS
and thus slow down the rebuild considerably. For
better efficiency, leave the CheckAliases option off
in the configuration file and turn it on only when
rebuilding by hand:
%newaliases -OCheckAliases%newaliases -on← old-style shorthand, still legal
Use Trailing Dots
It is often desirable to create aliases files that have nonlocal addresses to the right of the colon:
# sean took a job at the fire station sean: sean@firehouse.eli.nv.us
Normally, there is no harm in putting nonlocal addresses in your aliases file. But terrible things can go wrong when the Internet goes bad. Consider, for example, when the name server for firehouse.eli.nv.us begins to act up. Then it is possible for you to run:
% newaliases -onand have the run seem to hang, when it is only stuck, waiting for a bad name server to give back information about firehouse.eli.nv.us. If the wait is long, you might be tempted to kill the rebuild with a kill(8) of −9.
When sendmail’s rebuild is killed
while stuck, the aliases
database can be left in an incomplete state or with
a size of zero. In either instance, inbound mail
will likely begin to bounce. When that happens, you
can immediately rebuild with the -on omitted. This will
restore the bad aliases
database to a good state.
There might be times, however, when you want the
aliases database rebuilt with
the -on always
included. In such an instance, we recommend that you
reduce the risk of sendmail
hanging by placing a dot at the end of any addresses
that seem suspect. For example:
# sean took a job at the fire station
sean: sean@firehouse.eli.nv.us.
↑
add a dotThe presence of the dot short-circuits sendmail’s lookup of that address. The address is presumed good, and the rebuild of the aliases database can continue at a fast rate.
Prevent Simultaneous Rebuilds
The alias database files can be rebuilt in two ways:
automatically, by the daemon or by users sending
mail (and thereby indirectly running
sendmail),[207] or explicitly, by users rebuilding the
database with newaliases (or
the -bi
command-line switch). To prevent one rebuild from
compromising and corrupting another,
sendmail uses file
locking.
The sendmail program uses flock(2) or fcntl(2) with F_SETLK to lock the aliases file (depending on how it was compiled). If the aliases file is already locked (because the database is currently being rebuilt), sendmail prints the following message:
Alias file name is already being rebuiltIf sendmail is attempting to
rebuild because it was run as
newaliases or with the
-bi
command-line switch, the previous message is
printed, and the program exits. Otherwise, the
previous message is printed, and
sendmail waits for the
aliases file to become
unlocked.
Once the aliases file is locked,
sendmail next looks to see
whether the key @
appears in the database. If that key is missing,
sendmail knows the database
is still being rebuilt. If the AliasWait option (AliasWait on page 973) has a value,
sendmail waits that amount of
time for the other rebuild to finish. If the
AliasWait
option is missing or has a zero value,
sendmail plows ahead,
trusting the previous lock to prevent simultaneous
rebuilds.
The sendmail program waits the
number of seconds specified by the AliasWait option for an
@ key to appear
in the database. If that key doesn’t appear within
that wait, sendmail continues
with the rebuild, assuming that some other process
died while attempting to rebuild.
Before entering the key (the name to the left of the
colon) and contents (everything to the right of the
colon) pairs into the database,
sendmail truncates the
database (reduces it to size zero), thereby removing
the @
key.[208] After all the key and content pairs have
been written to the database,
sendmail adds a new @ key to show that it is
done.
Finally, sendmail closes the database and the aliases file. Closing the aliases file releases all locks it has on that file.
No DBM Aliasing
Some versions of Unix do not provide the libraries that are needed to compile sendmail with database support. When neither the db(3) nor ndbm(3) library is available, and when no other method for getting aliases is declared (such as nis), sendmail keeps aliases in its internal symbol table.
When the symbol table is used, sendmail reads the aliases text file only once, when sendmail starts or is forked as a child. If the aliases text file changes, a running daemon will not automatically recognize that change. Instead, the daemon must be killed, and restarted, before it can use any new aliases text file entries.
In general, we discourage you from running sendmail in daemon mode without external aliases database files.
Prevent Aliasing with -n
At times, it is desirable to run sendmail so that it does not perform aliasing. When aliasing is disabled, sendmail uses the recipient address as is. No addresses are ever looked up in the aliases file, even if they are local.
The -n command-line switch
tells sendmail not to perform aliasing
of recipient addresses. This switch is rarely used but can
be handy in a couple of situations.
Is an Alias Bad?
In tracking down local delivery problems, it can be difficult to determine where the problem lies. If you suspect a bad alias, you can force aliasing to be skipped and see whether that causes the problem to go away:
% /usr/sbin/sendmail -n user < /dev/nullThis tells sendmail to send an
empty mail message (one containing mandatory headers
only) to the recipient named user. The -n prevents
sendmail from looking up
user either in
the aliases database or in that
user’s ~/.forward. If user resolves to the
local delivery
agent, the message will be delivered, and you should
therefore suspect an aliasing problem.
Other switches, such as -v (verbose) and -d (debugging), can be
combined with -n
to view the delivery process in more detail.
Filtering Recipients with a Shell Script
The -n command-line
switch can also be used to suppress aliasing when
delivering to a list of recipients that has already
been aliased. For example, consider the following
script, which attempts to restrict delivery to users
who have mail delivered locally and to skip users
who have mail forwarded offsite:
#!/bin/sh
EX_OK=0 # From <sysexits.h>
EX_NOUSER=67 # From <sysexits.h>
EX_SOFTWARE=70 # From <sysexits.h>
if [ ${#} -ne 2 ]; then
echo Usage: $0 list-name
exit $EX_USAGE
fi
trap "exit 70" 1 2 13 15
LIST= "`/usr/sbin/sendmail -bv $1 \
| grep "mailer local" 2>&1'" \
| sed 's/\.\.\..*$//'
if [ -z "$LIST" ]
echo "$1 expanded to an empty list"
exit $EX_NOUSER
fi
if /usr/sbin/sendmail -n $LIST >/dev/null 2>&1
then
exit $EX_OK
fi
exit $EX_SOFTWAREThe sendmail program is called
twice inside this script. First, it is given the
-bv switch,
which causes it to expand the list of recipients in
$1. That
expansion includes aliasing (and
~/.forward aliasing) for each
name in the list. The output produced looks like
this:
user1... deliverable: mailer local, user user1 user2@otherhost... deliverable: mailer smtp, host otherhost, user user2@otherhost
The grep(1) program selects only
those lines that contain the expression "mailer local", thus
indicating a local user. The
sed(1) program then discards
from the ... to the end of each selected line. The
result, a list of local recipients only, is saved in
the shell variable LIST.
The sendmail program is called
with the -n
switch, which prevents it from re-aliasing the list
of names in $LIST
(they have already been aliased once).
Note that this script should not be used as is because
it checks only for the delivery agent named local, rather than for
any delivery agent that can perform final
delivery.
Pitfalls
The dbm and ndbm forms of the aliases(5) database files contain binary integers. As a consequence, those database files cannot be shared via network-mounted filesystems by machines of differing architectures. This is not a problem for Sleepycat db files.
The aliases file and database files can be used to circumvent system security if they are writable by the wrong users. Proper ownership and permissions are checked and enforced only by V8.9 and above sendmail. Restrictions on who can rebuild are enforced beginning with V8.11 sendmail.
Versions of sendmail that use the old-style dbm(3) libraries can cause overly long alias lines (greater than 1024 bytes) to be silently truncated. With the new databases, such as ndbm(3), a warning is printed. Note that V8 sendmail does not support old-style dbm(3) for this very reason.
Recursive (circular self-referencing) aliases are detected only when mail is being delivered. The sendmail program does not look for such alias loops when rebuilding its database.
Because of the way V8.8 sendmail and above lock the aliases file for rebuilding on some operating systems, that file must be writable by root. If it is not, sendmail prints the following and skips the rebuild:
warning: cannot lock aliases: Permission denied
This can be a problem if the master aliases file is shared via NFS because root is normally mapped to nobody.
[195] * If you set the
F=A flag for
the various smtp delivery agents, the local part of an alias
can be specified as a network or remote address,
such as
user@host.domain.
[196] * If yours is an
old configuration file that does not automatically
recognize a leading / character, you will need to add a new
rule near the end of your rule set 0. For
example:
R/$+ $@ $#local $:
/$1
[197] † Note that an @host prevents this interpretation. That is, /a is a file, but /a@host is not. This distinction is necessary for X.400 addresses to be handled correctly.
[198] * The progression is 0 seconds for the first sleep, then 10 seconds, then 20 seconds, then 30 seconds, and so on.
[199] * This is because some paranoid systems, such as BSD Unix, turn off the set-user-id and set-group-id bits when a file is written other than by root.
[200] † If your older
configuration file does not automatically
recognize a leading | character, you might need to add a
new rule near the end of your rule set 0. For
example:
R|$+ $@ $#local $:
|$1
[201] * Not all versions of Unix support this feature, and on some of those that do support it, only a few shells are supported.
[202] † Under V8 sendmail, this is no longer a problem for duplicate programs listed in ~/.forward files (Piping Through Programs on page 504) but still is a problem for aliases. The solution that sendmail uses is to internally append the uid of the ~/.forward file’s owner to the program name, thus making the program name more unique.
[203] * RFC2142 adds others to this list (RFC2142 Common Mailbox Names on page 474), such as abuse, webmaster, and so on.
[204] * Note that this
can also be done with the nobodyreturn keyword (PrivacyOptions=nobodyreturn on
page 1066) with the PrivacyOptions option.
[205] † Although RFC2142 requires that they all be treated in a case-insensitive manner.
[206] * V8.12 and above sendmail are no longer set-user-id root, which further limits who can rebuild aliases.
[207] * Under
pre-V8.12, this occurred only if the AutoRebuildAliases
option (AutoRebuildAliases on
page 978) was set to true. This option has been
removed beginning with V8.12
sendmail, and the
aliases database can no
longer be automatically rebuilt.
[208] * Even though we
show how sendmail rebuilds
its aliases file, you should
not take this as advice to use
makemap(1) to perform that
task. You should use
newaliases (or the -bi command-line switch)
only to rebuild.