Rules would be pretty useless if they always had to match the workspace exactly. Fortunately, that is not the case. In addition to literal text, you can also use wildcard operators that allow the LHS of rules to match arbitrary text in the workspace. To illustrate, consider this rule:
R$+ rhs is here lhs
This LHS begins with the first character following the
The LHS in this example is
This is a wildcard operator.
The truth of this if statement is determined by a process called pattern
matching. The LHS
$+ (a single token) is a pattern that
"match one or more tokens."
The address that is being evaluated
is tokenized and placed into the workspace, and
then the workspace is compared to that pattern:
firstname.lastname@example.org tokenized into gw @ wash . dc . gov in the workspace
When matching the workspace to an LHS pattern, sendmail scans the
workspace from left to right. Each token in the workspace is compared
to the wildcard operator (the
$+) in the LHS pattern. If the tokens all match
the pattern, the if part of the if-then pair is true.
$+ wildcard operator simply matches any one or more tokens:
workspace pattern gw $+ match one token (``one'') @ and optionally more (``or more'') wash . dc . gov
As you can see, if there are any tokens in the address at all
(the workspace is not empty), the LHS rule
evaluates to true.
email@example.com $+ should match and does @wash.dc.gov $+ matches an incomplete address
To make matching in the LHS more effective, sendmail allows
other text to appear in the pattern.
To make sure that the address in the workspace
contains a user part, the
@ character, and a host part,
the following LHS pattern can be used:
Just like the address in the workspace, this pattern is tokenized
before it is compared for a match. Wildcard operators (like
count as one token, and
@ is a token because
it is a separator character:
@ you can change these ()<>,;\"\r\n you cannot change these
The pattern of
$+@$+ is separated into three tokens:
$+ @ $+
Text in the pattern must match text in the workspace exactly
(token for token) if there is to be a match. A good address in the
workspace (one containing a user part and a host part)
will match our new LHS (
workspace pattern gw $+ match one or more @ @ match exactly wash $+ match one . or more dc . gov
Here, the flow of matching begins with the first
which matches one token (of the one or more) in the workspace.
@ matches the
identical token in the workspace. At this point, the
part of the pattern has been satisfied. All that remains is
for the final
$+ to match its one or more of
all the remaining tokens in the workspace, which it does.
A bad address in the workspace, on the other hand, will not match the pattern. Consider an address, for example, that lacks a user part:
@wash.dc.gov in the workspace workspace pattern @ $+ match one wash or more . dc . gov @ match exactly (fails!) $+
Here, the first
$+ incorrectly matches
@ in the workspace. Since there is no other
@ in the workspace to be matched by the
in the pattern, the first
$+ matches the entire workspace.
Because there is nothing left in the workspace, the attempt
to match the
When any part of a pattern fails to match the workspace, the entire
LHS fails (the if part of the if-then is false).
One small bit of confusion may yet remain. When a wildcard operator such as
$+ is used to match the workspace, sendmail always
does a minimal match. That is, it matches only what it needs
for the next part of the rule to work.
Consider the following:
In this LHS the first
$+ matches everything
in the workspace up to the first
For example, consider the following workspace:
In the above,
$+@ causes the
$+ to match only the
characters up to the first
@ character, the
This is the minimum that needs to be matched, and so it is the maximum
that will be matched.
Take a moment to replace the previous demo rules with the following three new demo rules in the client.cf file:
S0 R@ one R@$+ two R$+@$+ three
Again, these three rules are for demonstration purposes only (you'll see how to declare a real one soon enough). We've given each temporary RHS a number to see whether it is selected. Now run sendmail in rule-testing mode:
./sendmail -Cclient.cf -btADDRESS TEST MODE (ruleset 3 NOT automatically invoked) Enter <ruleset> <address>
Now print the rules to remind yourself what they are:
=S 0R@ one R@ $+ two R$+ @ $+ three
We'll test those rules with an assortment of test addresses.
The first address to try is a lone
0 @rewrite: ruleset 0 input: @ rewrite: ruleset 0 returns: one
@ causes the first temporary
RHS to be selected because the rule is
The LHS here (the pattern to match) contains the lone
That pattern matches the tokenized workspace
so the RHS for that rule rewrites the workspace to contain
one does not contain an @ character, neither the second nor third
rules match, so the entire rule set returns
Next enter an address that just contains a host and domain part but not a user part:
0 @your.domainrewrite: ruleset 0 input: @ your . domain rewrite: ruleset 0 returns: two
The first thing to notice is what was not printed! The workspace does not match the pattern of the first rule. But instead of returning an error, the workspace is carried down as is to the next rule - where it does match:
@your.domain does not match, so ... R@ one try the next rule R@$+ two
Now enter an address that fails to match the first two rules but successfully matches the third:
0 firstname.lastname@example.org: ruleset 0 input: you @ your . domain rewrite: ruleset 0 returns: three
The flow for this address is
email@example.com does not match, so ... R@ one try the next rule, which also does not match, so ... R@$+ two try the next rule, which does match. R$+@$+ three
Try other addresses such as your login name or UUCP addresses such as firstname.lastname@example.org and host!you. Can you predict what will happen with weird addresses like @@ or a@b@c?