19.5 The parse Rule Set 0The job of the parse rule set 0 is to select a delivery agent for each recipient. Beginning with V8.10 sendmail, it is declared like this: Sparse=0 As the name parse implies, the job of this rule set is to parse an address into important information so that the final form of delivery can be determined. The parse rule set 0 is called once for each recipient and must rewrite each into a special form called a triple. A triple is simply three pieces of information: the symbolic name of the delivery agent, the host part of the address, and the address to be passed to the delivery agent. Each part is indicated in the RHS by a special prefix operator, as shown in Table 19-1.
The triple is formed by rewriting with the RHS. It looks like this: $#delivery_agent $@ host $: address
The delivery agent selection must be the first of the three. In addition to specifying the delivery agent, $# also causes the parse rule set 0 to exit. The other two parts of the triple must appear in the order shown ($@ first, then $:). All three parts of the triple must be present in the RHS. The only exception is the $@ host part when the delivery agent has the F=l flag set. It can be present for V8 sendmail but must be absent for all other versions of sendmail. Not all rules in the parse rule set 0 are specifically used to select a delivery agent. It might be necessary, for example, to canonicalize an address with the $[ and $] operators (Section 18.7.6) before being able to decide whether the address is local or remote. If an address passes through the parse rule set 0 without selecting a delivery agent, the following error message is produced, and the mail message bounces: 554 5.3.5 buildaddr: no mailer in parsed address Here, no mailer means that a delivery agent was not selected by the parse rule set 0.[4] Therefore, it is important to design a parse rule set 0 that selects a delivery agent for every legitimate address.
If a triple is missing the address part (the $:), the following error is produced: 554 5.3.5 buildaddr: no user If the delivery agent that is selected is one for which there is no corresponding M configuration file declaration, the following error is produced: 554 5.3.5 buildaddr: unknown mailer bad delivery agent name here See LOCAL_RULE_0 (Section 4.3.3.2) for a way to add rules to the parse rule set 0. 19.5.1 Further Processing: $:addressThe address part of the triple is intended for use in the command line of the delivery agent and in the RCPT command in an SMTP connection. For either use, that address is rewritten by rule set 2 (if there is one), the R= equate of the delivery agent, and the final rule set 4, as illustrated in Figure 19-5. This means that the address part can be in focused form because the focus is later removed by the final rule set 4. But the address part must be a single username (no host) for some local delivery agents. The rewritten result is stored for use when a delivery agent's $u in A= (A=) argument is expanded. For example, for the local delivery agent, the rewritten result is the username as it will be given to /bin/mail for local delivery. Figure 19-5. The flow of $:address through rule setsThe rewritten result is also given to a remote site during the exchange of mail using the SMTP protocol. The local machine tells the remote machine the name of the recipient by saying RCPT TO: followed by the rewritten address portion of the triple. 19.5.2 Selecting S= and R=When it selects a delivery agent, the parse rule set 0, indirectly through that delivery agent, selects the rules that will be used in rewriting sender and recipient addresses. A sender address is rewritten by the rule set specified by the S= equate (S=). The recipient addresses are rewritten by the rule set specified by the R= equate (R=). If the R= or S= specifies a zero or if either is undeclared, that portion of rewriting is skipped. We won't cover individual R= or S= rule sets here because they depend on the individual needs of delivery agents. Instead, we recommend that you examine how your configuration file uses them. You'll probably be surprised to find that many R= and S= equates reference nonexistent rules (which means that sendmail will do no rewriting). 19.5.3 Delivering to Local RecipientTypically, some early rules in the parse rule set 0 are intended to detect addresses that should be delivered locally. A rule that accomplishes that end might look like this: R $+ <@ $w> $#local $:$1 local address Here, the $w sendmail macro is the name of the local host. Note that the RHS strips the focused host part from the username. At some sites, the local host can be known by any of several names. A rule to handle such hosts would begin with a class declaration that adds those names to the class w (such as in the first line here): Cw font-server fax printer3 R $+ <@ $=w> $#local $:$1 local address The class w is special because it is the one to which sendmail automatically appends the alternative name of the local host. This class declaration line adds names that sendmail might not automatically detect. Usually, such a declaration would be near the top of the configuration file rather than in the parse rule set 0, but technically it can appear anywhere in the file. This rule looks to see whether an address contains any of the names in class w. If it does, the $=w in the lefthand side (LHS) matches, and the RHS selects the local delivery agent. On central mail-server machines, the parse rule set 0 might also have to match from a list of hosts for which the central server is an MX recipient machine (FEATURE(use_cw_file)). 19.5.4 Forwarding to a Knowledgeable HostAfter handling mail destined for the local host, the parse rule set 0 generally looks for addresses that require a knowledgeable host to forward messages on the local host's behalf. In the following rule, the $B sendmail macro ($B) holds as its value the name of a machine that knows how to deliver BITNET mail (Section 4.5): R $* <@ $+.BITNET> $* $#esmtp $@$B $:$1<@$2.BITNET>$3 user@host.BITNET The tag .BITNET would have been added by users when sending mail. Note that BITNET in the LHS is case-insensitive; a user can specify Bitnet, bitnet, or even BiTNeT, and this rule will still match. A similar scheme can be used for other specialty addresses, such as UUCP and DECnet. 19.5.5 Handling UUCP LocallyHosts sometimes deliver mail to a few UUCP connections locally and forward to other UUCP connections through a knowledgeable host. The rules that handle this situation often make use of another class: R $* <@ $=V . UUCP> $#uucp $@ $2 $: $1 user@localuucp R $* <@ $+ . UUCP> $#esmtp $@ $Y $: $1<@ $2 . UUCP> kick upstairs Here, the class $=V contains a list of local UUCP connections. They are matched by the first rule, which selects the uucp delivery agent. All other UUCP addresses are passed to the knowledgeable host in $Y ($Y). The user part ($:) that is given to the knowledgeable host is the original address as it appeared to the LHS. 19.5.6 Forwarding over the NetworkNext, the parse rule set 0 typically sees whether it can send the mail message over the network. In the following example we assume that the local host is connected to an IP network: # deal with other remote names R $* <@ $*> $* $#esmtp $@ $2 $: $1 < @ $2> $3 user@host.domain Remember that we have already screened out and handled delivery to the local host, and therefore the focused host (in the <@$* > of the LHS) is on the network. The esmtp delivery agent is selected (to deliver using the SMTP protocol), with connection to be made to $2 (the $* part of the <@$* > in the LHS). The focus is kept in the user portion of the RHS triple. Remember that the user portion will be rewritten by rule set 2 (if there is one), R= rule set (if there is one), and the final rule set 4. Also remember that the final rule set 4 will defocus the address. We keep the focus here because rule set 2 and all R= rules (if present) expect the host part of addresses to be focused. 19.5.7 Handling Leftover Local AddressesWhatever is left after all preceding rules in the parse rule set 0 have selected delivery agents is probably a local address. Here, we check for a username without a host part: R $+ $#local $:$1 regular local names Notice that the user part is not focused; it is unfocused because there is no host part on lone local usernames. |