Chapter 29

# 29. Rule Sets

Rule sets in the configuration file, like subroutines in a program, control the sequence of steps sendmail uses to rewrite addresses. Inside each rule set is a series of zero or more individual rules. Rules are used to select the appropriate delivery agent for any particular address, to detect and reject addressing errors, and to transform addresses to meet particular needs.

In this chapter we will cover all aspects of rule sets, showing that rule sets are called in particular orders and explaining why this is so.

We will explain many of the rules that typically appear in rule sets. But be forewarned: The examples of rules in this chapter are explanatory only. Your sendmail.cf file is likely to have rules that are somewhat different from these examples. Copying or using these examples, without first understanding the underlying principles, can cause email to begin to fail.

## 29.1 The S Configuration Command

The `S` configuration command declares the start of a rule set. It is perhaps the simplest of all configuration commands and looks like this:

`S`ident``

The `S`, like all configuration commands, must begin the line. The `ident` identifies the rule set. There may be whitespace between the `S` and the `ident`. If the `ident` is missing, sendmail prints the following error message and skips that particular rule set declaration:

`/etc/sendmail.cf: line `num`: invalid ruleset name: ""`

Prior to V8.7 sendmail the `ident` could only be numeric. Beginning with V8.7 sendmail the `ident` may be numeric or alphanumeric. We cover the old form first, then the new.

### 29.1.1 Rule-Set Numbers

Prior to V8.7 sendmail, rule sets could be identified only by numbers. When a rule set is declared with an integer, that integer is taken to be the numeric identity of the rule set:

`S`#``

Here, `#` is an integer such as 23. If the `#` is greater than half [1] the maximum number of rule sets allowed (MAXRWSETS in conf.h) or is negative, sendmail syslog(3)'s the following error message at the level LOG_CRIT and defaults the rule set to 0:

[1] The reason for this will become clear shortly.

`bad ruleset `#` (`n` max)`

Here, the `#` is the bad rule-set number from the configuration file, and `n` is the maximum allowable rule-set number (the value of MAXRWSETS/2). By default, the maximum value for `#` is 99.

### 29.1.2 Rule-Set Names

Beginning with V8.7 sendmail, rule sets may be declared with numbers (as above) or with more meaningful names. The form for a rule-set name declaration looks like this:

`S`name``

The name may contain only ASCII alphanumeric characters and the underscore character. Any bad character causes that character and the characters following it to be silently ignored:

```My_rule             good
My rule             bad, name is ``My''```

Case is recognized; that is, `Myrule` and `MYRULE` are different names. You may use any name that begins with an uppercase letter. Names that begin with a lowercase letter or an underscore character are reserved for internal use by sendmail.

There may be at most MAXRWSETS/2 named rule sets (where MAXRWSETS is defined in conf.h). Each rule set that is declared beyond that amount causes sendmail to print the following error and ignore that rule-set declaration:

``name`: too many named rulesets (`#` max)`

When you declare a rule set name, sendmail associates a number with it. That number is selected by counting down from MAXRWSETS. That is, the first name is given the number MAXRWSETS-1, the second is given the number MAXRWSETS-2, and so on. Named rule sets may be used anywhere that numbered rule sets can be used.

### 29.1.3 Associate Number with Name

When knowing the number associated with a named rule set is of importance, you can associate a number with a name when the name is declared. The form of such a combined declaration looks like this:

`S`name`=`num``

Here, the rule set named `name` is declared. Instead of sendmail associating a number with it, you create the association by following the `name` with an `=` character and then an integer `num`. Arbitrary whitespace may surround the `=` character. If the integer is missing or non-numeric, sendmail prints the following error and skips that rule-set declaration:

`/etc/sendmail.cf: line `num`: bad ruleset definition "`bad`" (number required after `=')`

Although it is ugly, different names may share the same number:

```Sfoo=1
Sfee=1```

However, the same name may not be given a different number. Consider the following example:

```SMyrule=1
SMyrule=2```

This causes sendmail to print the following error and skip the second declaration:

`/etc/sendmail.cf: line `num`: Myrule: ruleset changed value (old 1, new 2)`

Named rule sets have numbers associated with them when they first appear. If you use a named rule set in an `S=` equate for a delivery agent and then later attempt to assign it a value, you will get an error like the above:

```Mprog, P=sh, ...., S=`Myrule`, ...
...
S`Myrule`=2```

