Complex Actions
Beginning with V8.7 sendmail, rule-testing mode offers six simple commands that accomplish complex tasks. They are listed in Table 38.1.
Command | Version | Description | |
---|---|---|---|
/canon
| and above | Canonify a host | |
/mx
| and above | Look up MX records | |
/map
| and above | Look up a database item | |
/tryflags
| and above | Select whom to /parse or /try | |
/parse
| and above | Parse an address | |
/try
| and above | 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 38.1 (such as /foo
) will produce an error:
Unknown "/" command /foo
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:
/canonhost
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 -d38.20) with the rule-testing -d
command (see "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 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 ) and with the -d8.2
debugging switch (see -d8.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:
/mxhost
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 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 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 ). It can be watched in huge detail with the -d8.20
debugging switch (see -d8.20).
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 (see "The K Configuration Command") or one that is internally defined by sendmail, such as aliases.files (see 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) returnsyou, 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 "$[ 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 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 ).
Select Whom to /parse or /try with /tryflags
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 hset 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:
[2] Internally, the
/tryflags
simply sets or clears the RF_HEADERADDR or RF_SENDERADDR flags. The meaning of these flags is documented in Table 37.10 (see -d24.4).
Usage: /tryflags [Hh|Ee][Ss|Rr]
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 (see $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 ) to separate it from any surrounding RFC822 comments (see -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 , which uses $g
as a place holder 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 (see ) 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 "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 ). 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 ).
The output of rule set 3 is passed to rule set 0 whose job is to select a delivery agent (line ). Because here.our.domain is the local machine, rule set 0 selects the local
delivery agent (line ).
Line shows that the $:
part of the delivery agent "triple" (see "Rule Set 0") will eventually be tucked into $u
(see ) for use by the delivery agent's A=
equate (see 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 ). It is then given to rule set 20 because the R=
equate (see R=) for the local
delivery agent specifies rule set 20 for the envelope recipient (line ). Finally, it is given to rule set 4 (see "Rule Set 4") because all addresses are lastly rewritten by 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, 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 "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 ). The selection of a delivery agent with parseaddr() can be watched with the -d20.1
debugging switch (see -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 -d24.5).
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 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:
/tryagent 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 ) 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 ) because all addresses are rewritten by it first. Rule set 2 (line ) 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 ). 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 ).
>/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 ). 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 ).
Internally, the /try
rule-testing command calls the remotename() routine, which can be watched with the -d12.1
debugging switch (see -d12.1).