The sendmail program offers a mode of operation
called rule-testing mode that allows you to observe the flow of
addresses through rule sets. The -bt command-line switch causes
sendmail to run in rule-testing mode.
This mode is interactive. You enter rule set numbers or names,
addresses, and other commands, and sendmail
processes them and prints the results. The -bt switch’s chief use is in testing changes in
the configuration file. It is also useful for learning how rules and
rule sets work.
The following command runs sendmail in rule-testing mode:[141]
% /usr/sbin/sendmail -btAt first, the output produced by this command line prompts you like this:
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked) Enter <ruleset> <address> >
The “ruleset 3” statement says that, beginning with V8 (and
IDA) sendmail, the canonify rule set 3 is no
longer automatically called when rule sets are listed at the
prompt. We cover this property in detail in The Address on page 315.
Prior to V8 sendmail, rule-testing mode
could be used only to test addresses. But beginning with
V8.7 sendmail, new functions were
added. To see a summary of those functions, enter a ? character followed by a
RETURN at the > prompt. The output, which we reproduce
next, lists and gives a brief description of each function.
Note that the numbers to the right refer to sections in this
chapter and are not a part of
sendmail’s output:
> ?
Help for test mode:
? :this help message.
.Dmvalue :define macro `m' to `value'. ← §8.2.1 on page
301
.Ccvalue :add `value' to class `c'. ← §8.2.2 on page
302
=Sruleset :dump the contents of the indicated ruleset. ← §8.4.1 on page
306
=M :display the known mailers. ← §8.4.2 on page
307
-ddebug-spec :equivalent to the command-line -d debug flag.
$m :print the value of macro $m. ← §8.3.1 on page
304
$=c :print the contents of class $=c. ← §8.3.2 on page
305
/mx host :returns the MX records for `host'. ← §8.5.2 on page
309
/parse address :parse address, returning the value of crackaddr, and
the parsed address (same as -bv). ← §8.5.5 on page
311
/try mailer addr :rewrite address into the form it will have when ← §8.5.6 on page
313
presented to the indicated mailer.
/tryflags flags :set flags used by parsing. The flags can be `H' for
Header or `E' for Envelope, and `S' for Sender or `R'
for Recipient. These can be combined. `HR' sets
flags for header recipients. ← §8.5.4 on page
311
/canon hostname :try to canonify hostname. ← §8.5.1 on page
308
/map mapname key :look up `key' in the indicated `mapname'. ← §8.5.3 on page
310
/quit :quit address test mode. ←V8.10 and later
rules addr :run the indicated address through the named rules. ← §8.6 on page
314
Rules can be a comma-separated list of rules.
End of HELP info
>This help output is contained in the
helpfile[142] file, the location of which is defined by the
HelpFile option
(HelpFile on page 1035). If that
option is not defined, or if the file specified does not
exist, you will get the following error message instead of
help:
Sendmail 8.12 -- HELP not implemented
Help for rule-testing mode requires that the helpfile both exist and contain lines that begin with:
-bt
If you installed a new sendmail but did not install the new help file (thus causing the old file to be used), you might see this error:
HELP topic "-bt" unknown
The solution here is to upgrade your helpfile file to the newest version.
Note that each function listed in the help output will also
produce a usage message if it is executed with no arguments.
Consider the /try
function, for example:
> /try
Usage: /try mailer address
>This parallels the syntax shown in the earlier help output. These mini-usage messages can effectively replace the helpfile file in case it is missing.
Finally, note that although address testing was not listed in the help output for V8.7 sendmail, it still existed.
Selected configuration file lines can be entered in rule-testing mode. They will behave just as they do when being read from the configuration file. For V8.8 sendmail and later, three configuration commands are honored:
#Commands that begin with a # are treated as
comments and ignored. Blank lines are also
ignored.
DThe D
configuration command (Configuration-File Definitions on page
787) is used to define a
sendmail macro. Both
single-character and multicharacter
sendmail macro names can be
used.
CThe C
configuration command (Class Configuration Commands on page
854) is used to add a value to a class. Both
single-character and multicharacter class names
can be used.
The # can begin a line. The
other two configuration commands in rule-testing mode must
begin with a dot:
.D{ntries} 23
.Cw localhostFailure to use a dot will produce this error message:
Undefined ruleset Cw
The use of any character other than the two listed will produce this error:
Unknown "." command .bad command hereTo get a usage message, just type a dot:
> .
Usage: .[DC]macro value(s)The .D rule-testing
command is used to define a
sendmail macro. One use for
this command might be to modify a rule that depends
on the $&
prefix (Use Value As Is with $& on page 793). For example, consider this small
configuration file that contains a rule in parse rule set 0 that is
intended to deliver a local user’s address via the
local delivery
agent:
V10 Sparse=0 R$+ $#local $@ $&X $: $1
If $X has a value,
this rule returns that value as the host (the
$@) part of a
parse rule set
0 triple (The parse Rule Set 0 on
page 696). If $X
lacks a value, the host part is empty. This
technique is useful because the $@ part with the
local delivery
agent is used to implement plussed users (Plussed Detail Addressing on page
476).
This scheme can be tested in rule-testing mode by
first specifying a local user with $X undefined:
%/usr/sbin/sendmail -bt -Ctest.cfADDRESS TEST MODE (ruleset 3 NOT automatically invoked) Enter <ruleset> <address> >parse bobparse input: bob parse returns: $# local $@ $: bob
This form of rule testing and the output produced are
described in detail in Process-Specified Addresses on page
314. Here, it is important only to note that the
host part of the triple (the $@ part) is
empty.
Now, use the .D
command to give $X the value home:
> .DXhomeNow, test those rules again:
> parse bob
parse input: bob
parse returns: $# local $@ home $: bobThis time the host part of the triple (the $@ part) has the
value home as
intended.
The .D command can
also be used to redefine the value of existing
sendmail macros. It cannot,
however, be used to redefine
sendmail macros used in rules
(except for $&), because those macros are
expanded as rules are read from the configuration
file (When Is a Macro Expanded? on
page 792). Also see Dump a Defined Macro with $ on
page 304, which describes how to view
sendmail macro values in
rule-testing mode.
The .C rule-testing
command is used to add a member to a class. If the
class does not exist, it is created. One possible
use for this command would be to test whether adding
a member to $=w
will have the effect you desire. For example,
suppose that a new alias called mailhub has been created
for the local host. In the following, we test
sendmail to see whether it
will detect that new name as local:
%/usr/sbin/sendmail -btADDRESS TEST MODE (ruleset 3 NOT automatically invoked) Enter <ruleset> <address> >canonify,parse bob@mailhubcanonify input: bob @ mailhub Canonify2 input: bob < @ mailhub > Canonify2 returns: bob < @ mailhub > canonify returns: bob < @ mailhub > parse input: bob < @ mailhub > Parse0 input: bob < @ mailhub > Parse0 returns: bob < @ mailhub > ParseLocal input: bob < @ mailhub > ParseLocal returns: bob < @ mailhub > Parse1 input: bob < @ mailhub > MailerToTriple input: < > bob < @ mailhub > MailerToTriple returns: bob < @ mailhub > Parse1 returns: $# esmtp $@ mailhub $: bob < @ mailhub > parse returns: $# esmtp $@ mailhub $: bob < @ mailhub >
This form of rule testing and the output that is
produced are described in detail in Process-Specified Addresses on page
314. Here, merely note that the esmtp delivery agent was
selected, suggesting that
mailhub was not automatically
recognized as local.
One way to fix this is to add
mailhub to the class $=w ($=w on page 876). In
rule-testing mode this can be done by using the
.C
command:
> .Cw mailhubNow, feed sendmail the same rules and address as before to see whether this fixed the problem:
> canonify,parse bob@mailhub
canonify input: bob @ mailhub
Canonify2 input: bob < @ mailhub >
Canonify2 returns: bob < @ mailhub . >
canonify returns: bob < @ mailhub . >
parse input: bob < @ mailhub . >
Parse0 input: bob < @ mailhub . >
Parse0 returns: bob < @ mailhub . >
ParseLocal input: bob < @ mailhub . >
ParseLocal returns: bob < @ mailhub . >
Parse1 input: bob < @ mailhub . >
Parse1 returns: $# local $: bob
parse returns: $# local $: bobSuccess! Adding mailhub to the
class $=w fixed
the problem. You could now make that change
permanent by editing your mc
file and using that to create a new configuration
file, or by adding the name to the
/etc/mail/local-host-names
file[143] (FEATURE(use_cw_file) on page 643).
Another use for .C
would include trying out masquerading for a
subdomain (FEATURE(limited_masquerade) on page 625). See also Dump a Class Macro with $=
on page 305 for a way to print the members of a
class while in rule-testing mode.
Beginning with V8.7, rule-testing commands allow you to print
the value of a defined sendmail macro
and the members of a class. With either command, you can use
single-character or multicharacter macro names. Both
commands begin with a $
character. An error is caused if nothing follows that
$:
Name required for macro/class
If an = character follows,
sendmail will display the
requested class. Otherwise, the value of the
sendmail macro is
displayed:
$X ← display the value of the X macro $=X ← list the members of the class X
The $ rule-testing
command causes sendmail to
print the value of a defined
sendmail macro. The form for
this command looks like this:
$X ← show value of the single-character macro name X ${YYY} ← show value of the multicharacter macro name YYY
Only one sendmail macro can be listed per line. If more than one is listed, all but the first are ignored:
$X $Y
↑
ignoredOne use for this command might be in solving the
problem of duplicate domains. For example, suppose
you just installed a new configuration file and
discovered that your host was no longer known as
here.our.domain, but instead
wrongly had an extra domain attached, like this:
here.our.domain.our.domain.
To check the value of $j ($j on page
830) which should contain the canonical name of your
host, you could run sendmail in
rule-testing mode:
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> $j
$w.our.domain
>This looks right because $w ($w on page
850) is supposed to contain our short hostname. But
just to check, you could also print the value of
$w:
> $w
here.our.domainAha! Somehow, $w
got the full canonical name. A quick scan of your
.mc file (Configure with m4 on page 587) turns
up this error:
LOCAL_CONFIG Dwhere.our.domain # $w is supposed to be full -- joachim
Apparently, your assistant, Joachim, mistakenly thought the new sendmail was wrong. You can take care of the configuration problem by deleting the offending line and creating a new configuration file. To solve the problem with Joachim, consider buying him a copy of this book.
The $= rule-testing
command tells sendmail to print
all the members for a class. The class name must
immediately follow the = with no intervening space, or the
name is ignored. Both single-character and
multicharacter names can be used:
$= X ← the X is ignored $=X ← list the members of the class X $={YYY} ← list the members of the multicharacter class YYY
The list of members (if any) is printed one per line:
> $=w
here.our.domain
here
[123.45.67.89]
fax
fax.our.domain
>To illustrate one use for this command, imagine that
you just made the local host the fax server for your
site. Of course, you were careful to modify the
configuration file and add fax
and fax.our.domain to the
$=w class in
it. But incoming mail to
fax.our.domain is still
failing. You run sendmail in
rule-testing mode, as earlier, to verify that the
correct entries are in $=w:
here.our.domain here [123.45.67.89] fax ← correct fax.our.domain ← correct
Because they are correct, it could be that you made the mistake of changing the configuration file and failing to restart the daemon (Daemon mode (-bd) on page 20). The following command line fixes the problem (SIGHUP on page 509):
# kill -HUP `head −1 /etc/mail/sendmail.pid`Beginning with V8.7 sendmail, two
rule-testing commands became available: the =S command displays all
the rules in a given rule set, and the =M command displays all
the delivery agents. Both display their items after the
configuration has been read. Thus, in the case of rules, all
the macros will have already been expanded.
Both commands are triggered by the leading = character. If nothing
follows the =, this usage
message is printed:
Usage: =Sruleset or =M
If any character other than S or M
follows the = character,
the following error is printed:
Unknown "=" command =bad character hereThe =S rule-testing
command causes sendmail to show
all the rules of a rule set. The form of this
command looks like this:
=SrulesetOptional whitespace can separate the
ruleset from the
S. The
ruleset can be a number
or a symbolic name (Rule Set Names
on page 684):
=S0 ← a number =SMyrule ← a name
Note that, although sendmail
macros can be used in defining rule sets (Macros in Rule Set Names on page 686),
they cannot be used with the =S command:
> =S$X
invalid ruleset name: "$X"
Undefined ruleset $X
>One use for the =S
command is to determine why a rule set is not
behaving as expected. Consider a rule set named
LocalizeSender
that is intended to rewrite all sending addresses so
that the local host’s name makes the message appear
as though it came from the mail hub machine. Suppose
that, when testing, you send an address through that
rule but it comes out unchanged:
> LocalizeSender bob@localhost
LocalizeSender input: bob @ localhost
LocalizeSender returns: bob @ localhost
>Puzzled, you look at the actual rule with the =S rule-testing
command:
> =SLocalizeSender
R$* < @ $=w > $* $@ $1 < @ mailhub . our . domain > $3
>Aha! The rule set named LocalizeSender[144] expects the host part of the address to
be surrounded by angle brackets! Knowing this, you
run the address through the rule again, this time
using angle brackets, and it succeeds:
> LocalizeSender bob<@localhost >
LocalizeSender input: bob < @ localhost >
LocalizeSender returns: bob < @ mailhub . our . domain >
>The =M rule-testing
command causes sendmail to
print its list of delivery agents. This command
takes no argument. Note that in the following
example, the lines are wrapped to fit on the
page:
> =M
mailer 0 (prog): P=/bin/sh S=EnvFromL/HdrFromL R=EnvToL/HdrToL M=0 U=0:0 F=9DFMeloq
su L=0 E=\n T=X-Unix/X-Unix/X-Unix r=100 A=sh -c $u
mailer 1 (*file*): P=[FILE] S=parse/parse R=parse/parse M=0 U=0:0 F=9DEFMPloqsu L=0
E=\n T=X-Unix/X-Unix/X-Unix r=100 A=FILE $u
mailer 2 (*include*): P=/dev/null S=parse/parse R=parse/parse M=0 U=0:0 F=su L=0 E=
\n T=<undefined>/<undefined>/<undefined> r=100 A=INCLUDE $u
mailer 3 (local): P=/usr/lib/mail.local S=EnvFromSMTP/HdrFromL R=EnvToL/HdrToL M=0
U=0:0 F=/59:@ADFMPSXflmnqswz| L=0 E=\r\n T=DNS/RFC822/SMTP r=100 A=mail.local -l
mailer 4 (smtp): P=[IPC] S=EnvFromSMTP/HdrFromSMTP R=EnvToSMTP/HdrFromSMTP M=0 U=0:
0 F=DFMXmu L=990 E=\r\n T=DNS/RFC822/SMTP r=100 A=TCP $h
mailer 5 (esmtp): P=[IPC] S=EnvFromSMTP/HdrFromSMTP R=EnvToSMTP/HdrFromSMTP M=0 U=0
:0 F=DFMXamu L=990 E=\r\n T=DNS/RFC822/SMTP r=100 A=TCP $h
mailer 6 (smtp8): P=[IPC] S=EnvFromSMTP/HdrFromSMTP R=EnvToSMTP/HdrFromSMTP M=0 U=0
:0 F=8DFMXmu L=990 E=\r\n T=DNS/RFC822/SMTP r=100 A=TCP $h
mailer 7 (dsmtp): P=[IPC] S=EnvFromSMTP/HdrFromSMTP R=EnvToSMTP/HdrFromSMTP M=0 U=0
:0 F=%DFMXamu L=990 E=\r\n T=DNS/RFC822/SMTP r=100 A=TCP $h
mailer 8 (relay): P=[IPC] S=EnvFromSMTP/HdrFromSMTP R=MasqSMTP/MasqRelay M=0 U=0:0
F=8DFMXamu L=2040 E=\r\n T=DNS/RFC822/SMTP r=100 A=TCP $hThis output is the same as that produced with the
-d0.15
debugging switch (-d0.15 on page
544). The individual items in each line are
explained in Chapter 20 on page 711.
Beginning with V8.7 sendmail, rule-testing mode offers six simple commands that accomplish complex tasks. They are listed in Table 8-1.
|
Command |
Version |
§ |
Description |
|
|
V8.7 and later |
Canonify a Host with /canon on page 308 |
Canonify a host. |
|
|
V8.7 and later |
Look Up MX Records with /mx on page 309 |
Look up MX records. |
|
|
V8.7 and later |
Look Up a Database Item with /map on page 310 |
Look up a database item. |
|
|
V8.7 and later |
Select Whom to /parse or /try with /tryflags on page 311 |
Select whom to |
|
|
V8.7 and later |
Parse an Address with /parse on page 311 |
Parse an address. |
|
|
V8.7 and later |
Try a Delivery Agent with /try on page 313 |
Try a delivery agent. |
A lone / character will
cause the following usage message to print:
Usage: /[canon|map|mx|parse|try|tryflags]
Anything other than the commands shown in Table 8-1 (such as
/foo) will
produce an error:
Unknown "/" command /foo
The /canon
rule-testing command causes
sendmail to look up the
canonical (official, fully qualified) name of a host
and print the result. The form for this command
looks like this:
/canon hostIf host is missing,
the following usage message is printed:
Usage: /canon address
When you correctly supply the hostname as the argument, sendmail looks up the canonical name and returns the result:
> /canon icsic
getcanonname(icsic) returns icsic.icsi.berkeley.edu
>Here, the hostname icsic was looked up. Because its
canonical name was found, that name is printed
following the returns. If the hostname had not been
found, sendmail would have
printed that same name after the returns:
> /canon foo
getcanonname(foo) returns fooIf you wish to watch the actual process of a host
being canonified, you can turn on the -d38.20 debugging switch
(-d38.20 on page 568) with the
rule-testing -d
command (Add Debugging for Detail
on page 318):
> -d38.20
>With that setting, the previous lookup of icsic produces a trace
of all the steps that sendmail
takes:
> /canon icsic
getcanonname(icsic), trying dns
getcanonname(icsic), trying files
text_getcanonname(icsic)
getcanonname(icsic.icsi.berkeley.edu), found
getcanonname(icsic) returns icsic.icsi.berkeley.eduHere, sendmail first looked up
icsic using
DNS. That lookup failed, so
sendmail fell back to looking
it up in the /etc/hosts file,
where it was found. The order in which these
techniques are tried is defined by your service
switch (ServiceSwitchFile on page
1088). If a service-switch mechanism is lacking, the
order is internally defined by
sendmail and varies depending
on the operating system used.
Internally, the /canon rule-testing command can be
watched in greater detail with the -d38.20 debugging switch
(-d38.20 on page 568) and with
the -d8.2
debugging switch (-d8.2 on page
548).
The /mx
rule-testing command causes
sendmail to look up a
specified hostname and return a list of MX records
for that host. The form for this command looks like
this:
/mx hostHere, host is the short or
fully qualified name of a host. If host is missing,
sendmail prints the following
usage message:
Usage: /mx address
When host exists and has MX
records associated with it,
sendmail will look up and
print those records. The MX records are listed in
the order in which they will be tried (lowest to
highest preference values). For example:
> /mx ourhost
getmxrr(ourhost) returns 2 value(s):
mx.our.domain
offsite.mx.domain
>If no MX records are found (as for a.com), sendmail prints the following message:
getmxrr(a.com) returns 0 value(s):
When multiple MX records have the same preference values, sendmail randomizes the list. During a single run of sendmail, the randomization will be the same each time. You can see this by looking up aol.com:
> /mx aol.com
getmxrr(aol.com) returns 4 value(s):
mailin-02.mx.aol.com.
mailin-01.mx.aol.com.
mailin-04.mx.aol.com.
mailin-03.mx.aol.com.If you have defined the FallbackMXhost option (FallbackMXhost on page 1030) the host
that is specified in that option will always appear
last in the list of MX hosts. As a side benefit, the
fallback host will also be listed for hosts that do
not exist:
%/usr/sbin/sendmail -OFallBackMXhost=mx.our.domain -btADDRESS TEST MODE (ruleset 3 NOT automatically invoked) Enter <ruleset> <address> >/mx a.comgetmxrr(a.com) returns 1 value(s): mx.our.domain >
This /mx command is
available for your use only if
sendmail was compiled with
NAMED_BIND
defined (NAMED_BIND on
page 124). If NAMED_BIND was not defined,
sendmail will print the
following error instead of listing MX
records:
No MX code compiled in
The /map
rule-testing command causes
sendmail to look up a key in
a database and print the value found (if there is
one). The /map
command is used like this:
/map name key
Here, name is the name of a
database. It is either a name you assigned using a
K configuration
command (The K Configuration Command on page 882) or a name that is internally defined
by sendmail, such as
aliases.files (switch on page 938). The
key is the item you
wish to look up in the database. If both
name and
key are missing,
sendmail prints this usage
message:
Usage: /map mapname key
If just the key is missing,
sendmail prints this
error:
No key specified
If the name is that of a
database that does not exist,
sendmail prints this
error:
Map named "bad name here" not found
Otherwise, the database does exist, so
sendmail looks up the
key in it. If the
key is not
found in the database, sendmail
prints this:
map_lookup: name (key) no match (error number here )
The error number corresponds to error numbers listed in the sysexits.h file.
The /map
rule-testing command is very useful for testing
databases of your own design. If a rule that uses
the database fails to work as predicted, use
/map to test
that database by hand. To illustrate, consider the
sampling of maps in the following sections.
The aliases map is used
to convert a local address into one or more new
addresses. Using the rule-testing /map command, you can
see how sendmail looks up an
alias:
> /map aliases root
map_lookup: aliases (root) returns you, hans@other.site (0)The host
database behaves the same as the /canon command shown
earlier. It looks up a hostname by using
sendmail’s internal host map ($[ and $]: A Special Case on page 895) which returns the canonical name
of the looked-up host:
>/map host localhostmap_lookup: host (localhost) returns localhost.our.domain. (0) >/map host bogus.no.domainmap_lookup: host (bogus.no.domain) no match (68)
The dequote
map (dequote on page 904) is not
really a database at all, but a hook into a
routine that removes quotation marks from
addresses:
>/map dequote "a"@"@b"map_lookup: dequote ("a"@"@b") returns a@@b (0) >/map dequote "amap_lookup: dequote ("a) no match (0) >/map dequote "<a"map_lookup: dequote ("<a") no match (0) >/map dequote "(a"map_lookup: dequote ("(a") no match (0)
Note in the second example that it removes only balanced quotation marks. Note in the last two examples that it will remove quotation marks only if the enclosed expression is a valid address expression. In neither of the last two examples were the enclosing angle braces or parentheses balanced.
Before we cover the /parse and /try commands, we need to mention the
/tryflags
rule-testing command because it is used to select
the sender, recipient, headers, and envelope for the
/parse and
/try commands.
The /tryflags
command is used like this:
/tryflags h ← set headers /tryflags e ← set envelope /tryflags s ← set sender /tryflags r ← set recipient /tryflags er ← set envelope recipient
The arguments are single letters that can appear in uppercase or lowercase and in any order. Any letter other than those shown is silently ignored.
The default setting when sendmail
first starts to run in rule-testing mode is er for envelope
recipient. Omitting the argument causes
sendmail to print the
following usage statement:
Usage: /tryflags [Hh|Ee][Ss|Rr]
The /parse
rule-testing command instructs
sendmail to pass an address
through a predetermined sequence of rules to select
a delivery agent and to put the $u macro ($u on page 848) into its final
form. The /parse
command is used like this:
/parse address
If the address is missing, sendmail prints the following usage message:
Usage: /parse address
The following example shows a local address being fed
into /parse. Note
that the numbers on the left are for later reference
and are not part of sendmail’s
output:
>/parse you@localhost (Your Name)❶ Cracked address = $g (Your Name) ❷ Parsing envelope-recipient address canonify input: you @ localhost ❸ Canonify2 input: you < @ localhost > ❹ Canonify2 returns: you < @ here . our. domain . > canonify returns: you < @ here . our. domain . > ❺ parse input: you < @ here . our. domain . > Parse0 input: you < @ here . our. domain . > Parse0 returns: you < @ here . our. domain . > ParseLocal input: you < @ here . our. domain . > ParseLocal returns: you < @ here . our. domain . > Parse1 input: you < @ here . our. domain . > Parse1 returns: $# local $: you ❻ parse returns: $# local $: you ❼ 2 input: you 2 returns: you ❽ EnvToL input: you ❾ EnvToL returns: you final input: you final returns: you ❿ mailer local, user you
The address you@localhost is
first fed into crackaddr (line
❶) to separate it from any surrounding RFC822
comments such as "(Your
Name).” If mail were actually to be
sent, the address would be stored in the $g macro before being
passed to rules. This is illustrated by line ❶,
which uses $g as
a placeholder to show where the address was
found.
The next line (line ❷) shows that the address will be
treated as that of an envelope recipient. The
/tryflags
command (Select Whom to /parse or /try with /tryflags
on page 311) sets whether it is treated as a header
or envelope or as a sender or recipient
address.
The address is passed to the canonify rule set 3 (The canonify Rule Set 3 on page 690)
because all addresses are rewritten by the canonify rule set 3
first. The job of the canonify rule set 3 is to focus on
(surround in angle brackets) the host part of the
address, which it does (line ❸). The canonify rule set 3, in
this example, then passes the address to the
Canonify2 rule
set to see whether localhost is
a synonym for the local machine’s name. It is, so
the Canonify2
rule set makes that translation (line ❹).
The output of the canonify rule set 3 is passed to the
parse rule set
0, whose job is to select a delivery agent (line ❺).
Because here.our.domain is the
local machine, the parse rule set 0 (by way of other rule
sets) selects the local delivery agent (line ❻).
Line ❻ shows that the $: part of the delivery agent “triple”
(The parse Rule Set 0 on page
696) will eventually be tucked into $u ($u on page 848) for use by the
delivery agent’s A= equate (A=
on page 738). But before that happens, that address
needs to be passed through its own set of specific
rules. It is given to rule set 2 because all
recipient addresses are given to rule set 2 (line
❼). It is then given to rule set EnvToL because the
R= equate
(R= on page 751) for the
local delivery
agent specifies rule set EnvToL for the envelope recipient (line
❽). Finally, it is given to the final rule set 4 (The final Rule Set 4 on page 694)
because all addresses are lastly rewritten by the
final rule set
4 (line ❾).
The last line of output shows that the local delivery agent was
selected and that the value that would be put into
$u (were mail
really being sent) would be you.
When you /parse an
address that is not local, the parse rule set 3 will
also select a host ($@) part for delivery:
parse returns: $# esmtp $@ uofa . edu . $: friend < @ uofa . edu . >In this instance, the last line of /parse output will also
include the host information that will be placed
into $h:
mailer esmtp, host uofa.edu., user friend@uofa.eduWhen you /parse an
address that is illegal (from the point of view of
rules), sendmail selects the
#error delivery
agent:
> /parse @host
Cracked address = $g
Parsing envelope-recipient address
canonify input: @ host
Canonify2 input: < @ host >
Canonify2 returns: < @ host >
canonify returns: < @ host >
parse input: < @ host >
Parse0 input: < @ host >
Parse0 returns: $# error $@ 5 . 1 . 3 $: "553 User address required"
parse returns: $# error $@ 5 . 1 . 3 $: "553 User address required"
@host... User address required
mailer *error*, host 5.1.3, user "553 User address required"The error here was that the address lacked a user
part. The meanings of all the parts of the #error delivery agent
are described in error on page
720. The second to last line in this example shows
the message that would be printed or returned if
such an address appeared in actual mail. The
delivery agent *error* is internal to
sendmail and cannot be
directly used.
In the SMTP RCPT
To: command,
sendmail is required to
express the recipient’s address relative to the
local host. For domain addresses, this simply means
that the address should be RFC2822-compliant (such
as you@here.our.domain). For
UUCP addresses, this can mean reversing the path
(such as you@there reversing to
there!you). The /try rule-testing
command causes an address to be rewritten so that it
appears to be correct relative to the local
host.
The /try command is
used like this:
/try agent addressHere, agent is the delivery
agent, and address is the
address to rewrite. The following usage message is
produced if both agent
and address are missing
or if just the address is
missing:
Usage: /try mailer address
The delivery agent (mailer) is used to select only the
R= or S= rule set for the
address. The /tryflags command (Select Whom to /parse or /try with /tryflags
on page 311) determines which is selected (by
selecting recipient or sender).
In the following example, the numbers to the left are for reference only and are not part of sendmail’s output:
> /try smtp you
Trying envelope-recipient address you for mailer esmtp
❶ canonify input: you
Canonify2 input: you
Canonify2 returns: you
canonify returns: you
❷ 2 input: you
2 returns: you
❸ EnvToSMTP input: you
PseudoToReal input: you
PseudoToReal returns: you
MasqSMTP input: you
❹ MasqSMTP returns: you < @ *LOCAL* >
EnvToSMTP returns: you < @ here . our . domain . >
❺ final input: you < @ here . our . domain . >
final returns: you @ here . our . domain
Rcode = 0, addr = you@here.our.domainHere, the envelope-recipient address
you is rewritten on the basis
of the smtp
delivery agent. Rule set canonify is called first (line ❶)
because all addresses are rewritten by it first.
Rule set 2 (line ❷) is called because all recipient
addresses get rewritten by it. Rule set EnvToSMTP (line ❹) sees
the special tag *LOCAL* and converts that tag to the
canonical name of your local machine. Rule set
final (line ❺)
removes focusing from the address, thus forming the
final address in its canonical form.
The sendmail rule-testing mode has always had the ability to test individual rule sets, but prior to V8.7 sendmail, rule sets could be specified only by number. Beginning with V8.7, rule sets can also be specified by name. Prior to V8 sendmail, rule set 3 was always called first, even if you did not specify it.[145]
The > prompt expects rule sets and addresses to be specified like this:
> ident,ident,ident ... addressEach ident is a rule set
name or number. When there is more than one rule
set, they must be separated from each other by
commas (with no spaces between them).
For numbered rule sets, the number must be in the range of 0 through the highest number allowed. A number that is too large causes sendmail to print the following two errors:
bad rule set number (max max) Undefined rule set number
A rule set whose number is below the maximum but was never defined will act as though it was defined but lacks rules.
Named rule sets must exist in the symbol table. If the name specified was never defined, the following error is printed:
Undefined rule set identIf any rule set number in the comma-separated list of
rule sets is omitted (e.g.,
ident,,ident),
sendmail interprets the
second comma as part of the second identifier, thus
producing this error:
Undefined rule set ,identifierThe address is everything
following the first whitespace (space and tab
characters) to the end of the line. If whitespace
characters appear anywhere in the list of rule sets,
the rule sets to the right of the whitespace are
interpreted as part of the address.
We show named rule sets in our examples, even though numbered rule sets will work just as well. But by using named rule sets, the examples will still work even if the corresponding numbers change in the future.
Each address that is specified is handed almost as is to the rule set or sets being tested. Each is tokenized and placed into the workspace for rule set processing. To illustrate, observe the following rule-testing session:
ADDRESS TEST MODE (rule set 3 NOT automatically invoked) Enter <rule set> <address> >parse bill (Bill Bix)parse input: bill ( Bill Bix ) Parse0 input: bill ( Bill Bix ) Parse0 returns: bill ( Bill Bix ) ParseLocal input: bill ( Bill Bix ) ParseLocal returns: bill ( Bill Bix ) Parse1 input: bill ( Bill Bix ) Parse1 returns: $# local $: bill ( Bill Bix ) parse returns: $# local $: bill ( Bill Bix ) >parse Bill Bix <bill> parse input: Bill Bix < bill > Parse0 input: Bill Bix < bill > Parse0 returns: Bill Bix < bill > ParseLocal input: Bill Bix < bill > ParseLocal returns: Bill Bix < bill > Parse1 input: Bill Bix < bill > Parse1 returns: $# local $: Bill Bix < bill > parse returns: $# local $: Bill Bix < bill > >canonify,parse Bill Bix <bill> canonify input: Bill Bix < bill > Canonify2 input: bill Canonify2 returns: bill canonify returns: bill parse input: bill Parse0 input: bill Parse0 returns: bill ParseLocal input: bill ParseLocal returns: bill Parse1 input: bill Parse1 returns: $# local $: bill parse returns: $# local $: bill >
The first test illustrates that sendmail does not strip RFC822-style comments from addresses before tokenizing them.
The second test illustrates that
sendmail does not internally
recognize addresses in angle brackets. Instead, the
canonify rule
set throws away everything but the address in angle
brackets, as shown in the third test.
Note that in many actual configuration files, the
canonify rule
set 3 also focuses on the host part of the address.
For this reason, you should
always begin with the
canonify rule
set 3 unless you are tuning a particular rule for
which you know the precise input required.
When sendmail starts to run in rule-testing mode, its appearance and initial behavior vary from vendor to vendor and from version to version. When rule-testing mode begins, sendmail always prints an introductory banner. Pre-V8 sendmail printed the following banner:
ADDRESS TEST MODE Enter <rule set> <address> >
It is important to note that (unless a banner says otherwise) sendmail always calls rule set 3 first.[146] That is, even if you try to test rule set 0, you always first see the effects of rule set 3.
Beginning with V8 sendmail, rule set 3 is no longer automatically called. To ensure that there is no confusion, V8 sendmail prints this banner:
ADDRESS TEST MODE (rule set 3 NOT automatically invoked) Enter <rule set> <address> >
Note that in all versions, the last line (the >) is a prompt. At this prompt, you can specify a rule set and an address or, beginning with V8.7, any of the commands shown in Overview on page 299.
Each line of output produced during rule testing begins with an indication of the rule set number or name being processed:
canonify input: Bill Bix < bill >
The word input
precedes each address that is about to be processed
by a rule set:
canonify input: Bill Bix < bill >The word returns
precedes each address that is the result of
rewriting by a rule set:
canonify returns: billWhen rule sets call other rule sets as subroutines,
those calls are shown in the output with input and returns pairs. In the
following, the Canonify2 rule set is called as a
subroutine rule set from inside the canonify rule set
3:
canonify input: Bill Bix < bill > Canonify2 input: bill Canonify2 returns: bill canonify returns: bill
The output can also contain rule set operators:
parse returns:$#local$:bill
In this output, the operators are printed as they
would appear in the configuration file. The $# selects a delivery
agent, and the $:
specifies the user. Under old versions of
sendmail, those operators are
printed in the output as control characters:
rewrite: rule set 0 returns:^Vlocal^Xbill
The correspondence between control characters in the old-style output and sendmail configuration file operators is given in Table 8-2.
In rule-testing mode, the -d command (The Syntax of -d on page 530) can be
used to turn debugging output on and off. Prior to V8.7
sendmail, the -d could be specified only
on the command line. Beginning with V8.7
sendmail, the -d can also be specified
in rule-testing mode. We illustrate the latter technique
here.
Debugging output can reveal in great detail how individual
rules are being handled. A debugging category and level of
21.12 (-d21.1 on page 554), for example, causes
sendmail to print the LHS of
each rule as it is tried. To illustrate, consider the
following (highly simplified) configuration-file rule
set:
V10 STest R @ $#local $:$n handle <> form R $* < @ $+ > $* $#$M $@$R $:$1<@$2>$3 user@some.where R $+ $#local $:$1 local names
Normal output that is produced when a rule set name and an address are entered at the > prompt looks like this:
> Test george
Test input: george
Test returns: $# local $: georgeBut if we turn on debugging using the -d rule-testing command:
> -d21.12the output that is produced when the same rule set number and address are entered is more verbose than it was before:
> Test george
Test input: george
-----trying rule: @
----- rule fails
-----trying rule: $* < @ $+ > $*
----- rule fails
-----trying rule: $+
-----rule matches: $# local $: $1
rewritten as: $# local $: george
Test returns: $# local $: georgeObserve that the first rule in the Test rule set (the lone @) does not match george in the workspace.
Therefore, that rule fails and is skipped. Then the more
complicated rule ($*<@$+>$*) is tried, and it too
fails. Finally, the $+
operator in the last rule matches george, and the workspace is
rewritten.
Note that the extra output that is produced by -d can potentially run to
many lines. To capture the output for later examination,
consider running sendmail in
rule-testing mode from within a
script(1),
emacs(1), or similar session.
To turn off the extra debugging output, just reuse the
-d rule-testing
command and specify a level of zero:
> -d21.0A -d with no category or
level behaves the same as the -d command-line switch (The Syntax of -d on page 530). It sets a
default of 0–99.1.
In debugging large configuration files, the output
that is produced by the -d21.15 switch can become too huge to
examine conveniently. A good alternative (when
modifying or adding rules) is to temporarily insert
a fake subroutine call before and after individual
rules to see what they do:
R$* $:$>TEST $1 ← fake subroutine call Rlhs rhs ← new rule R$* $:$>TEST $1 ← fake subroutine call
With the fake wrapper around the new rule (the name
TEST is
arbitrary), ordinary rule testing with -bt now shows how the
address is rewritten by that rule:
3 input: ...
TEST input: ...
TEST returns: ...
← new rule acted here
TEST input: ...
TEST returns: ...
3 returns: ...
>If you use this technique, remember, of course, to remove the fake subroutine calls before putting that configuration file into use.
The output that is produced by sendmail can become huge, especially when many addresses need testing. To simplify the process (and to help bulletproof your configuration file), consider using a shell script such as the following:
#!/bin/sh
/usr/sbin/sendmail -bt < $1 |\
egrep "canonify.*input:|canonify.*returns|^>"Here, the output is piped through egrep(1), which selects only the lines of interest. If this script were to be called testcf.sh, it could be invoked with the following command line:
% testcf.sh address.listHere, the address.list is a
file consisting of pairs of rule set names and addresses
such as the following:
canonify,parse nobody@ourhost canonify,parse nobody@ourhost.domain canonify,parse nobody@distant.domain ... and so on
The output that is produced shows the input to the canonify rule set 3 and
the result of each pass through that rule set:
> canonify input: nobody @ ourhost canonify returns: nobody < @ ourhost . domain . > > canonify input: nobody @ ourhost . domain canonify returns: nobody < @ ourhost . domain . > > canonify input: nobody @ distant . domain canonify returns: nobody < @ distant . domain . >
Note that the address.list
file should contain every conceivable kind of address. The
output from the shell script should be saved. At a later
time, after the configuration file is changed,
diff(1) can be used to see
whether the saved output differs from the new output (to see
whether anything unexpected changed as a result of your
modifications).
Also note that directly calling the canonify and parse rule sets 0 produces less useful
information than does the /parse rule-testing command (Parse an Address with /parse on
page 311). If you use that command, a
diff(1) against prior output
can provide more interesting and complete
information.
Old programs and scripts that are designed to
use -bt mode to
test addresses and the like tend to break with
each release of sendmail.
Fortunately, they are easy to fix if you know the
language involved.
There is no way to currently define rules on the fly. Consequently, you need to modify a configuration file and run sendmail in rule-testing mode repeatedly until the new rules work.
[141] * If you get an error such as “sendmail: Address test mode not supported”, you are probably not running the real sendmail. Some programs, such as Netscape’s Internet Mail Server, masquerade as sendmail without letting you know that they are doing so. If this offends you, complain to the vendor of the imposter.
[142] * Prior to V8.10, this file was called sendmail.hf
[143] * Prior to V8.10 sendmail, this file was called /etc/mail/sendmail.cw.
[144] * For the sake of the example, we limited this rule set to a single rule. Most rule sets will have many rules.
[145] * This was adopted from IDA sendmail.
[146] * We use a rule set number here because the versions of sendmail that always started with rule set 3 are too old to use named rule sets.