The solution is either to move the rule-set declaration (and its rules) so that they reside above the delivery agent declaration or to declare a numeric association in the delivery agent declaration instead of in the rule-set declaration:

```Mprog, P=sh, ...., S=`Myrule=2`, ...
...
S`Myrule````

or to place just the `S` line above the delivery agent declaration and the rules, without the `=2`, below it:

```S`Myrule=2`
Mprog, P=sh, ...., S=`Myrule`, ...
...
S`Myrule````

In general, we recommend that you assign numbers to named rule sets only if there is a genuine need.

### 29.1.4 Macros in Rule-Set Names

Macros may be used in any or all of a part of a rule-set declaration. They may be used to declare a name:

```D{NAME}myname
S\${NAME}```

or to declare a number:

```D{NUMBER}12
S\${NUMBER}```

or both a name and a number:

```D{NAME}myname
D{NUMBER}12
S\${NAME}=\${NUMBER}```

or even the whole thing:

```D{SET}myset=12
S\${SET}```

You may use single- and multicharacter macros in any combination. Macros may be used in any rule-set declaration, including subroutine calls inside rules:

`R\$* < \$=w > \$*       \$@ \$>\${NAME} \$2`

But they may not be used in the `S=` or the `R=` of delivery agents:

```Mprog, P=sh, ..., S=\$X, R=\$X, ...

neither of these will work```

Macros can be used in the command line to modify a configuration file when sendmail is run. Consider the desire to call one rule set when running as a daemon and another when processing the queue. You might declare such a rule like:

`R\$* < @ \$+ > \$*     \$@ \$>`\$A` \$2`

The two different runs might look like this:

```# /usr/lib/sendmail -MAdaemon_rule -bd
# /usr/lib/sendmail -MAqueue_rule -q30m```

The first defines the `\$A` macro to have the value `daemon_rule` and results in this subroutine call:

`R\$* < @ \$+ > \$*     \$@ \$>`daemon_rule` \$2`

The second defines the `\$A` macro to have the value `queue_rule` and results in this different subroutine call:

`R\$* < @ \$+ > \$*     \$@ \$>`queue_rule` \$2`

Note that you cannot define multi character macros from the command line. Also note that defining macros from the command line can result in sendmail giving up its root privilege.

### 29.1.5 Rule Sets and Lists of Rules

All rules (`R` lines) that follow a rule-set declaration are added to and become part of that rule set:

```S0
R...           rules added to rule set 0
SMyset
R...           rules added to rule set Myset
S1
R...           rules added to rule set 1```

Rule sets need not be declared in any particular order. Any order that clarifies the intention of the configuration file as a whole is acceptable. If a rule set appears more than once in a configuration file, V8 sendmail will print a warning:

```WARNING: Ruleset `name` redefined                 Prior to V8.8
WARNING: Ruleset `name` has multiple definitions  V8.8```

and append the new rules to the old:

```S0
R...           rules added to rule set 0
S2
R...           rules added to rule set 2
S0             warning issued
R...           rules appended to earlier rule set 0```

Note that the warning is given in all cases prior to V8.8, but beginning with V8.8, it is issued only in `-bt` rule-testing mode or if the `-d37.1` debugging switch is set.

Other configuration commands may be interspersed among rule definitions without affecting the rule set to which the rules are added:

```S0
R...           rules added to rule set 0
Pjunk=-100
DUuucphost.our.domain
R...           rules added to rule set 0```

Any rules that appear before the first `S` command are added to rule set 0 by default:

```R...           rules added to rule set 0
S1             first S command in configuration file
R...           rules added to rule set 1```

### 29.1.6 Odds and Ends

Arbitrary text that follows a rule set declaration is ignored unless it appears to be part of the declaration:

```S11 100 more rule sets      rule set 11
S11100 more rule sets       rule set 11,100 is illegal
SMyset 100 more rule sets   rule set Myset```

Although the first and last of the above examples work, we recommend that you use the `#` commenting mechanism instead:

```S11 #100 more rule sets      rule set 11
S11#100 more rule sets       rule set 11
SMyset #100 more rule sets   rule set Myset```

A rule-set declaration that has no rules associated with it is exactly the same as a rule set that is not declared. Both are like do-nothing subroutines:

```              rule set 1 not declared. Same as
S2            rule set 2 without rules
S3
R...```

 28.7 Pitfalls 29.2 Rule Sets and m4