Beginning with V8.7
sendmail
, rule-testing mode offers six simple commands that
accomplish complex tasks. They are listed in
Table 38.1
.
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 38.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
host
If
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 foo
If you wish to watch the actual process of a host being canonified,
you can turn on the
-d38.20
debugging switch (see
Section 37.5.135, -d38.20
)
with the rule-testing
-d
command (see
Section 38.7, "Add Debugging for Detail"
):
> -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.edu
Here,
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 (see
Section 34.8.61, ServiceSwitchFile
). If a service-switch mechanism is lacking, the order is internally defined by
sendmail
and varies depending operating system used.
Internally, the
/canon
rule-testing command can be watched
in greater detail with the
-d38.20
debugging switch
(see
Section 37.5.135
) and with the
-d8.2
debugging
switch (see
Section 37.5.31, -d8.2
).
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
host
Here,
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,
sendmail
"
returns 0
."
When multiple 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 8 value(s):
d.mx.AOL.COM.
h.mx.AOL.COM.
g.mx.AOL.COM.
c.mx.AOL.COM.
b.mx.AOL.COM.
f.mx.AOL.COM.
e.mx.AOL.COM.
a.mx.AOL.COM.
>
/mx aol.com
getmxrr(aol.com) returns 8 value(s):
d.mx.AOL.COM.
h.mx.AOL.COM.
g.mx.AOL.COM.
c.mx.AOL.COM.
b.mx.AOL.COM.
f.mx.AOL.COM.
e.mx.AOL.COM.
a.mx.AOL.COM.
Now exit rule-testing mode and perform two separate runs of
sendmail
:
%
echo /mx aol.com | /usr/lib/sendmail -bt
> /mx aol.com
getmxrr(aol.com) returns 8 value(s):
d.mx.AOL.COM.
g.mx.AOL.COM.
h.mx.AOL.COM.
c.mx.AOL.COM.
b.mx.AOL.COM.
f.mx.AOL.COM.
a.mx.AOL.COM.
e.mx.AOL.COM.
%
echo /mx aol.com | /usr/lib/sendmail -bt
> /mx aol.com
getmxrr(aol.com) returns 8 value(s):
b.mx.AOL.COM.
d.mx.AOL.COM.
g.mx.AOL.COM.
e.mx.AOL.COM.
a.mx.AOL.COM.
c.mx.AOL.COM.
h.mx.AOL.COM.
f.mx.AOL.COM.
If you have defined the
FallbackMXhost
(
V
)
(see
Section 34.8.25, FallbackMXhost (V)
), the host that is specified in that
option will always appear last in the list of mx hosts. As a
side benefit, it will also be listed for hosts that do not
exist:
%
/usr/lib/sendmail -OFallBackMXhost=mx.our.domain -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
>
/mx foo.bar
getmxrr(foo.bar) returns 1 value(s):
mx.our.domain
>
This
/mx
command is available for your use only if
sendmail
was compiled with NAMED_BIND defined
(see
Section 18.8.23, NAMED-BIND
). If NAMED_BIND was
not defined,
sendmail
will print the following error instead
of listing MX records:
No MX code compiled in
Internally, the
/mx
rule-testing command can be watched
in a little more detail with the
-d8.2
debugging
switch (see
Section 37.5.31
). It can be watched in huge
detail with the
-d8.20
debugging switch (see
Section 37.5.36, -d8.20
).
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 (see
Section 33.3, "The K Configuration Command"
) or one that is internally defined by
sendmail
, such as
aliases.files
(see
Section 33.8.17, switch
).
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 exists, 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
<sysexits.h>
.
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, first get a list of
databases that are available on your local machine:
%
/usr/lib/sendmail -d38.4 -bt | grep map_init
map_init(sequence:aliases.files, NULL, 0)
map_init(implicit:Alias0, /etc/aliases, 0)
map_init(host:host, NULL, 0)
map_init(switch:aliases, aliases, 0)
map_init(dequote:dequote, NULL, 0)
Here, the name of each database follows the colon in each line.
Your list, of course, will probably be different.
The
aliases
database, for example, 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 above. It looks up a hostname by using
sendmail
's
internal
host
map (see
Section 33.4.3, "$[ and $]: A Special Case"
), which returns the
canonical name of the looked-up host:
>
/map host localhost
map_lookup: host (localhost) returns localhost.our.domain. (0)
>
/map host bogus.no.domain
map_lookup: host (bogus.no.domain) no match (68)
The
dequote
map (see
Section 33.8.4, dequote
)
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 "a
map_lookup: dequote ("a) no match (0)
Note (in the second example) that it removes only balance quotation marks.
All lookups, no matter what the type, can be watched with the
-d38.20
debugging switch (see
Section 37.5.135
).
Two additional commands are
/parse
and
/try
.
We will cover them next, but first we need to mention the
/tryflags
rule-testing command, because it is used to select
the sender or recipient and headers or envelope for those
other 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 may appear in upper- 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.
[2]
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 (see
Section 31.10.36, $u
)
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
rewrite: ruleset 3 input: you @ localhost
rewrite: ruleset 96 input: you < @ localhost >
rewrite: ruleset 96 returns: you < @ here . our . domain . >
rewrite: ruleset 3 returns: you < @ here . our . domain . >
rewrite: ruleset 0 input: you < @ here . our . domain . >
rewrite: ruleset 0 returns: $# local $: you
rewrite: ruleset 2 input: you
rewrite: ruleset 2 returns: you
rewrite: ruleset 20 input: you
rewrite: ruleset 20 returns: you
rewrite: ruleset 4 input: you
rewrite: ruleset 4 returns: you
mailer local, user you
The address
you@localhost
is first
fed into
crackaddr
(line
2
) to separate
it from any surrounding RFC822 comments (see
Section 37.5.117, -d33.1
),
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
2
, which uses
$g
as a place holder to
show where the address was found.
The next line (line
3
) shows that the address will be
treated as that of an envelope recipient.
The
/tryflags
command (see
Section 38.5.4
)
sets whether it is treated as
a header or envelope or as a sender or recipient address.
The address is passed to rule set 3 (see
Section 29.4, "Rule Set 3"
) because
all addresses are rewritten by rule set 3 first. The job of rule set
3 is to focus on (surround in angle brackets) the host part of the address,
which it does (line
5
).
Rule set 3, in this example, then passes the address to rule set 96 to
see whether
localhost
is a synonym for the local machine's name.
It is, so rule set 96 makes that translation (line
6
).
The output of rule set 3 is passed to rule set 0 whose job is to
select a delivery agent (line
8
). Because
here.our.domain
is the local machine, rule set 0 selects the
local
delivery agent
(line
9
).
Line
9
shows that the
$:
part of the delivery agent "triple"
(see
Section 29.6, "Rule Set 0"
) will eventually
be tucked into
$u
(see
Section 31.10.36
) for use by the delivery agent's
A=
equate
(see
Section 30.4.1, A=
). But before that happens, that address needs to be
passed though its own set of specific rules. It is given to rule set
2 because all recipient addresses are given to rule set 2 (line
10
). It is then given to rule set 20 because the
R=
equate (see
Section 30.4.10, R=
)
for the
local
delivery agent specifies rule set 20
for the envelope recipient (line
12
).
Finally, it is given to rule set 4
(see
Section 29.5, "Rule Set 4"
) because all addresses are lastly rewritten
by rule set 4 (line
14
).
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, rule set
0 will also select a host (
$@
) part for delivery.
rewrite: ruleset 0 returns: $# smtp
$@ 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 smtp,
host there.domain.,
user friend@there.domain
When 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
rewrite: ruleset 3 input: @ host
rewrite: ruleset 96 input: < @ host >
rewrite: ruleset 96 returns: < @ host >
rewrite: ruleset 3 returns: < @ host >
rewrite: ruleset 0 input: < @ host >
rewrite: ruleset 0 returns: $# error $@ 5 . 1 . 1 $: "user address required"
@host... user address required
mailer *error*, user
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
Section 30.5.2, "The error Delivery Agent"
.
The second from the 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.
Internally, the
/parse
command first calls
crackaddr
(),
prints the result, then passes the original address to
parseaddr
().
The entry into and exit
from
crackaddr
() can be watched with the
-d33.1
debugging
switch (see
Section 37.5.117
). The selection of a delivery agent
with
parseaddr
() can be watched with the
-d20.1
debugging
switch (see
Section 37.5.66, -d20.1
). The rewriting of the user into
a suitable
$u
is handled by
buildaddr
() which can
be watched with the
-d24.5
debugging switch (see
Section 37.5.82, -d24.5
).
In the SMTP RCPT 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 RFC822-compliant (such as
you@here.our.domain
). For UUCP addresses,
this may mean reversing the path (such as
you@there
reverses 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 address
Here,
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 (see
Section 38.5.4
)
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 smtp
rewrite: ruleset 3 input: you
rewrite: ruleset 96 input: you
rewrite: ruleset 96 returns: you
rewrite: ruleset 3 returns: you
rewrite: ruleset 2 input: you
rewrite: ruleset 2 returns: you
rewrite: ruleset 21 input: you
rewrite: ruleset 21 returns: you < @ *LOCAL* >
rewrite: ruleset 4 input: you < @ *LOCAL* >
rewrite: ruleset 4 returns: you @ here . our . domain
Rcode = 0, addr = you@here.our.domain
Here, the envelope-recipient address
you
is rewritten
on the basis of the
smtp
delivery agent. Rule set 3 is called first
(line
31
) because all addresses are rewritten by it first.
Rule set 2 (line
32
) is called because all recipient
addresses get rewritten by it. Rule set 21 is called because that
rule set was indicated by the
smtp
delivery agent's
R=
equate. That rule set detects that the envelope recipient address (
you
) is local (line
33
).
Rule set 4 (always the last to rewrite) sees the special tag
*LOCAL*
and converts that tag
to the canonical name of your local machine (line
34
).
>
/try uucp localhost!there!you
Trying envelope recipient address localhost!there!you for mailer uucp
rewrite: ruleset 3 input: localhost ! there ! you
rewrite: ruleset 96 input: there ! you < @ localhost . UUCP >
rewrite: ruleset 96 returns: there ! you < @ here . our . domain . >
rewrite: ruleset 3 returns: there ! you < @ here . our . domain . >
rewrite: ruleset 2 input: there ! you < @ here . our . domain . >
rewrite: ruleset 2 returns: there ! you < @ here . our . domain . >
rewrite: ruleset 22 input: there ! you < @ here . our . domain . >
rewrite: ruleset 22 returns: there ! you
rewrite: ruleset 4 input: there ! you
rewrite: ruleset 4 returns: there ! you
Rcode = 0, addr = there!you
Here we try a UUCP address to examine what might be different.
This time, rule set 96 recognized
the
!
character as meaning this is a UUCP form of address.
That rule set recognizes that
localhost
is one of the names for the local
machine and converts the address to Internet form with your host's canonical
name (line
51
). Another difference is that rule set 22 is called
because that is the
R=
rule set for the
uucp
delivery agent.
That special rule set throws away the local host information, thus forming
a correct UUCP-style relative address (line
52
).
Internally, the
/try
rule-testing command
calls the
remotename
() routine, which can be watched with
the
-d12.1
debugging switch (see
Section 37.5.47, -d12.1
).