8.5 Complex Actions Made Simple
Beginning with V8.7 sendmail, rule-testing mode
offers six simple commands that accomplish complex tasks. They are
listed in Table 8-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 8-1 (such as /foo) will produce
an error:
Unknown "/" command /foo
8.5.1 Canonify a Host with /canon
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
(-d38.20) with the rule-testing
-d command (Section 8.7):
> -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
(ServiceSwitchFile). 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) and with the
-d8.2 debugging switch (-d8.2).
8.5.2 Look Up MX Records with /mx
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 (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), 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 -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> /mx a.com
getmxrr(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). If NAMED_BIND was not defined,
sendmail will print the following error instead
of listing MX records:
No MX code compiled in
8.5.3 Look up a Database Item with /map
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 (Section 23.2) or a name that
is internally defined by sendmail, such as
aliases.files (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 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.
8.5.3.1 The aliases database map
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)
8.5.3.2 The host map
The host database behaves the same as the
/canon command shown earlier. It looks up a
hostname by using sendmail's
internal host map (Section 23.4.3),
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)
8.5.3.3 The dequote map
The dequote map (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)
> /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.
8.5.4 Select Whom to /parse or /try with /tryflags
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]
8.5.5 Parse an Address with /parse
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) 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)
1 Cracked address = $g (Your Name)
2 Parsing envelope-recipient address
3 canonify input: you @ localhost
4 Canonify2 input: you < @ localhost >
5 Canonify2 returns: you < @ here . our. domain . >
6 canonify returns: you < @ here . our. domain . >
7 parse input: you < @ here . our. domain . >
8 Parse0 input: you < @ here . our. domain . >
9 Parse0 returns: you < @ here . our. domain . >
10 ParseLocal input: you < @ here . our. domain . >
11 ParseLocal returns: you < @ here . our. domain . >
12 Parse1 input: you < @ here . our. domain . >
13 Parse1 returns: $# local $: you
14 parse returns: $# local $: you
15 2 input: you
16 2 returns: you
17 EnvToL input: you
18 EnvToL returns: you
19 final input: you
20 final returns: you
21 mailer local, user you
The address you@localhost is first fed into
crackaddr (line 1)
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 1, which uses
$g as a place holder to show where the address was
found.
The next line (line 2) shows that the
address will be treated as that of an envelope recipient. The
/tryflags command (Section 8.5.4)
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
(Section 19.3) 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 4). 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 5).
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 7). 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 5).
Line 14 shows that the
$: part of the delivery agent
"triple" (Section 19.5) will eventually be tucked into
$u ($u) for use by the
delivery agent's A= equate (A=). 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 15). It is then given to rule set
EnvToL because the R= equate
(R=) for the local
delivery agent specifies rule set EnvToL for the
envelope recipient (line 17). Finally, it
is given to the final rule set 4 (Section 19.4) because all addresses are lastly rewritten by
the final rule set 4 (line 19).
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.edu
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
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. 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.
8.5.6 Try a Delivery Agent with /try
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
RFC2822-compliant (such as you@here.our.domain).
For UUCP addresses, this can 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 (Section 8.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 esmtp
1 canonify input: you
2 Canonify2 input: you
3 Canonify2 returns: you
4 canonify returns: you
5 2 input: you
6 2 returns: you
7 EnvToSMTP input: you
8 PseudoToReal input: you
9 PseudoToReal returns: you
10 MasqSMTP input: you
11 MasqSMTP returns: you < @ *LOCAL* >
12 EnvToSMTP returns: you < @ here . our . domain . >
13 final input: you < @ here . our . domain . >
14 final returns: you @ here . our . domain
15 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 canonify is called first (line 1) because all addresses are rewritten by it
first. Rule set 2 (line 5) is called
because all recipient addresses get rewritten by it. Rule set
EnvToSMTP (line 13) is
called because that rule set was indicated by the
esmtp delivery agent's
R= equate. That rule set detects that the
envelope-recipient address (you) is local (line 7). Rule set final
(always the last to rewrite) sees the special tag
*LOCAL* and converts that tag to the canonical
name of your local machine (line 11).
|