Chapter 17. Configure sendmail.cf with m4

V8 sendmail provides an easy way to create a custom configuration file for your site. In the cf subdirectory of the V8 sendmail source distribution you will find a file named README. It contains easy-to-understand, step-by-step instructions that allow you to create a custom configuration file for your site. This chapter supplements that file.

The m4 Preprocessor

Creating a configuration file with m4(1) is simplicity itself. The m4(1) program is a macro preprocessor that produces a sendmail configuration file by processing a file of m4 commands. Files of m4 commands traditionally have names that end in the characters .m4 (the same as files used for building the sendmail binary). For building a configuration file, the convention is to name a file of m4 commands with an ending of .mc (for macro configuration). The m4 process reads that file and gathers definitions of macros, then replaces those macros with their values and outputs a sendmail configuration file.

With m4, macros are defined (given values) like this:

define(macro, value)

Here, the macro is a symbolic name that you will use later. Legal names must begin with an underscore or letter and can contain letters, digits, and underscores. The value can be any arbitrary text. A comma separates the two, and that comma can be followed by optional whitespace.

There must be no space between the define and the left parenthesis. The definition ends with the right parenthesis.

To illustrate, consider this one-line m4 source file named /tmp/x:

input text to be converted
            ↑
 define(A,B)A
  ↑
 the m4 definition

When m4 is run to process this file, the output produced shows that A (the input) is redefined to become B:

% m4 /tmp/x
B

m4 Is Greedy

The m4 program is greedy. That is, if a macro is already defined, its value will replace its name in the second declaration. Consider this input file:

define(A,B)
define(A,C)
A B

Here, the first line assigns the value B to the macro named A. The second line notices that A is a defined macro, so m4 replaces that A with B and then defines B as having the value C. The output of this file, after processing with m4, will be:

C C

To prevent this kind of greedy behavior (and to prevent the confusion it can create), you can quote an item to prevent m4 from interpreting it. You quote with m4 by surrounding each item with left and right single quotes:

define(A,B)
define(`A',C)
A B

Here, the first line defines A as B like before. But the second line no longer sees A as a macro. Instead, the single quotes allow A to be redefined as C. So, the output is now:

C B

Although it is not strictly necessary, we recommend that all macro and value pairs be quoted. The preceding line should generally be expressed like this:

define(`A',`B')
define(`A',`C')
A B

This is the form we use when illustrating m4 throughout this book, including in the previous two chapters.

m4 and dnl

Another problem with m4 is that it replaces its commands with empty lines. The earlier define commands, for example, will actually print like this:

a blank linea blank line
 C B

To suppress this insertion of blank lines, you can use the special m4 command dnl (for Delete through New Line). That command looks like this:

define(`A',`B')dnl
define(`A',`C')dnl
A B

You can use dnl to remove blank lines where they might prove inconvenient or unsightly in a configuration file.

The dnl command can also be used to put comments into an mc file. Just be sure to put a blank line after the last dnl because each dnl gobbles both the text and the newline:

dnl This is a comment.
                       ← note the extra blank line

m4 and Arguments

When an m4 macro name is immediately followed by a left parenthesis, it is treated like a function call. Arguments given to it in that role are used to replace $digit expressions in the original definition. For example, suppose the m4 macro CONCAT is defined like this:

define(`CONCAT',`$1$2$3')dnl

and then later used like this:

CONCAT(`host', `.', `domain')

The result will be that the host will replace $1, the dot will replace $2, and the domain will replace $3, all jammed tightly together just as `$1$2$3' were:

host.domain

Macro arguments are used to create such techniques as FEATURE( ) and OSTYPE( ), which are described later in this chapter.

The DOL m4 Macro

Ordinarily, the $ character is interpreted by m4 as a special character when found inside its define expressions:

define(`A', `$2')
             ↑
      the $ makes $2 an m4 positional variable

There might be times, however, when you might want to put a literal $ character into a definition—perhaps when designing your own DOMAIN, FEATURE, or HACK files.

You place a literal $ into a definition with the DOL m4 macro. For example:

define(`DOWN', `R DOL(*) < @ $1 > DOL(*)    DOL(1) < @ $2 > DOL(2)')

Here, we define the m4 macro named DOWN, which takes two arguments ($1 and $2). Notice how the $ character has meaning to m4. This newly created DOWN macro can then be used in one of your .m4 files, perhaps like this:

DOWN(badhost,  outhost)

DOWN creates a rule by substituting the argument (badhost for the $1 in its definition, and outhost) for the corresponding $2. The substitution looks like this:

R DOL(*)    becomes ←   R $*
< @ $1 >    becomes ←   < @ badhost >
DOL(*)      becomes ←   $*
DOL(1)      becomes ←   $1
< @ $2 >    becomes ←   < @ outhost >
DOL(2)      becomes ←   $2

After substitution, the following new rule is the result:

R $* < @ badhost > $*       $1 < @ outhost > $2

The DOL m4 macro allowed the insertion of $ characters (such as $*) and protects you from having the literal use of $ characters being wrongly interpreted by m4.

Needless to say, you should never redefine the DOL m4 macro.

Configure with m4

The process of building a sendmail configuration file begins by creating a file of m4 statements. Traditionally, the suffix for such files is .mc. The cf/cf directory contains examples of many .mc files. Of special interest are those that begin with generic, for these can serve as boilerplates in developing your own .mc files:

generic-bsd4.4.mc    generic-mpeix.mc        generic-sunos4.1.mc
generic-hpux10.mc    generic-nextstep3.3.mc  generic-ultrix4.mc
generic-hpux9.mc     generic-osf1.mc
generic-linux.mc     generic-solaris.mc

All .mc files require specific minimal statements. For a SunOS 4.1.4 site on the Internet, for example, the following are minimal:

OSTYPE(sunos4.1)dnl         ← see §17.2.2.1 on page 590
MAILER(local)dnl            ← see §17.2.2.2 on page 590
MAILER(smtp)dnl             ← see §17.2.2.2 on page 590

To build a configuration file from these statements, you would place them into a file—say, localsun.mc—and then run the following command:

% ./Build localsun.cf
Using M4=/usr/5bin/m4
rm -f localsun.cf
/usr/5bin/m4 ../m4/cf.m4 localsun.mc > localsun.cf || ( rm -f localsun.cf && exit 1 )
chmod 444 localsun.cf

Here, you run the Build[235] script found in the cf/cf directory. You pass it the name of your mc file with the “.mc” suffix changed to a “.cf” suffix. The Build script uses m4 to expand your mc file into a full-fledged configuration file.

Another way to build a configuration file is by running m4 by hand:

% m4  ../m4/cf.m4 localsun.mc >  sendmail.cf

Here, the ../m4/cf.m4 tells m4 where to look for its default configuration file information.

If you are using an old version of m4, the following error message will be printed:

You need a newer version of M4, at least as new as
System V or GNU
m4: file not found: NoSuchFile

Just as the message says, you need a newer version of m4. (The third line is just a result of forcing m4 to fail and can be safely ignored.) Thus, we would need to rerun our second localsun.mc example (earlier) as:

% /usr/5bin/m4  ../m4/cf.m4 localsun.mc >  sendmail.cfSystem V version of m4

Another cause of failure could be that the ../m4/cf.m4 file was not where you thought it was. Various versions of m4 print this error in different ways:

/usr/5bin/m4:-:1 can't open file                 ← SysV m4
m4: ../m4/cf.m4: No such file or directory       ← GNU m4
m4: file not found: ../m4/cf.m4                  ← BSD m4

One possible reason for this error might be that you are developing your .mc file somewhere other than in the cf/cf directory.[236] The solution is to use a full pathname to cf.m4 or to replace that expression on the command line with a shell variable.

After you have successfully produced a “first draft” of your configuration file, you can edit localsun.mc and add features as you need them. Many possibilities are described in the rest of this chapter.

The _CF_DIR_ m4 Macro

It can be advantageous to maintain all the files that make up your local m4 configuration separately from the sendmail distribution. This prevents new releases of sendmail from clobbering your source files. It also allows you to maintain configuration information more conveniently (perhaps under rcs(1) control) and to use programs such as make(1) to simplify configuration and installation.

Most modern versions of m4 allow you to define m4 macros on the command line, and one such m4 macro is recognized internally by the m4 technique:

_CF_DIR_

This command-line m4 macro tells m4 where the m4/cf.m4 file described earlier is located. It needs to have its value set to be the cf directory under the sendmail source distribution, and it needs to end in a slash character. For example, GNU m4 version 1.2 allows this:

% setenv CFDIR /usr/local/src/mail/sendmail/cf/
% /usr/local/gnu/bin/m4 -D_CF_DIR_=${CFDIR} ${CFDIR}m4/cf.m4 localsun.mc \
    > sendmail.cf

Notice that we store the value for _CF_DIR_ in an environment variable. Note that GNU m4 can figure out the _CF_DIR_ path itself from the path of the cf.m4 file. We include _CF_DIR_ here merely as an example. If your version of m4 lacks this ability, you should consider upgrading.

With the _CF_DIR_ m4 macro, we can further simplify configuration and installation by using make(1). To illustrate, consider the following few lines from a Makefile on a SunOS system:

M4=/usr/local/gnu/bin/m4
CFDIR=/usr/local/src/mail/sendmail/cf/
localsun: localsun.mc
        $(M4) -D_CF_DIR_=$(CFDIR) $(CFDIR)/m4/cf.m4 localsun.mc > sendmail.cf

With this Makefile the two complex command lines shown earlier are reduced to a single, simple command line:

% make

The Minimal mc File

Every mc file requires minimal information. Table 17-1 shows which m4 items are required and lists two that are recommended. We show them in the order that they should be declared (OSTYPE first and MAILER last), and then describe the mandatory and recommended information.

Table 17-1. Required and recommended m4 items

Item

Section

 

Description

OSTYPE( )

OSTYPE( ) m4 macro on page 590

Required

Support for your operating system

DOMAIN( )

DOMAIN( ) m4 macro on page 591

Recommended

Common domain-wide information

FEATURE( )

FEATURE( ) m4 macro on page 592

Recommended

Solutions to special needs

MAILER( )

MAILER( ) m4 macro on page 590

Required

Necessary delivery agents

Note that what is minimally required for a workstation differs from what is minimally required for a central mail server. We suggest that you use these recommendations as a jumping-off point and then investigate all the m4 macros and features that are available.

OSTYPE( ) m4 macro

Support for various operating systems is supplied with the OSTYPE m4 command. Every .mc file must declare the operating system with this command, and this command must be the first in your mc file.[237] The available support is supplied by files in the _CF_DIR_/ostype directory. A listing of those files looks something like this:

a-ux.m4         bsdi2.0.m4     hpux9.m4        openbsd.m4       solaris2.ml.m4
aix3.m4         darwin.m4      irix4.m4        osf1.m4          solaris2.pre5.m4
aix4.m4         dgux.m4        irix5.m4        powerux.m4       solaris8.m4
aix5.m4         domainos.m4    irix6.m4        ptx2.m4          sunos3.5.m4
altos.m4        dynix3.2.m4    isc4.1.m4       qnx.m4           sunos4.1.m4
amdahl-uts.m4   freebsd4.m4    linux.m4        riscos4.5.m4     svr4.m4
bsd4.3.m4       freebsd5.m4    maxion.m4       sco-uw-2.1.m4    ultrix4.m4
bsd4.4.m4       gnu.m4         mklinux.m4      sco3.2.m4        unixware7.m4
bsdi.m4         hpux10.m4      mpeix.m4        sinix.m4         unknown.m4
bsdi1.0.m4      hpux11.m4      nextstep.m4     solaris2.m4      uxpds.m4

To include support, select the file that best describes your operating system, delete the .m4 suffix from its name, and include the resulting name in an OSTYPE declaration:

OSTYPE(`ultrix4')

Here, support for the DEC Ultrix operating system is defined. Note that some of these are not entirely accurate. For example, ultrix4.m4 includes support for Ultrix versions 4.2 and 4.3, and sunos4.1.m4 includes support for SunOS versions 4.1.2, 4.1.3, and 4.1.4.

If you pick a name for which no file exists, or if you misspell the name of the file, an error similar to the following will print:

m4: Can't open ../ostype/ultrux4.1.m4: No such file or directory

If you omit the OSTYPE declaration entirely, you will get the following error:

*** ERROR: No system type defined (use OSTYPE macro)

MAILER( ) m4 macro

Delivery agents are not automatically declared. Instead, you must specify which ones you want to support and which ones you want to ignore. Support is included by using the MAILER definition:

MAILER(`local')

This causes support for both the local and the prog delivery agents to be included. This is the minimal declaration (even if you don’t intend to perform local or program delivery).

The MAILER definition must always be last in your mc configuration file.[238] If you include MAILER definitions for procmail(1), maildrop(1), or uucp, those definitions must always follow the definition for smtp. Any modification of a MAILER definition (as, for example, with LOCAL_MAILER_MAX) must precede that MAILER definition:

define(`LOCAL_MAILER_MAX', `1000000')           ← here
MAILER(`local')
define(`LOCAL_MAILER_MAX', `1000000')           ← not here

A minimal mc file for an average machine on the Internet would contain two MAILER definitions:

MAILER(`local')
MAILER(`smtp')

The first you have already seen. The second includes support for sending email to other hosts on the Internet. If this minimal mc is all you think you’ll need, you can continue on to the rest of this chapter. If, on the other hand, you expect to support any variations on mail receipt and delivery beyond the basics, you should leap ahead to Chapter 20, study that chapter, and then return here. (See Table 20-1 on page 717 for a list of all the available delivery agents.)

All delivery agent equates, such as F= and M=, can be modified with the .m4 configuration technique. Table 20-18 on page 736 lists all the equates and shows where to find further information about each of them. By investigating those sections, you can discover how to tune particular equates with the m4 technique. For example, the following mc lines define the program used for local delivery to be mail.local:

FEATURE(`local_lmtp')
define(`LOCAL_MAILER_PATH', `/usr/local/bin/mail.local')
MAILER(local)

Note that all modifications to equates must precede the corresponding MAILER( ) definition.

DOMAIN( ) m4 macro

For large sites it can be advantageous to gather into a single file all configuration decisions that are common to the entire domain. The directory to hold domain information files is called domain. The configuration information in those files is accessed by using the DOMAIN( ) m4 technique. For example:

DOMAIN(`uofa.edu')

This line in any of your mc files causes the file domain/uofa.edu.m4 to be included at that point. Examples that come with the distribution illustrate subdomains under Berkeley.EDU. One boilerplate file, named generic.m4, can be used as a starting point for your own domain-wide file. For example, if all hosts at your site masquerade behind one email name, you might want to put MASQUERADE_AS (MASQUERADE_AS mc Macro on page 600) in your domain file. Domain files also form a natural location for the definition of site-specific relays (Relays on page 602).

If the domain that is specified does not exist or is misspelled, an error similar to the following will be printed:

m4: Can't open ../domain/generik.m4: No such file or directory

The use of DOMAIN( ) is not mandatory but is recommended. Note that problems can arise because the items inside your domain file will determine where the DOMAIN( ) declaration must go in the mc file. If, for example, the domain file contains MAILER( ) definitions, DOMAIN( ) should appear near the end of the mc file with the MAILER( ) definitions. If the domain file contains rules and rule sets, the DOMAIN( ) must be last in the mc file, but if the domain file contains OSTYPE( ), DOMAIN( ) must be first in the mc file. So, consider well what you place in your domain file. Avoid defining anything in your domain file that restricts where the DOMAIN( ) definition must go in your mc file.

In the event that your domain file contains many position-dependent commands, such as rule sets and an OSTYPE( ) command, you might need to split that file into pieces. You can split it something like this:

DOMAIN(`our.domain.sun')
DOMAIN(`our.domain.rules')

Here, the first line causes the file our.domain.sun.m4 to be read. That file contains the OSTYPE( ) declaration for all your Sun workstations. This DOMAIN( ) entry would appear at the top of your mc file.

The second line causes the file our.domain.rules.m4 to be read. That file might contain antispam rule sets. This second DOMAIN( ) entry would appear near the end of your mc file, perhaps under LOCAL_RULESETS.

FEATURE( ) m4 macro

V8 sendmail offers a number of features that you might find very useful. To use a feature, include an m4 command such as one of the following in your mc file:

FEATURE(keyword)
FEATURE(keyword,  argument)
FEATURE(keyword,  argument,   argument,  ... etc.)

These declarations cause a file of the name feature/keyword.m4 to be read at that place in your mc file. The available keyword files are summarized in Table 17-7 on page 612, and each is explained in the section at the end of this chapter. Note that some keywords require additional arguments.

The Order of mc Lines

As you have seen, some mc lines must precede others. This is necessary partly because m4(1) is a one-pass program, and partly because the order of items in the final sendmail.cf file is also critical. The recommended order is:

VERSIONID( )           ← see §17.2.3.1 on page 593
OSTYPE( )              ← see §17.2.2.1 on page 590
DOMAIN( )             ← see §17.2.2.3 on page 591
option definitionssee §24.4 on page 953
FEATURE( )            ← see §17.8 on page 611
macro definitionssee §21.7 on page 796
MAILER( )              ← see §17.2.2.2 on page 590
ruleset definitionssee §19.1.7 on page 688

If in doubt about where some particular item should go, look in the many example files in cf/cf. Some of them (especially the file knecht.mc) will also give you good ideas about how you can improve your own mc file.

VERSIONID m4 macro

The VERSIONID m4 macro is used to insert an identifier into each mc and m4 file that becomes a part of your final .cf file. Each file that is supplied with sendmail already has such an identifier. You should include a similar identifier in each of your mc files:

VERSIONID(`$Id$')

Here, the VERSIONID m4 macro is used to insert an RCS-style revision number. The $Id$ becomes an actual version number when the file is checked in with ci(1). Arbitrary text can appear between the single quotes. You can use RCS, SCCS, or any other kind of revision identification system. The text cannot contain a newline because the text appears in the .cf file as a comment:

#####  $Id$ #####

Use of VERSIONID and revision control in general is recommended.

HACK( ) m4 macro

Some things just can’t be called features. To make this clear, they go in the hack directory and are referenced using the HACK m4 macro. They tend to be site-dependent:

HACK(`cssubdomain')

This illustrates use of the Berkeley-dependent cssubdomain hack (that makes sendmail accept local names in either Berkeley.EDU or CS.Berkeley.EDU).

Another way to think of a hack is as a transient feature. Create and use HACK as a temporary solution to a temporary problem. If a solution becomes permanent, move it to the FEATURE directory and reference it there.

m4 Macros by Function

The m4 technique uses a huge number of macros to accomplish the complex task of creating configuration files for all possible circumstances. Many are detailed in the reference section at the end of this chapter. Many others are documented in chapters dedicated to particular subjects. Here, we summarize many of the m4 macros by classification or function. Note that a comprehensive list of all m4 macros is available in Appendix A on page 1227.

Options

Options can be set, unset, and changed in your mc file with simple define statements. For example, the following line sets the location of the aliases file and thus the AliasFile option:

define(`ALIAS_FILE', `nis:-N mail.aliases')

Configuring options with the m4 technique is described in Options in the mc File on page 953 (with the individual m4 option names listed in Table 24-3 on page 953). Options are described in general in Chapter 24 on page 947. We recommend that you leap ahead to that chapter, learn about options that will make your use of sendmail more valuable, and then return here.

Define sendmail Macros

Defined sendmail macros can be declared in your mc file. Those that are useful are listed in Table 21-5 on page 796. That section also describes the general technique of defining sendmail macros via m4. To illustrate, for example:

define(`BITNET_RELAY', `host.domain')

causes the value host.domain to be assigned to an internal sendmail macro (currently $B). Non-m4-specific defined macros can be declared with the LOCAL_CONFIG technique (LOCAL_CONFIG mc macro on page 595).

Rules and Rule Sets

Rules are used to rewrite mail addresses and to select delivery agents, among other things. They are organized in rule sets, which can be thought of as subroutines. We deal with rules and rule sets more deeply in Chapter 18 on page 648 and Chapter 19 on page 683. Here we only illustrate how the mc configuration method is used to insert custom rules and rule sets in a variety of convenient ways. We list all the mc keywords that affect rules and rule sets in Table 17-2. For completeness, we also list one keyword for adding delivery agents.

Table 17-2. mc configuration keywords

Keyword

§

Versions

Description

LOCAL_CONFIG

LOCAL_CONFIG mc macro on page 595

V8.1 and later

Add general information.

LOCAL_NET_CONFIG

LOCAL_NET_CONFIG mc macro on page 598

V8.6 and later

Add custom rules for SMART_HOST.

LOCAL_RULE_0

LOCAL_RULE_0 mc macro on page 596

V8.1 and later

Add custom rules to the parse rule set 0.

LOCAL_RULE_1

LOCAL_RULE_1 and LOCAL_RULE_2 mc macros on page 596

V8.1 and later

Add custom rules to rule set 1.

LOCAL_RULE_2

LOCAL_RULE_1 and LOCAL_RULE_2 mc macros on page 596

V8.1 and later

Add custom rules to rule set 2.

LOCAL_RULE_3

LOCAL_RULE_3 mc macro on page 596

V8.1 and later

Add custom rules to the canonify rule set 3.

LOCAL_RULESETS

LOCAL_RULESETS mc macro on page 597

V8.8 and later

Group local rules with others.

LOCAL_SRV_FEATURES

srv_features on page 708

V8.12 and later

Add/create rules for the srv_features rule set.

LOCAL_TRY_TLS

Disable STARTTLS with the try_tls rule set on page 217

V8.12 and later

Add custom rules to the try_tls rule set.

LOCAL_TLS_CLIENT

The access database with tls_server and tls_client on page 214

V8.12 and later

Add custom rules to the tls_client rule set.

LOCAL_TLS_RCPT

The tls_rcpt rule set on page 215

V8.12 and later

Add custom rules to the tls_rcpt rule set.

LOCAL_TLS_SERVER

The access database with tls_server and tls_client on page 214

V8.12 and later

Add custom rules to the tls_server rule set.

MAILER_DEFINITIONS

MAILER_DEFINITIONS on page 716

V8.12 and later

Define delivery agents.

To illustrate, consider the following technique for adding a rule to the parse rule set 0:

LOCAL_RULE_0
R$* <@ $=w . $=m> $*        $#local $: $1      @here.ourdomain

Here, we add a rule to the parse rule set 0 that accepts any address with a host part in the class $=w ($=w on page 876) that is also in one of the local domains listed in the class $=m ($=m on page 872) as a local address.

LOCAL_CONFIG mc macro

The LOCAL_CONFIG mc macro allows custom configuration lines to be inserted in the configuration file by using the mc file. The inserted lines are carried literally into the output and appear in the resulting configuration file just before the options. The LOCAL_CONFIG mc macro should be used for sendmail macro, class, and map definitions, but not for rule set declarations. For rule sets, use the LOCAL_RULESETS mc macro (LOCAL_RULESETS mc macro on page 597):

LOCAL_CONFIG
FE/usr/local/mail/visible.users
Khostmap hash /etc/hostmap

In this example, the class $=E has additional names read from the file visible.users, and the hostmap database is declared.

If you wrongly include rule sets and rules with this LOCAL_CONFIG mc macro you might see the following warning:

Warning: OperatorChars is being redefined.
      It should only be set before rule set definitions.

LOCAL_RULE_0 mc macro

The parse rule set 0 first checks to see whether the mail should be delivered locally. It then checks for other addresses, such as uucp and smtp. You can insert custom delivery agent selections of your own in the parse rule set 0, after the local delivery selection, but before the uucp, smtp, and the like. To do this, use the LOCAL_RULE_0 mc macro:

LOCAL_RULE_0
# We service lady via an mx record.
R$+ < @ lady.Berkeley.EDU. >         $#uucp $@ lady $: $1

Here, we introduce a new rule to select a delivery agent. The host lady is a UUCP host for which we accept mail via an MX record.

In The parse Rule Set 0 on page 696, we deal with the flow of rules through the parse rule set 0. For now, merely note that LOCAL_RULE_0 fits into the flow of rules through the parse rule set 0 like this:

  1. Basic canonicalization (list syntax, delete local host, etc.)

  2. LOCAL_RULE_0

  3. FEATURE(ldap_routing) (FEATURE(ldap_routing) on page 922)

  4. FEATURE(virtusertable) (FEATURE(virtusertable) on page 645)

  5. Addresses of the form “user@$=w” passed to local delivery agent

  6. FEATURE(mailertable) (FEATURE(mailertable) on page 629)

  7. UUCP, BITNET_RELAY ($B on page 808), etc.

  8. LOCAL_NET_CONFIG (LOCAL_NET_CONFIG mc macro on page 598)

  9. SMART_HOST (SMART_HOST mc macro on page 597)

  10. SMTP, local, etc. delivery agents

LOCAL_RULE_1 and LOCAL_RULE_2 mc macros

Rule sets 1 and 2 are normally empty and are not included in the configuration file that is created from your mc file. Rule set 1 processes all sender addresses (Rule Set 1 on page 702). Rule set 2 processes all recipient addresses (Rule Set 2 on page 702). These two mc macros are used just like LOCAL_RULE_0, as shown earlier, but they introduce rules that would otherwise be omitted, rather than adding rules to an existing rule set.

Note that any modifications made to addresses in LOCAL_RULE_1 and LOCAL_RULE_2 are reflected in the headers of mail messages.

LOCAL_RULE_3 mc macro

All addresses are first rewritten by the canonify rule set 3 (The canonify Rule Set 3 on page 690). Thus, for complex configuration needs, it is handy to define special rules and add them to the canonify rule set 3. Note that new rules are added to the end of the canonify rule set 3 by way of rule set 96. That is, each final decision in the canonify rule set 3 calls rule set 96 (with $>96) before returning.

The LOCAL_RULE_3 mc macro is most often used to introduce new rules that can be used in canonicalizing the hostnames.

One suggested use for LOCAL_RULE_3 is to convert old UUCP hostnames into domain addresses using the UUCPSMTP mc macro. For example:

LOCAL_RULE_3
UUCPSMTP(decvax,   decvax.dec.com)
UUCPSMTP(research, research.att.com)

This causes the following address transformations:

decvax!user    becomesuser@decvax.dec.com
research!user  becomesuser@research.att.com

Another suggested use for LOCAL_RULE_3 is to introduce a new rule to look up hostnames in a locally customized database:

LOCAL_RULE_3
R$*<@$+>$*       $:$1<@ $(hostmap $2 $) >$3

The declaration and definition of local database maps with the K configuration command (The K Configuration Command on page 882) should appear in the LOCAL_CONFIG section.

LOCAL_RULESETS mc macro

Prior to V8.8 sendmail, you had to use the divert mc directive to force your new rule set declarations to be emitted alongside the normal mc-generated rule sets. Beginning with V8.8, that bit of “black magic” has been removed.

The LOCAL_RULESETS mc command causes all the rule sets and rules that follow it to be emitted into your configuration file along with all the rules that are automatically generated. You use it like this:

LOCAL_RULESETS
your new rule sets and rules here

SMART_HOST mc macro

Some sites can deliver local mail to the local network but cannot look up hosts on the Internet with DNS. Usually, such sites are connected to the outside world through a firewall, or with UUCP. To ensure delivery of all mail, such sites need to forward all nonlocal mail to a smart (or well-connected) gateway host.

You can enable this behavior by defining SMART_HOST. In a firewall situation, all nonlocal mail should be forwarded to a gateway machine for handling:

define(`SMART_HOST', `gateway.your.domain')

In the case of a site that is only UUCP-connected, all nonlocal mail will need to be forwarded to an Internet-connected host over UUCP:

define(`SMART_HOST', `uucp-dom:supporthost')

Here, Internet mail will be forwarded to the host supporthost using the uucp-dom delivery agent.

For information about other ways to use SMART_HOST, see the file cf/README.

LOCAL_NET_CONFIG mc macro

LOCAL_NET_CONFIG is chiefly intended as a place to override settings of the SMART_HOST mc macro (SMART_HOST mc macro on page 597). To illustrate, consider one possible setup for mail. The idea is to allow hosts on the local network to deliver directly to each other but to have all other mail sent to a “smart host” that forwards that mail offsite. Commonly, such arrangements are used by sites with in-house networks that have access to the outside world only through a UUCP link. For such sites you can use LOCAL_NET_CONFIG:

define(`SMART_HOST', `relay:uucp-gateway')
LOCAL_NET_CONFIG
R $* < @ $+ .$m. > $*     $#smtp $@ $2.$m $: $1 < @ $2.$m > $3

Here, SMART_HOST is defined as relay:uucp-gateway (meaning send to the host uucp-gateway with the relay delivery agent). The LOCAL_NET_CONFIG then introduces a rule that causes all names that end in your domain name ($m) to be delivered via the smtp delivery agent. Any other addresses fall through and are handled by the SMART_HOST rules.

In The parse Rule Set 0 on page 696, we deal with the flow of rules through the parse rule set 0. For now, merely note that LOCAL_NET_CONFIG fits into the flow of rules through the parse rule set 0 like this:

  1. Basic canonicalization (list syntax, delete local host, etc.)

  2. LOCAL_RULE_0 (LOCAL_RULE_0 mc macro on page 596)

  3. FEATURE(ldap_routing) (FEATURE(ldap_routing) on page 922)

  4. FEATURE(virtusertable) (FEATURE(virtusertable) on page 645)

  5. Addresses of the form “user@$=w” passed to local delivery agent

  6. FEATURE(mailertable) (FEATURE(mailertable) on page 629)

  7. UUCP, BITNET_RELAY ($B on page 808), etc.

  8. LOCAL_NET_CONFIG

  9. SMART_HOST (SMART_HOST mc macro on page 597)

  10. SMTP, local, etc. delivery agents

Masquerading

Masquerading is the process of transforming the local hostname in addresses into that of another domain. This results in the mail message appearing to come from that other domain rather than from the local host. Masquerading is most often used in domains where email is addressed to the domain rather than to individual hosts inside the domain.

Masquerading usually rewrites header-sender addresses. Some mc features allow you also to rewrite envelope addresses and recipient headers. The complete list of all definitions and features that affect masquerading is shown in Table 17-3.

Table 17-3. Definitions and features affecting masquerading

What

§

Version

Masquerade

EXPOSED_USER

EXPOSED_USER mc Macro on page 599

V8.6 and later

All but these hosts

EXPOSED_USER_FILE

EXPOSED_USER_FILE mc macro on page 600

V8.12 and later

All but these

FEATURE(allmasquerade)

FEATURE(allmasquerade) on page 615

V8.2 and later

The recipient too

FEATURE(domaintable)

FEATURE(domaintable) on page 621

V8.2 and later

Rewrite old domain as equivalent to new domain

FEATURE(generics_entire_domain)

FEATURE(generics_entire_domain) on page 622

V8.10 and later

Transform sender addresses

FEATURE(genericstable)

FEATURE(genericstable) on page 622

V8.8 and later

Transform sender addresses

FEATURE(limited_masquerade)

FEATURE(limited_masquerade) on page 625

V8.8 and later

Only MASQUERADE_DOMAIN hosts

FEATURE(local_no_masquerade)

FEATURE(local_no_masquerade) on page 626

V8.12 and later

Don’t masquerade local mail

FEATURE(masquerade_entire_domain)

FEATURE(masquerade_entire_domain) on page 631

V8.8 and later

All of a domain

FEATURE(masquerade_envelope)

FEATURE(masquerade_envelope) on page 632

V8.7 and later

The envelope too

GENERICS_DOMAIN

GENERICS_DOMAIN mc macro on page 624

V8.8 and later

List domains for genericstable

GENERICS_DOMAIN_FILE

GENERICS_DOMAIN_FILE mc macro on page 624

V8.8 and later

List domains for genericstable

MASQUERADE_AS

MASQUERADE_AS mc Macro on page 600

V8.6 and later

As another host

MASQUERADE_DOMAIN

MASQUERADE_DOMAIN mc Macro on page 600

V8.6 and later

Other domains

MASQUERADE_DOMAIN_FILE

MASQUERADE_DOMAIN_FILE mc Macro on page 601

V8.6 and later

Other domains

MASQUERADE_EXCEPTION

MASQUERADE_EXCEPTION mc Macro on page 601

V8.10 and later

But not these domains

MASQUERADE_EXCEPTION_FILE

MASQUERADE_EXCEPTION_FILE mc Macro on page 602

V8.12 and later

But not these domains

EXPOSED_USER mc Macro

An internal sendmail class is used by the V8 configuration file to hold a list of usernames that should never be masqueraded (even if masquerading is enabled with the MASQUERADE_AS mc macro). Prior to V8.10 sendmail, the user root was always in that class. With V8.10 and later, that class is now always empty unless you add usernames into it.

You can add users individually with the EXPOSED_USER mc macro like this:

EXPOSED_USER(`user')

Here, user is either one user or a list of users separated by spaces.

EXPOSED_USER_FILE mc macro

The EXPOSED_USER_FILE macro, like the EXPOSED_USER macro, allows you to list names that should never be masqueraded (even if masquerading is enabled with the MASQUERADE_AS mc macro). It lists usernames in an external file, one name per line, and is declared like this:

EXPOSED_USER_FILE(`/etc/mail/exposedusers')

This declaration causes a list of users to be read from the file /etc/mail/exposedusers. Because EXPOSED_USER_FILE is implemented with an F configuration command (The F Class Command on page 857), you can add whatever F command arguments you desire. For example:

EXPOSED_USER_FILE(`-o /etc/mail/exposedusers')

Here the -o switch makes the presence of the /etc/mail/exposedusers file optional.

If you are currently reading exposed users from a file declared with the F configuration command, you are encouraged to convert to this new macro. Use of it will insulate you from change in the future if a different class name is ever used.

MASQUERADE_AS mc Macro

At sites with one central mail server (see MAIL_HUB, MAIL_HUB mc Macro on page 605), it can be advantageous for mail to appear as though it is from the hub. This simplifies mail administration in that all users have the same machine address no matter which workstations they use. You can cause a workstation to masquerade as the server (or as another host) by using the MASQUERADE_AS mc macro:

MASQUERADE_AS(`server')

This causes outgoing mail to be labeled as coming from the server (rather than from the value in $j, $j on page 830). The new address appears in the sender headers (such as From:) but specifically does not appear in the Received: (Received: on page 1162) and Message-ID: (Message-ID: on page 1159) headers.

Some users (such as root) should never be masqueraded because one always needs to know their machine of origin. Such users are declared by using the EXPOSED_USER mc macro. Note that prior to V8.10 sendmail, root was always exposed.

If you wish to have recipient addresses also masqueraded, cautiously use the allmasquerade feature (FEATURE(allmasquerade) on page 615).

MASQUERADE_DOMAIN mc Macro

Ordinarily, MASQUERADE_AS enables hosts in the local domains (as defined in the $=w class, $=w on page 876) to be transformed into the masquerading host. It also masquerades a list of additional hosts, but that list is normally empty.

If you wish to masquerade a domain other than your local one, you can use the MASQUERADE_DOMAIN mc macro:

MASQUERADE_DOMAIN(`other.domain')

Essentially, all that MASQUERADE_DOMAIN does is assign its argument to an internal sendmail class, so you can list multiple domains in a single MASQUERADE_DOMAIN statement:

MASQUERADE_DOMAIN(`domain1 domain2 domain3')

Note that MASQUERADE_DOMAIN masquerades only the domain and not any hosts under that domain. If you wish to masquerade all hosts under a domain (including the domain itself), see the masquerade_entire_domain feature (FEATURE(masquerade_entire_domain) on page 631).

Also note that MASQUERADE_DOMAIN has special meaning for the limited_masquerade feature (FEATURE(limited_masquerade) on page 625). When that feature is declared, only the domains listed under MASQUERADE_DOMAIN will be masqueraded.

MASQUERADE_DOMAIN_FILE mc Macro

In masquerading other domains, as with MASQUERADE_DOMAIN, it can prove advantageous to store the list of masqueraded domains in an external file. The MASQUERADE_DOMAIN_FILE mc macro allows you to do just that:

MASQUERADE_DOMAIN_FILE(`/etc/mail/domains')

Essentially, all that MASQUERADE_DOMAIN_FILE does is read the external file using the F configuration command. As a consequence, you can add an F-style argument to its declaration:

MASQUERADE_DOMAIN_FILE(`-o /etc/mail/domains')

Here, we added a -o to make the existence of the file optional.

Note that the file specified with MASQUERADE_DOMAIN_FILE is read only once, when sendmail first starts.

MASQUERADE_EXCEPTION mc Macro

Normally, when you masquerade a site, you masquerade all the machines at that site. But in some instances that might not be desirable. Beginning with V8.10 sendmail, it is now possible to omit selected hosts from masquerading.

Consider, for example, a university that hosts a few subdomains within it. If bigcampus.edu provided mail services for cs.bigcampus.edu, it might set up its main mail server’s mc file like this:

MASQUERADE_AS('bigcampus.edu')
FEATURE(`masquerade_entire_domain')
MASQUERADE_EXCEPTION(`cs.bigcampus.edu')

The argument to MASQUERADE_EXCEPTION can be one or more hosts, separated from each other by spaces. Each excepted host is assigned to an internal sendmail class.

Note that you cannot exempt all hosts in a domain with this MASQUERADE_EXCEPTION mc macro. You must specify each host individually.

MASQUERADE_EXCEPTION_FILE mc Macro

If you have many exceptions defined with the MASQUERADE_EXCEPTION mc configuration macro, you can store them in a single file—say, donotmasq—and read that file using the MASQUERADE_EXCEPTION_FILE mc macro:

MASQUERADE_EXCEPTION_FILE(`/etc/mail/donotmasq')    ← V8.12 and later

Essentially, all that MASQUERADE_EXCEPTION_FILE does is read the external file using the F configuration command. As a consequence, you can add an F-style argument to its declaration:

MASQUERADE_EXCEPTION_FILE(`-o /etc/mail/donotmasq')    ← V8.12 and later

Here, we added a -o to make the existence of the file optional.

Note that the file specified with MASQUERADE_EXCEPTION_FILE is read only once, when sendmail first starts.

Relays

A relay is a rule that sends all of one type of mail to a specific destination. One example is email fax transmissions. Clearly, even though local mail should be delivered locally, mail to the pseudouser fax should always be sent to a special fax-handling machine.

The complete list of relays supported by the V8 sendmail mc technique is shown in Table 17-4.

Table 17-4. Relays

Relay

§

Versions

Description

BITNET_RELAY

BITNET_RELAY mc Macro on page 603

V8.1 and later

The BITNET relay

DECNET_RELAY

DECNET_RELAY mc Macro on page 604

V8.7 and later

The DECnet relay

FAX_RELAY

FAX_RELAY mc Macro on page 604

V8.6 and later

The FAX relay

LOCAL_RELAY

LOCAL_RELAY mc Macro on page 604

V8.1 and later

Relay for unqualified users

LUSER_RELAY

LUSER_RELAY mc Macro on page 605

V8.7 and later

Relay for unknown local users

MAIL_HUB

MAIL_HUB mc Macro on page 605

V8.6 and later

All local delivery on a central server

SMART_HOST

SMART_HOST mc macro on page 597

V8.6 and later

The ultimate relay

UUCP_RELAY

UUCP_RELAY mc Macro on page 606

V8.1 and later

The UUCP relay

All relays are declared in the same fashion. For example:

define(`LOCAL_RELAY',`agent:host')

Here, agent is the name of a delivery agent to use, and host is the name of the machine to which all such mail will be relayed. If agent: is missing, it defaults to a literal relay:.

If the host is listed under a domain that uses wildcard MX records (Wildcard MX Records on page 335), you should specify it with a trailing dot, as, for example:

define(`LOCAL_RELAY', `smtp:relay.sub.domain.')
                                            ↑
                                        trailing dot

In The parse Rule Set 0 on page 696, we deal with the flow of rules through the parse rule set 0. For now, merely note that relays fit into the flow of rules through the parse rule set 0 like this:

  1. Basic canonicalization (list syntax, delete local host, etc.)

  2. LOCAL_RULE_0 (LOCAL_RULE_0 mc macro on page 596)

  3. FEATURE(ldap_routing) (FEATURE(ldap_routing) on page 922)

  4. FEATURE(virtusertable) (FEATURE(virtusertable) on page 645)

  5. Addresses of the form “user@$=w” passed to local delivery agent

  6. FEATURE(mailertable) (FEATURE(mailertable) on page 629)

  7. UUCP_RELAY, BITNET_RELAY, FAX_RELAY, DECNET_RELAY

  8. LOCAL_NET_CONFIG

  9. SMART_HOST (SMART_HOST mc macro on page 597)

  10. SMTP, local, etc. delivery agents

BITNET_RELAY mc Macro

When configuring with the mc method, you can specify a host that will transfer mail between the Internet and BITNET. Mail to BITNET can then be sent by appending the pseudodomain .BITNET to an address. For example:

user@ucbicsi.BITNET

Here, ucbicsi is a BITNET host.

To allow your configuration file to handle this form of address, you need to declare the name of your BITNET relay using the BITNET_RELAY keyword:

define(`BITNET_RELAY', `relay_host')dnl

This statement causes the rule for BITNET to be included in your configuration file and causes relay_host to become the host to which BITNET mail is sent.

See Relays on page 602 for a description of how to include a delivery agent specification with relay_host. See also, bitdomain feature (FEATURE(bitdomain) on page 617) for a way to convert BITNET addresses to Internet addresses for hosts that have both.

DECNET_RELAY mc Macro

DECnet addresses are of the form node::user. They can be handled by defining a host that will relay them into your DECnet network. Using the mc configuration method, you enable DECnet like this:

define(`DECNET_RELAY', `relay_host')dnl

Mail addressed to node::user will then be forwarded to relay_host, as will any Internet-style addresses that end in the pseudodomain .DECNET, such as user@domain.DECNET.

FAX_RELAY mc Macro

At many sites, faxes can be sent via email. When the host that dispatches those faxes is not the local host, you need to relay fax mail to the host that can dispatch faxes. This ability is enabled by defining that relay host with the FAX_RELAY mc configuration macro:

define(`FAX_RELAY', `relay_host')dnl

This causes all mail that ends with the pseudodomain .FAX to be forwarded to relay_host.

On the fax relay machine, you will also have to declare the fax delivery agent with the MAILER( ) mc command (MAILER( ) m4 macro on page 590).

LOCAL_RELAY mc Macro

Unless you specify otherwise, any address that is a username without any @host part is delivered using the local delivery agent. If you prefer to have all such mail handled by a different machine, you can define that other machine with the LOCAL_RELAY mc macro.

Note that a relay is different from the knowledgeable hub defined with MAIL_HUB. (See later in this chapter for an illustration of how MAIL_HUB and LOCAL_RELAY interact.)

This mc macro is deprecated because it doesn’t work well with some MUAs—for example, mh( ). This is because some MUAs put a host part on all addresses even if only the user part was specified.

LOCAL_USER mc Macro

Some unqualified usernames (names without an @host part) need to be delivered on the local machine even if LOCAL_RELAY is defined. The user root is one such example. By remaining local, aliasing is allowed to take place.

The LOCAL_USER mc macro is used to add additional usernames to the list of local users. Note that prior to V8.12, root was always a member of that list:

LOCAL_USER(`operator')
LOCAL_USER_FILE(`path')       ← V8.12 and later

Here, the first line causes the name operator to be appended to the list of local users. The second line causes the list of local users to be read from the file named path. The disposition of local usernames, which include the domain of the local host is determined by the stickyhost feature (FEATURE(stickyhost) on page 642).

LUSER_RELAY mc Macro

A local user is one who evaluates to delivery on the local machine, even after aliasing. By defining LUSER_RELAY:

define(`LUSER_RELAY', `relay_host')dnl

any username that is not found in the passwd(5) file will be forwarded to relay_host. This check is made after aliasing but before processing of the ~/.forward file.

The mc method adds rules to the localaddr rule set 5 that cause the user to be looked up with the user database type (see the name field lookup for that type in user on page 945). If the user’s name is not found, the message is forwarded to relay_host.

See Relays on page 602 for a description of how to include a delivery agent specification with relay_host. Also see the V8.12 FEATURE(preserve_luser_host) (FEATURE(preserve_luser_host) on page 638) for a way to preserve the recipient’s hostname when using this LUSER_RELAY m4 configuration macro.

MAIL_HUB mc Macro

One scheme for handling mail is to maintain one mail spool directory centrally and to mount that directory remotely on all clients. To avoid file-locking problems, delivery to such a spool should be performed only on the central server. The MAIL_HUB mc macro allows you to specify that all local mail be forwarded to the central server for delivery. The point is to let unqualified names be forwarded through a machine with a large aliases file.

If you define both LOCAL_RELAY and MAIL_HUB, unqualified names and names in the class $=L are sent to LOCAL_RELAY and other local names are sent to MAIL_HUB. To illustrate, consider the result of various combinations for the user you on the machine here.our.site.

If LOCAL_RELAY is defined as relay.our.site and MAIL_HUB is not defined, mail addressed to you is forwarded to relay.our.site, but mail addressed to is delivered locally.

If MAIL_HUB is defined as hub.our.site and LOCAL_RELAY is not defined, mail addressed to you and mail addressed to is forwarded to hub.our.site for delivery.

If both LOCAL_RELAY and MAIL_HUB are defined as shown earlier, mail addressed to you is sent to relay.our.site for delivery, and mail addressed to is forwarded to hub.our.site.

If you want all outgoing mail to go to a central machine, use SMART_HOST too.

Note that LOCAL_RELAY is considered most useful when combined with the FEATURE(stickyhost) (FEATURE(stickyhost) on page 642). Also note that the FEATURE(nullclient) (FEATURE(nullclient) on page 637) can be used if you want all mail to be forwarded to a central machine no matter what.

UUCP_RELAY mc Macro

UUCP is usually modem-based and typically connects two individual machines together. Unlike domain-based delivery, UUCP delivery is from one machine to the next, and then from that next machine to yet another (using addresses such as fbi!wash!gw).

If your site handles UUCP traffic, that handling can be in one of two forms. Either a given host has direct UUCP connections or it does not. If it does not, you might wish to have all UUCP mail forwarded to a host that can handle UUCP. This is done by defining a UUCP_RELAY, which is defined just as you would define any other relay (as described in Relays on page 602).

If your machine or site does not support UUCP, we recommend disabling all UUCP with the FEATURE(nouucp) (FEATURE(nouucp) on page 636).

If your machine has directly connected UUCP hosts, you might wish to use one or more of the UUCP techniques. But before doing so, be sure to declare the uucp delivery agent (MAILER( ) m4 macro on page 590).

UUCP Support

The mc configuration technique includes four UUCP options to choose from. They are listed in Table 17-5.

Table 17-5. UUCP support

Relay

§

Versions

Description

LOCAL_UUCP

The LOCAL_UUCP mc Macro on page 609

V8.13 and later

Add new rules and rule sets to select a UUCP delivery agent

SITE

SITE mc Macro (Obsolete) on page 609

V8.1 and later

Declare sites for SITECONFIG (obsolete)

SITECONFIG

SITECONFIG mc Macro (Obsolete) on page 609

V8.1 and later

Local UUCP connections (obsolete)

UUCP_RELAY

UUCP_RELAY mc Macro on page 606

V8.1 and later

The UUCP relay

UUCPSMTP

UUCPSMTP mc Macro on page 610

V8.1 and later

Individual UUCP-to-network translations

Note that two items in the table are marked as obsolete. This is because all their functions have been moved into the FEATURE(mailertable) (FEATURE(mailertable) on page 629). They are included for backward compatibility with early configuration file versions.

Support for UUCP can be included in your mc file with the MAILER command:

MAILER(`uucp')

This declares six[239] delivery agents and the rules to support them. They are listed in Table 17-6.

Table 17-6. UUCP delivery agents

Agent

§

Versions

Description

uucp-old

uucp-old (a.k.a. uucp) on page 608

V8.6 and later

Old-style, all ! form of UUCP

uucp

uucp-old (a.k.a. uucp) on page 608

V8.1 and later

Synonym for the above (obsolete)

uucp-new

uucp-new (a.k.a. suucp) on page 608

V8.6 and later

Old-style with multiple recipients

suucp

uucp-new (a.k.a. suucp) on page 608

V8.1 and later

Synonym for the above (obsolete)

uucp-uudom

uucp-uudom on page 608

V8.6 and later

Domain-form headers, old-form envelope

uucp-dom

uucp-dom on page 608

V8.6 and later

Domain-form headers and envelope

If support for SMTP delivery agents is also included prior to UUCP, the last two additional delivery agents are included (uucp-dom and uucp-uudom). Note that smtp must be first for this to happen:

MAILER(`smtp')
MAILER(`uucp')

If uucp is first, uucp-dom and uucp-uudom are excluded.

When processing UUCP mail (addresses that contain a ! and those that end in a .UUCP suffix), sendmail routes to those hosts on the basis of the class in which they were found. Hosts that are found in $=U are delivered via uucp-old, hosts in $=Y are delivered via uucp-new, and hosts in $=Z are delivered via uucp-uudom.

The choice of which delivery agent to use for UUCP delivery is under the control of the SITECONFIG mc macro (SITECONFIG mc Macro (Obsolete) on page 609). Which you choose depends on what version of UUCP you are running locally and what version is being run at the other end of the connection. There are far too many variations on UUCP to allow specific recommendations here. In general, you need to choose between a domain form of address () and a UUCP form (wash!gw) and then go with the delivery agent that makes the most sense for you. We recommend that you start with the most domain-correct agent, uucp-dom, and see if it works for you. If not, scale back to uucp-uudom, then to uucp-new, and finally to uucp-old as a last resort.

uucp-old (a.k.a. uucp)

If you are running an old version of UUCP, you might have to use this delivery agent. All addresses are turned into the ! form even if they were in domain form:

user                becomes →      yourhost!user
user@host.domain    becomes →      yourhost!host.domain!user

This delivery agent can deliver to only one recipient at a time, so it can spend a lot of time transmitting duplicate messages. If at all possible, avoid using this delivery agent.

uucp-new (a.k.a. suucp)

Newer releases of UUCP can send to multiple recipients at once. If yours is such a release, you can use the uucp-new delivery agent. It is just like uucp-old except that it can perform multiple deliveries.

uucp-uudom

More modern implementations of UUCP can understand and correctly handle domain-style addresses in headers (although they still require the ! form in the envelope). If yours is such an implementation, you can use the uucp-uudom delivery agent.

At the receiving end, the message mail arrives with the five-character "From" line showing the sender address in the ! form. The "From" line reflects the envelope address.

uucp-dom

The uucp-dom is the most domain-correct form of the available UUCP delivery agents. All addresses, envelopes, and headers, regardless of whether they began in the ! form, are sent out in domain form. Essentially, this uses UUCP as a transport mechanism, but in all other respects it adheres to the Internet standards.

The LOCAL_UUCP mc Macro

If you enable UUCP, the parse rule set 0 normally adds rules that select UUCP delivery agents. First, locally connected UUCP addresses are detected and the appropriate UUCP delivery agent is selected based on each such address found. Addresses in the class $=Z select the uucp-uudom delivery agent. Addresses in the class $=Y select the uucp-new delivery agent. And addresses in the class $=U select the uucp-old delivery agent.

Finally, the parse rule set 0 adds rules that detect remotely connected UUCP addresses.

Beginning with V8.13, if you need to add rules between these two phases (between the detection of local UUCP addresses and remote UUCP addresses), you may do so by utilizing this new LOCAL_UUCP mc macro. For example, the following mc file entry:

LOCAL_UUCP
R$* < @ $={ServerUUCP} . UUCP. > $*        $#uucp-uudom $@ $2 $: $1 < @ $2 .UUCP. >
$3

causes the preceding new rule to be added to the parse rule set 0 in the location shown here:

# resolve locally connected UUCP links
...New rules added here
# resolve remotely connected UUCP links (if any)

Note that the LOCAL_UUCP mc macro is not intended for casual use. It should be used only to solve special UUCP needs that cannot be solved using more conventional methods.

SITE mc Macro (Obsolete)

UUCP connections are declared inside the SITECONFIG file with the SITE mc macro. That mc macro just takes a list of one or more UUCP hostnames:

SITE(lady)
SITE(sonya grimble)

Each listed host is added to the class that was defined as the third argument to the SITECONFIG declaration.

SITECONFIG mc Macro (Obsolete)

The SITECONFIG mc macro is obsolete but has been retained for backward compatibility. It has been replaced by the FEATURE(mailertable) (FEATURE(mailertable) on page 629).

The SITECONFIG mc macro is useful for maintaining lists of UUCP connections. There are two types of connections: those connected to the local host and those connected to another host. The first type is declared with SITECONFIG like this:

SITECONFIG(`file',` host',`class')

Here, file is the name of a file (without the .m4 suffix) that is in the directory cf/siteconfig. That file contains a list of SITE declarations (described earlier). The host is the UUCP node name of the local host. The class is the name (one letter, or multicharacter) of a class that holds the list of UUCP connections. For example:

SITECONFIG(`uucp.arpa',`arpa',`U')
SITECONFIG(`uucp.arpa',`arpa',`{MyUUCPclass}')

Here, the file cf/siteconfig/uucp.arpa.m4 contains a list of UUCP hosts directly connected to the machine arpa. This declaration would be used only in the machine arpa’s mc file. The list of UUCP hosts is added to the sendmail class-macro $=U in the first example, and $={MyUUCPclass} in the second.

Some single-character letters are special. The special letters available for local connections are U (for uucp-old), Y (for uucp-new), and Z (for uucp-uudom).

A second form of the SITECONFIG mc macro is used by hosts other than the host with the direct UUCP connections. It is just like the earlier form but with the full canonical name of the host:

SITECONFIG(`uucp.arpa',`arpa.Berkeley.EDU',`W')

This also reads the file uucp.arpa.m4, but instead of causing UUCP connections to be made locally, it forwards them to the host arpa.Berkeley.EDU.

The hostname that is the second argument is assigned to the $W sendmail macro. The class $=W is set aside to hold lists of hosts that appear locally connected. This class is also used with the SITE mc macro. The letters that are available for remote sites are V, W, and X.

If nothing is specified, the class becomes Y. If class U is specified in the third parameter, the second parameter is assumed to be the UUCP name of the local site, rather than the name of a remote site. In this latter case, the specified local name has a .UUCP appended, and the result is added to class w.

Note that SITECONFIG won’t work if you disable UUCP with FEATURE(nouucp) (FEATURE(nouucp) on page 636).

UUCPSMTP mc Macro

If your site has a host that used to be a UUCP site but is now on the network, you can intercept and rewrite the old address of that host into the new network address. For example, mail to the machine wash used to be addressed as wash!user. Now, however, wash is on the network, and the mail should be addressed as .

The UUCPSMTP mc macro provides the means to specify a UUCP-to-network translation for specific hosts. The earlier example would be declared like this:

LOCAL_RULE_3
UUCPSMTP(`wash',`wash.dc.gov')

The UUCPSMTP mc macro should be used only under LOCAL_RULE_3.

Pitfalls

  • The use of the # to place comments into a .mc file for eventual transfer to your configuration file might not work as expected. The # is not special to the m4 processor, so m4 continues to process a line even though that line is intended to be a comment. So, instead of:

    # Here we define $m as our domain

    (which would see define as an m4 keyword), use single quotes to insulate all such comments from m4 interpretation:

    # `Here we define $m as our domain'
  • Never blindly overwrite your sendmail.cf file with a new one. Always compare the new version to the old first:

    % diff /etc/mail/sendmail.cf oursite.cf
    19c19
    < ##### built by you@oursite.com on Sat Nov  3  11:26:39 PDT 2007
    ---
    > ##### built by you@oursite.com on Fri Dec 14 04:14:25 PDT 2007

    Here, the only change was the date the files were built, but if you had expected some other change, this would tell you the change had failed.

  • Never edit your sendmail.cf file directly. If you do, you will never be able to generate a duplicate or update from your mc file. This is an especially serious problem when upgrading from one release of sendmail to a newer release. Should you make this mistake, reread the appropriate sections in this book and the documentation supplied with the sendmail source.

  • Don’t assume that UUCP support and UUCP relaying are turned off by default. Always use FEATURE(nouucp) (FEATURE(nouucp) on page 636) to disable UUCP unless you actually support UUCP:

    FEATURE(`nouucp')               ← recommended through V8.9
    FEATURE(`nouucp',`reject')      ← recommended with V8.10 and later

Configuration File Feature Reference

In this section, we detail each feature available when configuring with the mc configuration method. We list them briefly in Table 17-7, and explain them in greater detail in the text that follows. Note that a comprehensive list of all mc configuration macros and features is available in Appendix A.

Table 17-7. FEATURE( )s available with the mc configuration technique

FEATURE( )

§

Description

accept_unqualified_senders

FEATURE(accept_unqualified_senders) on page 614

Allow unqualified MAIL From:.

accept_unresolvable_domains

FEATURE(accept_unresolvable_domains) on page 614

Accept unresolvable domains.

access_db

The access Database on page 277

A database for mail policy.

allmasquerade

FEATURE(allmasquerade) on page 615

Masquerade recipient as well as sender.

always_add_domain

FEATURE(always_add_domain) on page 616

Add the local domain even on local mail.

authinfo

FEATURE(authinfo) on page 616

Use a separate database for authentication information.

badmx

FEATURE(badmx)—V8.14 and Later on page 291

Rejects a client host name, the domain part of which resolves to a bad MX record (V8.14 and later).

bestmx_is_local

FEATURE(bestmx_is_local) on page 617

Accept best MX record as local if in $=w.

bitdomain

FEATURE(bitdomain) on page 617

Convert BITNET addresses into Internet addresses (deprecated).

blacklist_recipients

Reject per Recipient on page 284

Look up recipients in access database.

block_bad_helo

FEATURE(block_bad_helo)—V8.14 and Later on page 292

Rejects clients who provide a HELO/EHLO argument that is either unqualified or one of the server’s names (V8.14 and later).

compat_check

FEATURE(compat_check) on page 619

Screen sender/recipient pairs.

conncontrol

FEATURE(conncontrol) on page 619

Limit simultaneous connections to your machine from another machine (V8.13 and later).

delay_checks

Accept and Reject per Recipient on page 284

Check SMTP RCPT To: first.

dnsbl

FEATURE(dnsbl) on page 261

Reject based on various DNS blacklists.

domaintable

FEATURE(domaintable) on page 621

Rewrite old domain as equivalent to new domain.

enhdnsbl

FEATURE(enhdnsbl) on page 263

Enhanced dnsbl lookups

generics_entire_domain

FEATURE(generics_entire_domain) on page 622

Match subdomains in generics table.

genericstable

FEATURE(genericstable) on page 622

Transform sender addresses.

greet_pause

FEATURE(greet_pause)—V8.13 and Later on page 293

Suppress slamming by detecting advance writes (V8.13 and later).

ldap_routing

ldap (was ldapx) on page 912

Reroute recipients based on LDAP lookups.

limited_masquerade

FEATURE(limited_masquerade) on page 625

Only masquerade MASQUERADE_DOMAIN hosts.

local_lmtp

FEATURE(local_lmtp) on page 625

Deliver locally with LMTP and mail.local.

local_no_masquerade

FEATURE(local_no_masquerade) on page 626

Don’t masquerade local mail.

local_procmail

FEATURE(local_procmail) on page 627

Use procmail(1), etc. as local delivery agent.

lookupdotdomain

FEATURE(lookupdotdomain) on page 628

Enable .domain secondary access.db lookups.

loose_relay_check

FEATURE(loose_relay_check) on page 270

Allow %-hack relaying.

mailertable

FEATURE(mailertable) on page 629

Database selects new delivery agents.

masquerade_entire_domain

FEATURE(masquerade_entire_domain) on page 631

Masquerade all hosts under a domain.

masquerade_envelope

FEATURE(masquerade_envelope) on page 632

Masquerade the envelope as well as headers.

mtamark

FEATURE(mtamark)—V8.13 and Later, Experimental on page 295

Experimental support for the MTA Mark approach (V8.13 and later).

msp

FEATURE(msp) on page 633

Create a mail submission cf file.

nocanonify

FEATURE(nocanonify) on page 634

Don’t canonify with $[ and $].

nodns

FEATURE(nodns) on page 635

Omit DNS support from configuration file (deprecated V8.7 through V8.12, removed as of V8.13).

no_default_msa

FEATURE(no_default_msa) on page 635

Disable automatic listening on MSA port 587.

notsticky

FEATURE(notsticky) on page 636

Don’t differ unqualified versus qualified addresses.

nouucp

FEATURE(nouucp) on page 636

Eliminate all UUCP support.

nullclient

FEATURE(nullclient) on page 637

Relay all mail through a mail host.

preserve_local_plus_detail

FEATURE(preserve_local_plus_detail) on page 637

Retain plussed addresses for delivery.

preserve_luser_host

FEATURE(preserve_luser_host) on page 638

Preserve recipient host with LUSER_RELAY.

promiscuous_relay

FEATURE(promiscuous_relay) on page 271

Allow unbridled relaying.

queuegroup

FEATURE(queuegroup) on page 638

Select queue groups via the access database.

ratecontrol

FEATURE(ratecontrol) on page 638

Limit the rate at which other MTAs may connect to yours (V8.13 and later).

rbl

FEATURE(rbl) on page 640

Reject connections based on rbl.maps.vix.com (V8.9 through V8.11).

redirect

FEATURE(redirect) on page 640

Add support for address.REDIRECT aliases.

relay_based_on_MX

FEATURE(relay_based_on_MX) on page 271

Relay based on MX records.

relay_entire_domain

FEATURE(relay_entire_domain) on page 272

Relay based on $=m in addition to $=w.

relay_hosts_only

FEATURE(relay_hosts_only) on page 273

Relay individual hosts, not domains.

relay_local_from

FEATURE(relay_local_from) on page 273

Relay based on $=w and MAIL From:.

relay_mail_from

FEATURE(relay_mail_from) on page 274

Relay based on MAIL From: and RELAY in access_db.

require_rdns

FEATURE(require_rdns)—V8.14 and Later on page 296

Rejects clients whose IP address cannot be properly resolved (V8.14 and later).

smrsh

Configure to Use smrsh on page 380

Use smrsh (sendmail restricted shell).

stickyhost

FEATURE(stickyhost) on page 642

Differ unqualified from qualified addresses.

use_client_ptr

FEATURE(use_client_ptr)—V8.13 and Later on page 297

Replace IP address with ${client_ptr} in check_relay (V8.13 and later).

use_ct_file

FEATURE(use_ct_file) on page 643

Use /etc/mail/trusted-users for trusted users.

use_cw_file

FEATURE(use_cw_file) on page 643

Use /etc/mail/local-host-names for local hosts.

uucpdomain

FEATURE(uucpdomain) on page 644

Convert UUCP hosts via a database (deprecated).

virtuser_entire_domain

FEATURE(virtuser_entire_domain) on page 645

Match subdomains in the virtual user table.

virtusertable

FEATURE(virtusertable) on page 645

Support for virtual domains.

Note that this reference is not comprehensive. Options, sendmail macros, and delivery agents, for example, are described in chapters dedicated to those topics.

FEATURE(accept_unqualified_senders)

Allow unqualified MAIL From: V8.9 and later

The MAIL From: command of the SMTP transaction is used to convey the address of the envelope sender. RFC821 requires that the envelope sender address always be fully qualified. That is, it must always have a user part, an @ character, and a domain part, in that order.

The normal behavior of sendmail is to reject the envelope sender if it is not fully qualified. For example:

MAIL From: <you>
553 5.5.4 <you>... Domain name required

This rejection is done for network connections only. When reading the envelope sender via the standard input under the -bs command-line switch (-bs on page 236) a missing @domain part is OK:

% /usr/sbin/sendmail -bs
220 yourhost.domain ESMTP Sendmail 8.14.1/8.14.1; Fri, 14 Dec 2007 14:13:09 −0700
HELO yourhost
250 yourhost.domain Hello your@yourhost.domain, pleased to meet you
MAIL From: <bob>
250 2.1.0 <bob>... Sender ok

If machines at your site routinely send unqualified envelope sender addresses (addresses without the @domain part), you will find that mail is being rejected.

Your first attempt at a solution should be to fix the broken software that is sending unqualified addresses. If that fails, or if you lack the permission or authority, you can use this accept_unqualified_senders feature to force sendmail to accept unqualified envelope sender addresses:

FEATURE(`accept_unqualified_senders')

Another way to handle this problem is with the (V8.10 and later) DaemonPortOptions option’s Modifier key value (DaemonPortOptions=Modify= on page 996). If that value includes a u character, unqualified envelope sender addresses are accepted even if this feature is omitted. Even if this feature is included, the presence of an f in the DaemonPortOptions option’s Modifier key value causes the normal behavior of enforcing fully qualified addresses.

FEATURE(accept_unresolvable_domains)

Accept unresolvable domains V8.9 and later

The MAIL From: command of the SMTP transaction is used to convey the address of the envelope sender. RFC821 requires that the envelope sender address always be fully qualified. That is, it must always have a user part, an @ character, and a domain part, in that order.

Ordinarily, sendmail looks up the domain part of the address using DNS, and, if not found, rejects that SMTP transaction. For example:

MAIL From: <you@nosuch.host>
501 5.1.8 <you@nosuch.host>... Sender domain must exist

This is useful in blocking spam and fraudulent mail. However, if your machine is behind a firewall, it is possible that it cannot look up any outside addresses. In that situation, all mail from the outside will fail.

If you need to allow all mail to be received when the domain part of the envelope sender address cannot be looked up, you can do so by declaring FEATURE(accept_unresolvable_domains):

FEATURE(`accept_unresolvable_domains')

You can also declare this feature on a machine that is dedicated to a special purpose. A machine dedicated to receiving and processing survey reply mail might be a good candidate for this feature. If you don’t care about the spam protection offered without this feature, go ahead and declare it.

FEATURE(access_db)

A database for mail policy V8.9 and later

Prior to V8.9, the only way to accept or reject mail from selected sites was to use tcpwrappers, or to write your own custom rule sets and rules. Beginning with V8.9, sendmail offers a database which provides that same service, and more (such as feature selection and policy control), in a much more easily configurable way. See The access Database on page 277 for a detailed description of this feature.

FEATURE(allmasquerade)

Masquerade recipient as well as sender V8.2 and later

If a MASQUERADE_AS domain is defined, that name replaces any sender addresses, the domain part of which is listed either by MASQUERADE_DOMAIN (MASQUERADE_DOMAIN mc Macro on page 600) or in the $=w class ($=w on page 876). FEATURE(allmasquerade) causes header recipient addresses to also have that treatment.

But note that this feature can be extremely risky and that it should be used only if the MASQUERADE_AS host has an aliases file that is a superset of all aliases files and a passwd file that is a superset of all passwd files at your site. To illustrate the risk, consider a situation in which the masquerade host is named hub.domain and mail is being sent from the local workstation. If a local alias exists on the local workstation—say, thishost-users—that does not also exist on the masquerade host, FEATURE(allmasquerade) will cause the To: header to go out as:

To: thishost-users@hub.domain

Here, the address thishost-users does not exist on the masquerade host (or worse, might show up as a user part with a host part from an arbitrary Internet site), and as a consequence, replies to messages containing this header will bounce.

The form for FEATURE(allmasquerade) is:

MASQUERADE_AS(`your.hub.domain')
FEATURE(`allmasquerade')

Note that MASQUERADE_AS (MASQUERADE_AS mc Macro on page 600) must also be defined and must contain a fully qualified hostname.

FEATURE(always_add_domain)

Add the local domain even on local mail V8.1 and later

Normally, header recipient addresses and header and envelope sender addresses that are local are left as is. If FEATURE(always_add_domain) is defined, local addresses that lack a host part have an @ and the MASQUERADE_AS host appended (if it is defined). If MASQUERADE_AS is not defined, an @ and the value of the $j sendmail macro ($j on page 830) are appended.

The form for the always_add_domain feature is:

FEATURE(`always_add_domain')

The always_add_domain feature is safe and recommended. It ensures that all addresses that are locally delivered will be fully qualified. See FEATURE(allmasquerade) (FEATURE(allmasquerade) on page 615) for a description of the risks surrounding masquerading addresses.

FEATURE(authinfo)

Use a separate database for authentication information V8.12 and later

Beginning with V8.12, FEATURE(authinfo) tells sendmail to look in a special database file called authinfo for authentication information, rather than in the access database. This means you can have more secure permissions for the authinfo database than for the access database. FEATURE(authinfo) is declared like this:

FEATURE(`authinfo')

This creates a default configuration declaration that looks like this:

Kauthinfo hash /etc/mail/authinfo

Here the hash is derived from the setting of the DATABASE_MAP_TYPE mc configuration macro (Set a Default Database-Map Type for Features on page 897) and the /etc/mail is derived from the setting of the MAIL_SETTINGS_DIR mc macro (The MAIL_SETTINGS_DIR mc Macro on page 68). If you wish to change the defaults without having to change these two mc configuration macros, you can simply define that new default by adding a second argument to the feature declaration:

FEATURE(`authinfo', `hash /etc/private/authinfo')

If you provide a second argument and the second argument is a literal LDAP:

FEATURE(`authinfo', `LDAP')

the default becomes the following (we have wrapped the lines to fit the page):

Kauthinfo ldap −1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)
(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))
(sendmailMTAMapName=authinfo)(sendmailMTAKey=%0))

See ldap (was ldapx) on page 912 for a description of the ldap database type and its −1, -v, and -k switches. See Authinfo and the access database (V8.12 and later) on page 195 for a description of the authinfo database’s contents and how to create that database.

FEATURE(badmx)

Reject a domain with bad MX record V8.14 and later

This feature rejects a client hostname, whose domain part resolves to a bad MX record. See FEATURE(badmx)—V8.14 and Later on page 291 for a full description of this feature.

FEATURE(bestmx_is_local)

Accept best MX record as local if in $=w V8.6 and later

The class $=w ($=w on page 876) defines which hostnames will be treated as being equivalent to the local hostname. That method, however, requires that the mail administrator manually keep the class up-to-date.

As an alternative, for low- to medium-volume sites, use FEATURE(bestmx_is_local). When enabled, this feature looks up each hostname that it finds in the bestmx internal database map (bestmx on page 902). That map returns the best MX record (if it is known) for that name. That returned record is then compared to the list of hostnames in class $=w to see whether it is equivalent to the local host. If so, the address is accepted for local delivery.

The form for FEATURE(bestmx_is_local) is:

FEATURE(`bestmx_is_local')

If you wish to limit lookups to a small list of domains, you can add them as a second argument:

FEATURE(`bestmx_is_local', `domain1 domain2 etc.')

Only the hosts listed are allowed to list your site as the best MX record for use with this feature.

Use of this feature is best limited to low-volume sites. Looking up every address in the bestmx map can cause numerous DNS enquiries. At high-volume sites, the magnitude of extra DNS enquiries can adversely tax the system and network.

There is also a risk to this feature. Someone could create an MX record for your site without your knowledge. Bogus mail might then be accepted at your site without your permission:

bogus.site.com.    IN MX 0 your.real.domain

Here, mail to bogus.site.com would be sent to your site, where the name bogus.site.com would be looked up with FEATURE(bestmx_is_local). Your sendmail would find itself listed as the MX for bogus.site.com and so would accept the bogus mail and attempt to deliver it locally. If the bogus name were designed to discredit you, it could be set to sex.bogus.site.com, for example, and mail to would be delivered to you without you knowing the reason.

FEATURE(bitdomain)

Convert BITNET addresses into Internet addresses Deprecated

This FEATURE(bitdomain) is deprecated because its functionality can be handled by the newer FEATURE(domaintable) (FEATURE(domaintable) on page 621). In case you still need to use FEATURE(bitdomain), we continue to describe it here.

Many Internet hosts have BITNET addresses that are separate from their Internet addresses. For example, the host icsi.berkeley.edu has the registered BITNET name ucbicsi. If a user tried to reply to an address such as:

user@ucbicsi.bitnet

that mail would fail. To help with translating registered BITNET names into Internet addresses, John Gardiner Myers has supplied the bitdomain program in the contrib subdirectory. It produces output in the form:

ucbicsi    icsi.berkeley.edu

that can be put into database form for use with the K configuration command. FEATURE(bitdomain) causes rules to be included in the configuration file that perform the necessary translation:

R$* < @ $+ .BITNET > $*         $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3

Note that this rule requires BITNET addresses to be so identified with a .BITNET suffix. If the address, without the suffix, is found in the bitdomain database, the Internet equivalent address is used in its place. See also the UUCPSMTP mc configuration macro and FEATURE(domaintable).

The form of FEATURE(bitdomain) is:

FEATURE(`bitdomain')

This declaration causes the following K configuration command to be included in addition to the aforementioned rule:

Kbitdomain hash /etc/mail/bitdomain

FEATURE(bitdomain) is one of those that can take an argument to specify a different form of, or name for, the database:

FEATURE(`bitdomain',`dbm -o /opt/sendmail/bitdomain')

The extra argument causes the aforementioned K command to be replaced with the following one:

Kbitdomain dbm -o /opt/sendmail/bitdomain

The earlier bitdomain setting is safe. You can routinely include it in all configuration files. The database lookup is performed only if the .BITNET suffix is present and the database file exists. (See -o on page 889 for a description of the K command’s -o switch.)

You can also provide an extra argument, where that second argument is a literal LDAP:

FEATURE(`bitdomain', `LDAP')

The default in this instance becomes the following (we have wrapped the lines to fit the page):

Kbitdomain ldap −1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)
(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))
(sendmailMTAMapName=bitdomain)(sendmailMTAKey=%0))

See ldap (was ldapx) on page 912 for a description of the ldap database type and its −1, -v, and -k switches.

Note that you must also define BITNET_RELAY ($B on page 808) if you want .BITNET-suffixed mail that is not found in the database to be routed to a relay machine. If BITNET_RELAY is not defined, .BITNET-suffixed mail that is not found in the database is bounced.

FEATURE(blacklist_recipients)

Look up recipients in access database V8.9 and later

FEATURE(access_db) (The access Database on page 277) provides a way to selectively reject envelope sender addresses (and much more). By declaring this FEATURE(blacklist_recipients), you enable the access database to also selectively reject envelope recipient addresses. This feature is fully described in Reject per Recipient on page 284.

FEATURE(block_bad_helo)

Reject clients with a bad HELO/EHLO hostname V8.14 and later

This feature rejects clients who provide a HELO/EHLO argument that is either unqualified or one of the server’s names. See FEATURE(block_bad_helo)—V8.14 and Later on page 292 for a full description of this feature.

FEATURE(compat_check)

Screen sender/recipient pairs V8.12 and later

Beginning with V8.12 sendmail, it is possible to screen email based on sender and recipient address pairs stored in the access database. One use for such a method might be to prevent one employee from receiving mail from another employee. Another use might be to prevent a pseudouser, such as admin, from receiving spurious reports from another user, such as bin. Yet another use might be to reject spam mail to a mailing list.

FEATURE(compat_check) is described in full in FEATURE(compat_check)—V8.12 and Later on page 288.

FEATURE(conncontrol)

Check SMTP RCPT TO: first V8.13 and later

FEATURE(conncontrol) allows you to use the access database to control the number of simultaneous connections another machine may have to your server.[240] The number of simultaneous connections allowed each interval is based on the setting of the ConnectionRateWindowSize option (ConnectionRateWindowSize on page 989), which defaults to 60 seconds. So, for example, if you want to reject a host that has more than 10 simultaneous connections to your server (sometime in the past 60 seconds), where that host has the IP address 192.168.23.45, you would put the following into your access database source file:

ClientRate:192.168.23.45       10

Here, if the host with the IP address 192.168.23.45 tries to set up an 11th simultaneous connection to your server, that connection will be denied.

You enable FEATURE(conncontrol) like this:

FEATURE(`conncontrol')

But note, if you have not already declared the access database (The access Database on page 277), you must do so before declaring this new feature, or you will get the following error when building your new configuration file:

*** ERROR: FEATURE(conncontrol) requires FEATURE(access_db)

Once you have successfully enabled this FEATURE(conncontrol), you may use it to control the number of simultaneous connections, based on IP addresses of hosts or networks, or to set the default limit:

ClientRate:192.168.23.45                   2
ClientRate:127.0.0.1                       0
ClientRate:                                10
ClientRate:10.5.2                          2
ClientRate:IPv6:2002:c0a8:51d2::23f4       5

Here, the first line (as you have seen) limits the number of simultaneous connections from the IP address 192.168.23.45 to no more than two.

In the second line, which specifies zero, the zero means that there is no limit imposed on the overall number of simultaneous connections. This is suitable for the loopback interface address (127.0.0.1) because that is where the local submission version of sendmail delivers its mail.

The third line omits the IP address entirely, thereby setting the default limit for all other IP (unspecified) addresses.

The fourth line shows how network addresses may also be limited.

The last line shows that IPv6 addresses may be specified merely by prefixing each with a literal IPv6:.

Note that the limits we show here are just examples, not recommendations. The limits you choose will depend on your particular circumstances.

conncontrol and delay checks

If you also declare FEATURE(delay_checks) (Accept and Reject per Recipient on page 284), connection control checks will be delayed until after the first envelope recipient has been received. Clearly this makes this connection check less useful than it should be. If you use delay_checks, you may add an additional argument to this FEATURE(conncontrol) to get it to run as early as possible despite the use of that delaying feature:

FEATURE(`conncontrol', `nodelay')

Here, the nodelay is literal and prevents FEATURE(delay_checks) from having any effect on connection controls. Note that if you declare both the delay_checks and FEATURE(conncontrol), FEATURE(delay_checks) must appear first in your mc file.

Terminate connections with 421

Normally, FEATURE(conncontrol) rejects connections with a temporary error:

452 Too many open connections

If the connecting client terminates the connection by sending an SMTP QUIT, connection control terminates as you would expect. But if the client chooses to ignore that return value, the client will be given 4yz SMTP (temporary rejection) replies to all commands it sends until it sends an SMTP QUIT command. Clearly this may not be acceptable at your site. If you want the connection terminated without regard to the connecting client’s behavior, you may do so by adding a second argument to this FEATURE(conncontrol):

FEATURE(`conncontrol', `nodelay', `terminate')
FEATURE(`conncontrol',  ,`terminate')

Here, the terminate is literal and, when present, causes all rejected connections to be rejected with a 421 return code. Note that 421 is special, because it allows sendmail to terminate the connection without waiting for the client to send a QUIT. If you omit the nodelay first argument, you need to use two commas (as in the second example shown earlier) to make terminate the second argument.

FEATURE(delay_checks)

Check SMTP RCPT TO: first V8.10 and later

This feature is fully described in Accept and Reject per Recipient on page 284.

FEATURE(dnsbl)

Reject based on various DNS blacklists V8.10 and later

The original feature was called rbl and caused hosts listed with the original “real-time blackhole list” to be rejected. That feature has been deprecated and replaced by this new FEATURE(dnsbl). With this new feature you can have hosts rejected by any number of real-time blackhole lists, including or excluding the original. This feature is fully described in FEATURE(dnsbl) on page 261.

FEATURE(domaintable)

Rewrite old domain as equivalent to new domain V8.2 and later

Some sites need to use multiple domain names when transitioning from an old domain to a new one. FEATURE(domaintable) enables such transitions to operate smoothly by rewriting the old domain to the new. To begin, create a file of the form:

old.domain    new.domain

In it, the left side of each line has one of possibly many fully qualified hostnames, and the right side has the new name. The makemap(1) program (The makemap Program on page 370) is then used to convert that file into a database.

FEATURE(domaintable) causes a rule such as this to be included in your configuration file:

R $* < @ $+ > $*                 $: $1 < @ $(domaintable $2 $) > $3

Here, each host part of an address in the canonify rule set 3 is looked up in the domaintable map. If it is found, the new name from that map replaces it.

FEATURE(domaintable) enables this lookup by including a K configuration command:

Kdomaintable hash /etc/mail/domaintable

The form of FEATURE(domaintable) is:

FEATURE(`domaintable')

FEATURE(domaintable) is one of those that can take an argument to specify a different form of, or different name for, the database:

FEATURE(`domaintable',`dbm /etc/mail/db/domaintable')

The extra argument causes the aforementioned K command to be replaced with the following one:

Kdomaintable dbm /etc/mail/db/domaintable

You can provide an extra argument that is a literal LDAP:

FEATURE(`domaintable', `LDAP')

The default in this instance becomes the following (we have wrapped the lines to fit the page):

Kdomaintable ldap −1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)
(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))
(sendmailMTAMapName=domain)(sendmailMTAKey=%0))

See ldap (was ldapx) on page 912 for a description of the ldap database type and its −1, -v, and -k switches.

Although this feature might appear suitable for a service provider that wishes to accept mail for client domains, it really is not. Such a service provider should use FEATURE(virtusertable) (FEATURE(virtusertable) on page 645) instead.

FEATURE(enhdnsbl)

Enhanced dnsbl lookups V8.12 and later

This is an enhanced version of FEATURE(dnsbl) and is fully described in FEATURE(enhdnsbl) on page 263.

FEATURE(generics_entire_domain)

Match subdomains in generics table V8.10 and later

This feature extends the use of the FEATURE(genericstable) (FEATURE(genericstable) on page 622). Ordinarily, user addresses whose host part is listed in a special class defined by the GENERICS_DOMAIN mc macro (GENERICS_DOMAIN mc macro on page 624) are looked up in the generics table. Thus, if the generics table contains this rule:

news     news@news.our.domain

and if that special class contains the domain our.domain, only sender addresses of the form news@our.domain would be looked up, and addresses of a subdomain form, such as news@sub.our.domain, would not.

If you declare this FEATURE(generics_entire_domain), and if you also declare contents for that special class with either GENERICS_DOMAIN (GENERICS_DOMAIN mc macro on page 624) or GENERICS_DOMAIN_FILE (GENERICS_DOMAIN_FILE mc macro on page 624), subdomains are also matched. That is, with this feature declared, news@sub.our.domain would also match and be looked up.

FEATURE(genericstable)

Transform sender addresses V8.8 and later

The User Database (userdb on page 942) allows recipient addresses to be changed so that they can be delivered to new hosts. For example, can be transformed with the User Database into . The genericstable provides the same type of transformation on the sender’s address.

To begin, create a file of the form:

user                newuser@new.host.domain
user@host.domain    newuser@new.host.domain

In it, each line begins with the old address, either the user part alone or the full address. On the right is the new address for that sender. One example of a use for this table might be to make the user news always appear as though it was from the news machine:

news            news@news.our.domain
news@our.domain news@news.our.domain

Note that the bare user part (news in the first line) is looked up only if sendmail considers it to be in the local domain. If a domain is listed (as in the second line in the preceding example), that entry is looked up only if it is in a special class defined with the GENERICS_DOMAIN mc macro (GENERICS_DOMAIN mc macro on page 624). If you want subdomains to also match, you must declare FEATURE(generics_entire_domain) (FEATURE(generics_entire_domain) on page 622). Ways to list domains in that special class are outlined later in this chapter.

The makemap(1) program (The makemap Program on page 370) is then used to convert this file into a database:

makemap hash db_file <  text_file

Here, db_file is the name you give to the created database, and text_file is the name of the source text file.

Note that local and nonlocal hosts can appear in the special class defined with the GENERICS_DOMAIN mc macro. Also note that the members of $=w are not automatically placed into this special class.

FEATURE(genericstable) enables this lookup by including a K configuration command:

Kgenerics hash /etc/mail/genericstable

The form for this FEATURE(genericstable) declaration is:

FEATURE(`genericstable')

FEATURE(genericstable) is one of those that can take an argument to specify a different form of, or a different name for, the database:

FEATURE(`genericstable',`dbm -o /etc/mail/genericstable')

The extra argument causes the earlier K command to be replaced with the following one:

Kgenerics dbm -o /etc/mail/genericstable

See -o on page 889 for a description of the K command -o switch.

You can also provide an extra argument that is a literal LDAP:

FEATURE(`domaintable', `LDAP')

The default in this instance becomes the following (we have wrapped the lines to fit the page):

Kgenerics ldap −1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)
(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))
(sendmailMTAMapName=generics)(sendmailMTAKey=%0))

See ldap (was ldapx) on page 912 for a description of the ldap database type and its −1, -v, and -k switches.

The genericstable should be enabled only if you intend to use it. It causes every sender to be looked up in that database.

GENERICS_DOMAIN mc macro

Beginning with V8.8 sendmail, a new mc macro was introduced to make it easier to list domains for use with FEATURE(genericstable). Called GENERICS_DOMAIN, it is used like this:

GENERICS_DOMAIN(`domain1 domain2 etc.')

Each domain that you intend to list should be listed individually and separated from the others by spaces. Multiple GENERICS_DOMAIN lists can be declared in your mc file:

GENERICS_DOMAIN(`domain1')
GENERICS_DOMAIN(`domain2')
GENERICS_DOMAIN(`etc.')

If you are currently declaring the $=G class directly under the LOCAL_CONFIG mc macro, you are encouraged to convert to this new mc macro. Use of it will insulate you from change in the future if a different sendmail class is ever used.

GENERICS_DOMAIN_FILE mc macro

Beginning with V8.8 sendmail, a new mc macro was introduced to make it easier to list domains with FEATURE(genericstable). Called GENERICS_DOMAIN_FILE, it is used like this:

GENERICS_DOMAIN_FILE(`/etc/mail/genericdomains')

This declaration causes the list of domains to be read from the file /etc/mail/genericdomains. Because GENERICS_DOMAIN_FILE is implemented with an F configuration command (The F Class Command on page 857), you can add whatever F command arguments you desire. For example:

GENERICS_DOMAIN_FILE(`-o /etc/mail/genericdomains')

Here, the -o switch makes the presence of the /etc/mail/genericdomains file optional.

If you are currently reading a list of domains from a file declared with an FG configuration command, you are encouraged to convert to this new macro. Use of it will insulate you from change in the future if a different class is ever used.

FEATURE(greet_pause)

Block slamming by detecting advance writes V8.13 and later

This FEATURE(greet_pause) allows you to block sites that write SMTP commands before reading the prior reply. This feature is described in FEATURE(greet_pause)—V8.13 and Later on page 293.

FEATURE(ldap_routing)

Reroute recipients based on LDAP lookups V8.10 and later

This FEATURE(ldap_routing) allows recipients to be rerouted in much the same fashion as the User Database, but by using an LDAP database instead. See ldap (was ldapx) on page 912 for a complete description of this feature.

FEATURE(limited_masquerade)

Only masquerade MASQUERADE_DOMAIN hosts V8.8 and later

Ordinarily, addresses can be masqueraded if they are unqualified (lack a domain part) or if they match any hostname in $=w ($=w on page 876) or in the special class defined by the MASQUERADE_DOMAIN mc macro (MASQUERADE_DOMAIN mc Macro on page 600). Masquerading replaces the hostname part of an address with the fully qualified hostname defined by MASQUERADE_AS.

Some sites handle mail for multiple domains. For these sites, it is important to recognize all incoming mail as local via $=w. On the other hand, only a subset of the hosts in $=w should be masqueraded. Consider, for example, the host our.domain that receives mail for the domains his.domain and her.domain:

Cw our.domain his.domain her.domain

In this scenario, we want all but her.domain to be masqueraded as our.domain. The way to create such exceptions is with FEATURE(limited_masquerade).

FEATURE(limited_masquerade) causes masquerading to be based only on the special class defined by the MASQUERADE_DOMAIN mc macro (MASQUERADE_DOMAIN mc Macro on page 600) and not $=w. You use limited_masquerade like this:

MASQUERADE_AS(`our.domain')
FEATURE(`limited_masquerade')
LOCAL_DOMAIN(`our.domain his.domain her.domain')
MASQUERADE_DOMAIN(`our.domain his.domain')

Here, MASQUERADE_AS is declared first to define how masqueraded domains should be rewritten. Then, FEATURE(limited_masquerade) is declared. The LOCAL_DOMAIN declares all three domains to be recognized as local (that is, it adds them to the class $=w, $=w on page 876). Finally, MASQUERADE_DOMAIN (MASQUERADE_DOMAIN mc Macro on page 600) adds only the hosts that you wish masqueraded to the special class. Specifically, the special class omits the her.domain.

FEATURE(limited_masquerade) causes sendmail to masquerade the hosts in the special class defined by the MASQUERADE_DOMAIN mc macro, without the normal masquerading of the hosts in $=w too. Note that MASQUERADE_DOMAIN is also used to list the domains for the FEATURE(masquerade_entire_domain).

FEATURE(local_lmtp)

Deliver locally with LMTP and mail.local V8.9 and later

The LMTP can be used to transfer mail from sendmail to the program that delivers mail to the local user. Historically, that has been a program, such as /bin/mail, that simply gathered a message on its standard input and wrote that message to the end of the file that the user read. Beginning with V8.9, sendmail can speak the special LMTP language to local delivery programs. The mail.local program, supplied in source form with the sendmail open source distribution, is one such program.

Operating systems that can use that program for local delivery are already set up correctly to use it. Those that are not already set up to use it can use this feature to override the settings in their OSTYPE (OSTYPE( ) m4 macro on page 590) defaults.

Building and using mail.local is described in The mail.local Delivery Agent on page 359. Once it is built and installed, you can use this FEATURE(local_lmtp) to enable use of that program. One way to do that looks like this:

FEATURE(`local_lmtp')
MAILER(`local')

Note that this feature must be declared before you define the local delivery agent. This feature defines both the use of mail.local and the place where that program can be found. By default, that location is /usr/libexec/mail.local. If you installed mail.local in a different place or under a different name, you can specify that location like this:

FEATURE(`local_lmtp', `/usr/sbin/mail.local')
MAILER(`local')

This feature also sets the LOCAL_MAILER_FLAGS (Pre-V8.10 mc modification of F= on page 744) to a default of F=PSXfmnz9, sets the LOCAL_MAILER_ARGS (How to define A= with your mc configuration on page 738) to a default of mail.local -l, and sets the LOCAL_MAILER_DSN_DIAGNOSTIC_CODE (T= on page 754) to a default of SMTP. If you need to change any of these, you can do so with the proper mc macro. Just be sure you make all your changes after FEATURE(local_lmtp) was declared, and before the local delivery agent is declared:

FEATURE(`local_lmtp')
                            ← define your new values here
MAILER(`local')

Beginning with V8.13, sendmail allows you to add a third, optional argument that supplies the command-line arguments for the mail.local program (as well as for any other programs that use LMTP, such as procmail). Essentially, the third argument is supplied as the value to the A= equate (A= on page 738). For example, the following supplies the −7 command-line switch (don’t advertise 8-bit MIME support) for the mail.local program:

FEATURE(`local_lmtp', , `mail.local -l −7')

And the following enables procmail(1) to be used for LMTP delivery:

FEATURE(`local_lmtp', `/mail/bin/procmail', `procmail -Y -a $h -z')

Note that the second argument, if unused, must be present (but empty) if you wish to specify a third argument. Also note that you should manually append new command-line switches to the default switches, rather than replace them.

Also note that prior to V8.13, this FEATURE(local_lmtp) sets the default LOCAL_MAILER_FLAGS to F=PSXfmnz9. Beginning with V8.13, the F=f flag (F=f on page 771) is no longer set as part of that default. Recall that if sendmail is run with a -f command-line argument (-f on page 241) and if the F=f delivery agent flag is specified, the A= for this local delivery agent will have the two additional arguments -f and $g inserted between its argv[0] and argv[1].

FEATURE(local_no_masquerade)

Don’t masquerade local mail V8.12 and later

Ordinarily, the MASQUERADE_AS mc configuration macro (MASQUERADE_AS mc Macro on page 600) causes header, envelope, sender, and recipient addresses to appear as though they were sent from the masquerade host. Sometimes it is desirable to perform masquerading only when mail is sent offsite, and not to masquerade when mail is sent from one user to another locally.

For just such situations, FEATURE(local_no_masquerade) is available. You declare it like this:

FEATURE(`local_no_masquerade')

You must make this declaration before you declare the local delivery agent. If you mistakenly declare local first, like this:

MAILER(`local')                     ← wrong, local must not be first
FEATURE(`local_no_masquerade')

you will see the following error, and your configuration file will be incomplete:

*** MAILER(`local') must appear after FEATURE(`local_no_masquerade')

FEATURE(local_procmail)

Use procmail(1), etc. as local delivery agent V8.7 and later

The procmail(1) program can handle a user’s mail autonomously (for example, sorting incoming mail into folders based on subject) and can function as a sendmail delivery agent. Some administrators prefer procmail(1) in this latter role over normal Unix delivery agents. If this is your preference, you can easily use procmail(1) in that role with FEATURE(local_procmail):

FEATURE(`local_procmail')

FEATURE(local_procmail) changes the P=, F=, and A= equates for the local delivery agent into:

P=/usr/local/bin/procmail                  ← see §20.5.11 on page 748
F=SPfhn9                                   ← see §20.5.6 on page 743
A=procmail -Y -a $h -d $u                  ← see §20.5.2 on page 738

If you have installed procmail in a different location, you can specify that alternative location with a second argument:

FEATURE(`local_procmail', `/admin/mail/bin/procmail')

Beginning with V8.10, sendmail allows this FEATURE(local_procmail) to accept additional arguments to define the A= values (set with LOCAL_MAILER_ARGS; How to define A= with your mc configuration on page 738) and the F= values (set with LOCAL_MAILER_FLAGS; Pre-V8.10 mc modification of F= on page 744). Those additional arguments were added to support other programs in addition to procmail(1), such as maildrop(1) and scanmails(1).[241] They are used like this:

FEATURE(`local_procmail', `/admin/mail/bin/procmail', `A= stuff here', `F= stuff
here')

If you need to specify command-line arguments different from the defaults shown earlier, you can do so either with the second argument (the A= stuff here), or by using the LOCAL_MAILER_ARGS (How to define A= with your mc configuration on page 738) mc macro:

FEATURE(`local_procmail')
define(`LOCAL_MAILER_ARGS', `procmail -Y -a hidden.domain -d $u')

If you need to use F= flags different from those shown, you can do so either with the third argument (the F= stuff here), or by using the LOCAL_MAILER_FLAGS (Pre-V8.10 mc modification of F= on page 744) mc macro:

FEATURE(`local_procmail')
define(`LOCAL_MAILER_FLAGS', `SPfhn')

Both must follow FEATURE(local_procmail).

Use another program instead of procmail

You can also use FEATURE(local_procmail) (FEATURE(local_procmail) on page 627) to include support for the other programs. For example, the following line in your mc can be used to change the local delivery agent to use the maildrop(8) program:

FEATURE(`local_procmail', `/usr/local/bin/maildrop', `maildrop -d $u')

But before you do this, first create a configuration file without this feature that looks at the F= delivery agent equate for the local delivery agent. Then add the earlier line and create another configuration file. Note any differences between the F= delivery agent equates from the two configuration files and decide which are important to retain. If you decide that there are more F= delivery agent flags to retain than were created by FEATURE(local_procmail), you can create a superset and add that superset declaration to FEATURE(local_procmail) like this:

FEATURE(`local_procmail', `/usr/local/bin/maildrop', `maildrop -d $u', `SPfhn9A')

The maildrop(8) program is intended for use only with Intel-based architectures, and is available with Debian GNU/Linux from http://packages.debian.org/stable/mail/maildrop.html.

Note that despite our description of maildrop(1) in this section, you can use this FEATURE(local_procmail) to install other programs in the role of the local delivery program. But test carefully before releasing any new program in this role.

FEATURE(lookupdotdomain)

Enable .domain secondary access.db lookups V8.12 and later

Normally, lookups of hosts in the access database (The access Database on page 277) are literal. That is, host.domain is looked up first as host.domain and then as domain. For example, the host hostA.CS.Berkeley.edu would first be looked up as hostA.CS.Berkeley.edu, then as CS.Berkeley.edu, then as Berkeley.edu, and lastly as edu. None of the components is looked up with a leading dot. That is, host.domain’s second lookup is domain, not .domain.

If you wish each lookup to also include a lookup of the domain part with a dot prefix, you can declare this FEATURE(lookupdotdomain):

FEATURE(`lookupdotdomain')

Once declared, all lookups of hosts in the access database will include another lookup with the domain part prefixed with a dot. That is, for example, without lookupdotdomain declared, the lookups of hostA.CS.Berkeley.edu will look like this:

hostA.CS.Berkeley.edu
CS.Berkeley.edu
Berkeley.edu
edu

But with lookupdotdomain declared, the lookups of hostA.CS.Berkeley.edu will look like this:

hostA.CS.Berkeley.edu
.CS.Berkeley.edu
CS.Berkeley.edu
.Berkeley.edu
Berkeley.edu
.edu
edu

This allows anything.cs.berkeley.edu to be treated differently from cs.berkeley.edu. For example:

.cs.berkeley.edu      REJECT
cs.berkeley.edu       OK

Here, anything that ends in .cs.berkeley.edu will be rejected, whereas anything ending in cs.berkeley.edu will be accepted.

Note that this FEATURE(lookupdotdomain) requires that the access.db be declared first. If you reverse the declarations (this feature first), you will get the following warning and your resulting configuration file will not be what you expect:

*** ERROR: FEATURE(`lookupdotdomain') requires FEATURE(`access_db')

Also note that this FEATURE(lookupdotdomain) should not be used in conjunction with the FEATURE(relay_hosts_only) (FEATURE(relay_hosts_only) on page 273) because that feature disables subdomain lookups. If you declare FEATURE(relay_hosts_only) first and then declare this feature, the following warning will be printed:

*** WARNING: FEATURE(`lookupdotdomain') does not work well with FEATURE(`relay_hosts_
only')

If you declare this feature first, then FEATURE(relay_hosts_only), no warning will be printed.

FEATURE(loose_relay_check)

Allow %-hack relaying V8.9 and later

See FEATURE(loose_relay_check) on page 270 for a complete description of this feature and how it interacts with other relaying features.

FEATURE(mailertable)

Database selects new delivery agents V8.1 and later

A mailertable is a database that maps host.domain names to special delivery agent and new domain name pairs. Essentially, it provides a database hook into the parse rule set 0. Because mailertable follows handling of the local host, none of the hosts in the $=w ($=w on page 876) will be looked up with this feature.

New domain names that result from a mailertable lookup are used for routing but are not reflected in the headers of messages.

To illustrate, one mapping in a source text file could look like this:

compuserv.com    smtp:compuserve.com

The key portion (on the left) must be either a fully qualified host and domain name, such as lady.bcx.com, or a partial domain specification with a leading dot, such as .bcx.com. On the right, the delivery agent name must be separated from the new domain name by a colon. The source text file is converted into a database with the makemap(1) program (The makemap Program on page 370). Beginning with V8.8 sendmail, the host part of the return value can also specify a user:

downhost.com     smtp:postmaster@mailhub.our.domain
                          ↑
                     V8.8 and later

The host.domain is looked up in the mailertable database, and if that host.domain is found, a delivery agent, colon, and domain pair are returned. If the delivery agent (in mailertable) is error, the #error delivery agent is called. This allows error messages to be put into the database, as, for example:

badhost    error:nohost mail to badhost is prohibited      ← V8.9 and earlier
badhost    error:5.7.0:550 mail to badhost is prohibited   ← V8.10 and later

The first token following the error: is passed in the $@ part of the #error delivery agent. Note that prior to V8.10, you had to use words or <sysexits.h > codes here, not DSN values (such as 5.7.0), because the latter were wrongly broken up into five tokens. Beginning with V8.10, you can also use DSN values here, and they will be handled properly. See error on page 720 for a full description of the #error delivery agent and for tables of useful words and codes for the $@ part.

If the host is found and it is not an error delivery agent, that delivery agent is selected. Otherwise, the unresolved host.domain is passed to other rule sets for further mailertable lookups. Those other rule sets recursively strip the leftmost part of the host.domain away and look up the result in the mailertable. This continues until either a match is found or only a dot is left. Then that dot is looked up to give you a hook for failed lookups:

.     smtp:smarthost

As a special case, the delivery agent named local causes slightly different behavior in that it allows the name of the target user to be listed without a host part:

virtual.domain    local:bob

Here, any mail that is received for the virtual.domain is delivered to the user bob on the local machine. If the user part is missing:

virtual.domain    local:

the mail is delivered to the user part of the original address. This latter approach can be beneficial when you have a huge number of hosts listed in $=w. Consider moving those hosts to the mailertable database, and placing local: on the righthand side of each entry.[242]

The form for FEATURE(mailertable) is:

FEATURE(`mailertable')

This causes the following database declaration in the configuration file:

Kmailertable hash /etc/mail/mailertable

Here, the hash is derived from the setting of the DATABASE_MAP_TYPE mc configuration macro (Set a Default Database-Map Type for Features on page 897) and the /etc/mail is derived from the setting of the MAIL_SETTINGS_DIR mc macro (The MAIL_SETTINGS_DIR mc Macro on page 68). If you wish to change the defaults without having to change these two mc configuration macros, you can simply define that new default by adding a second argument to the feature declaration:

FEATURE(`mailertable',`dbm -o /etc/mail/mailertable')

Here, the database type was changed to dbm, and a -o database switch was added to make the presence of the database optional.

You can also provide an extra argument that is a literal LDAP:

FEATURE(`domaintable', `LDAP')

The default in this instance becomes the following (we have wrapped the lines to fit the page):

Kgenerics ldap −1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)
(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))
(sendmailMTAMapName=mailer)(sendmailMTAKey=%0))

See ldap (was ldapx) on page 912 for a description of the ldap database type and its −1, -v, and -k switches.

FEATURE(mailertable) was inspired by the IDA version of sendmail.

In The parse Rule Set 0 on page 696, we deal with the flow of rules through the parse rule set 0. For now, merely note that FEATURE(mailertable) fits into the flow of rules through the parse rule set 0 like this:

  1. Basic canonicalization (list syntax, delete local host, etc.)

  2. LOCAL_RULE_0 (LOCAL_RULE_0 mc macro on page 596)

  3. FEATURE(ldap_routing) (FEATURE(ldap_routing) on page 922)

  4. FEATURE(virtusertable) (FEATURE(virtusertable) on page 645)

  5. Addresses of the form “user@$=w” passed to local delivery agent

  6. FEATURE(mailertable)

  7. UUCP, BITNET_RELAY ($B on page 808), etc.

  8. LOCAL_NET_CONFIG

  9. SMART_HOST (SMART_HOST mc macro on page 597)

  10. SMTP, local, etc. delivery agents

FEATURE(masquerade_entire_domain)

Masquerade all hosts under a domain V8.8 and later

Ordinarily, masquerading transforms any host from a list of hosts in the class $=w ($=w on page 876) into the host defined by MASQUERADE_AS. If domains are also masqueraded with MASQUERADE_DOMAIN, they too are transformed. For example, consider these declarations:

MASQUERADE_AS(`our.domain')
MASQUERADE_DOMAIN(`her.domain')

The first line causes any host part of an address contained in the class $=w to be transformed into our.domain. The second line transforms the domain part of her.domain into our.domain.

The key point here is that the domain part her.domain will be transformed, whereas hosts under that domain will not be transformed:

george@her.domain          becomes  →    george@our.domain
george@host.her.domain     remains  →    george@host.her.domain

If you wish MASQUERADE_DOMAIN to transform all the hosts under the declared domain, you can use FEATURE(masquerade_entire_domain):

MASQUERADE_AS(`our.domain')
MASQUERADE_DOMAIN(`her.domain')
FEATURE(`masquerade_entire_domain')

This feature extends masquerading of her.domain to include all the hosts under that domain:

george@her.domain          becomes →    george@our.domain
george@host.her.domain     becomes →    george@host.her.domain
george@host.sub.her.domain becomes →    george@our.domain

Note that you can masquerade only domains that are under your direct jurisdiction and control. Also note that domain masquerading is intended for actual domains. Virtual domains are better handled with the FEATURE(genericstable) (FEATURE(genericstable) on page 622).

FEATURE(masquerade_envelope)

Masquerade the envelope as well as headers V8.7 and later

Ordinarily, masquerading (Masquerading on page 598) affects only the headers of email messages, but sometimes it is also desirable to masquerade the envelope.[243] For example, error messages are often returned to the envelope-sender address. When many hosts are masquerading as a single host, it is often desirable to have all error messages delivered to that central masquerade host.

FEATURE(masquerade_envelope) causes masquerading to include envelope addresses:

MASQUERADE_AS(`our.domain')        ← masquerade headers
FEATURE(`masquerade_envelope')     ← also masquerade the envelope

These mc lines cause all envelope addresses (where the host part is declared as part of class $=w; $=w on page 876) to be transformed into our.domain. See MASQUERADE_DOMAIN for a way to also masquerade other domains, and see FEATURE(masquerade_entire_domain) for a way to also masquerade all the hosts under other domains.

In general, masquerade_envelope is recommended for uniform or small sites. Large or variegated sites might prefer to tailor the envelope on a subdomain-by-subdomain or host-by-host basis.

FEATURE(mtamark)

Experimental mtamark support V8.13 and later

FEATURE(mtamark) provides experimental support for the mtamark IETF proposal. This feature is described in FEATURE(mtamark)—V8.13 and Later, Experimental on page 295.

FEATURE(msp)

Create a mail submission cf file V8.12 and later

FEATURE(msp) is used to create a submit.cf file for use with a mail submission program, which is a command-line sendmail that functions as a mail submission agent (MSA).

In its simplest form, this feature is used like this:

FEATURE(`msp')

Here, a configuration file suitable for an MSA will be created. The resulting MSA will forward any message it gathers to the host localhost and will do so without looking up MX records for localhost. Unless told otherwise (as described later), the MSA will submit messages locally to port 25.

In the event that mail does not go to the local host, first check to see that the host named localhost is correctly defined on your machine:

% nslookup localhost
Server:  your.name.server
Address:  123.45.67.89

Name:    localhost
Address:  127.0.0.1

If the address printed is not 127.0.0.1 for IPv4, or ::1 for IPv6, either correct the problem with your own name server, or contact your ISP and demand a correction. If that fails, you can still send to the local host by putting the correct address directly into the msp declaration as an argument:

FEATURE(`msp', `[127.0.0.1]')

Here, the square brackets tell sendmail that it is dealing with an address, rather than a hostname.

The argument can also be used to tell the MSA to connect to a host other than localhost:

FEATURE(`msp', `otherhost')

Here, submitted mail will be forwarded to the host otherhost for delivery, or for relaying outward. Unless you suppress it, the MSA will look up MX records for otherhost and, if found, will deliver to the MX records found. If that is inappropriate, you can suppress MX lookups by surrounding the hostname with square brackets:

FEATURE(`msp', `[otherhost]')     ← suppress MX lookups

A second argument can be supplied to this feature which will cause the MSA to submit mail on port 587 instead of on port 25:

FEATURE(`msp', `[otherhost]', `MSA')

If the second argument is a literal MSA, the MSA will connect to port 587. If it is anything else, no change in port will be made.

The second argument can be present and the first absent if you wish to connect to port 587 on localhost:

FEATURE(`msp', `', `MSA')

If you wish to have all envelope and header addresses rewritten to appear as though they are from otherhost, you can combine the MASQUERADE_AS mc configuration macro with this feature:

MASQUERADE_AS(`otherhost')
FEATURE(`msp', `[otherhost]', `MSA')

This feature is used to create the submit.cf file. See The submit.cf File on page 66 for a description of this process. Also see cf/SECURITY and cf/README in the source distribution.

FEATURE(nocanonify)

Don’t canonify with $[ and $] V8.1 and later

Ordinarily, sendmail tries to canonify (add a domain to) any hostname that lacks a domain part, and to canonify (ensure a correctly formed domain) for any host with a domain. It does this by passing the unadorned hostname to the $[ and $] operators (Canonicalize Hostname: $[ and $] on page 668). FEATURE(nocanonify) prevents sendmail from passing addresses to $[ and $] for canonicalization. This is generally suitable for use by sites that act only as mail gateways or that have MUAs that do full canonicalization themselves.

The form for FEATURE(nocanonify) is:

FEATURE(`nocanonify')

If you only want hostnames without a domain part canonicalized, you can add a second argument like this:

FEATURE(`nocanonify', `canonify_hosts')

Note that FEATURE(nocanonify) disables only one possible use of $[ and $] in the configuration file. If the pre-V8.9 FEATURE(nouucp) is omitted (thereby including UUCP support), addresses that end in a .UUCP suffix still have the preceding part of the address canonified with $[ and $] even if FEATURE(nocanonify) was declared.

Also note that the Modifiers=C equate (DaemonPortOptions=Modify= on page 996) for the DaemonPortOptions option does the same thing as this FEATURE(nocanonify), but does so on a port-by-port basis.

Sending out any unqualified addresses can pose a risk. To illustrate, consider a header where the local host is here.us.edu:

To: hans@here.us.edu
Cc: jane@here, george@fbi.us.gov
From: you@here.us.edu

The assumption here is that this will go to the local hub machine for delivery, and that the hub will view jane as a local user and perform local delivery.

But consider a hub that has two MX records (a rather small number). One points to itself so that it always gets mail first. The other points to a host at another host, off campus. If the hub is down but its clients are up, mail will be delivered to the other campus machine on the assumption that it will hold the mail until the hub returns to service. The problem is that the address jane@here is unqualified (incomplete) when it gets to the other campus machine, and will bounce because a host in jane@here is unknown.

Beginning with V8.10 sendmail, you can list domains that you want canonified, even though you have enabled this feature. You add those domains to a special sendmail class using either of two new macros:

CANONIFY_DOMAIN(`list of domains')
CANONIFY_DOMAIN_FILE(`/path')

The first form causes the list of domains to be added to your configuration file using the C configuration command. The second causes the file indicated by /path to be read (using the F configuration command) for a list of domains. For example, to require that the local domain be always canonified you can use a declaration such as this:

CANONIFY_DOMAIN(`$=m')

Subdomains (such as sub.your.domain) will be matched when you list just the domain (your.domain). Therefore, it is only necessary to list top-level domains to have a domain and its subdomains canonicalized.

FEATURE(nodns)

Omit DNS support from configuration file V8.6 through V8.8, removed V8.13

This feature was still offered through V8.12, but as of V8.9 it did nothing. Instead, beginning with V8.7 sendmail, you should either use the service-switch file (ServiceSwitchFile on page 1088) to control use of DNS or compile a sendmail without DNS support (NAMED_BIND on page 124). This feature was removed as of V8.13.

FEATURE(no_default_msa)

Disable automatic listening on MSA port 587 V8.10 and later

When V8.10 sendmail starts up in daemon mode, it listens both on the normal port 25 for incoming SMTP connections, and on port 587 for the local submission of mail. This later role is that of an MSA (documented in RFC2476).

Although listening on another port by default might seem like a bad idea, it is actually a very good way to enable a smooth transition to the adoption of MSA services. The MTA, for example, when listening on port 587 will limit the amount of automatic canonicalization it does on unqualified addresses. This is good because that canonicalization is really the role of an MSA connecting to that port.

Although we highly recommend that you leave this service enabled, you might prefer to disable it. If so, you can disable it with this FEATURE(no_default_msa):

FEATURE(`no_default_msa')

Additional information about MSAs can be found in our discussion of the DaemonPortOptions option (DaemonPortOptions on page 993).

Because there is no way to directly change the settings of the MSA in your mc configuration file, you can use the following trick if you need to change, say, the M= equate from M=E to M=Ea:

FEATURE(`no_default_msa')
DAEMON_OPTIONS(`Port=587,Name=MSA,M=Ea')

Here, this feature prevents the automatic creation of an mc configuration entry for an MSA. You then insert your own declaration, with your new settings.

Be aware, however, that this feature also disables the listening daemon on port 25. If you use this feature, be certain to redeclare a port 25 daemon if you need one:

FEATURE(`no_default_msa')
DAEMON_OPTIONS(`Port=587,Name=MSA,M=Ea')
DAEMON_OPTIONS(`Port=smtp, Name=MTA')

FEATURE(notsticky)

Don’t differ user from user@local.host V8.1 through V8.6

Mail addressed to a local user that includes the name of the local host as part of the address (i.e., user@local.host) is delivered locally. From V8.1 to V8.6 sendmail, if the address has a host part, lookups in the User Database (userdb on page 942) and the additional processing of the localaddr rule set 5 (The localaddr Rule Set 5 on page 700) are skipped. Under V8.6, addresses with just the user part are always processed by the User Database and the localaddr rule set 5.

The V8.6 FEATURE(notsticky) changes this logic. If this feature is chosen, all users are looked up in the User Database, and the additional processing done by the localaddr rule set 5 is skipped.

Beginning with V8.7, the default is as though notsticky were used, and thus the FEATURE(stickyhost) can be used to restore the previous default.

FEATURE(nouucp)

Eliminate all UUCP support V8.1 and later

If your site wants nothing to do with UUCP addresses, you can set FEATURE(nouucp). Among the changes this causes are that the ! character is not recognized as a separator between hostnames, and all the macros that relate to UUCP (UUCP Support on page 606) are ignored. This feature truly means no UUCP.

You declare nouucp like this:

FEATURE(`nouucp')               ← through V8.9
FEATURE(`nouucp',`nospecial')   ← V8.10 and later
FEATURE(`nouucp',`reject')      ← V8.10 and later

Beginning with V8.10, an argument has been added that can be either nospecial or reject. The nospecial causes sendmail to simply ignore the ! character. The reject causes sendmail to reject mail with the ! character. If you declare neither argument (as in the first line), and you are using sendmail V8.10 or above, you will see the following error, and your configuration file will fail to build properly:

*** ERROR: missing argument for FEATURE(nouucp):
                use `reject' or `nospecial'. See cf/README.

Note that all the other UUCP declarations (such as UUCP_RELAY) will be ignored if you use this nouucp.

When you use this feature on any machine that forwards uucp mail to a central mail hub machine, be certain that you also declare it on that mail hub machine. If you don’t take this precaution, you open up your mail hub to risk of unintended relaying.

FEATURE(nullclient)

Relay all mail through a mail host V8.6 and later

Some sites have a number of workstations that never receive mail directly. They are usually clustered around a single mail server. Normally, all clients in a cluster like this send their mail as though the mail is from the server, and they relay all mail through that server rather than sending directly. If you have such a configuration, use a declaration such as the following:

FEATURE(`nullclient', `host.domain')

Note that the host.domain must be the fully qualified domain name of your mail server or relay to the outside world.

If you wish to prevent the nullclient version of sendmail from trying to access aliases, add this line to your .mc file:

undefine(`ALIAS_FILE')

Note that this works only with V8.8 and later .mc files.

FEATURE(promiscuous_relay)

Allow unbridled relaying V8.9 and later

The relaying of outside mail through your site to another outside site is turned off by default. But if you want to allow this old and dangerous behavior, declare this FEATURE(promiscuous_relay). This feature, how it is used, and how it fits into relaying and spam handling in general are explained in FEATURE(promiscuous_relay) on page 271.

FEATURE(preserve_local_plus_detail)

Retain plussed addresses for delivery V8.12 and later

Beginning with V8.7, sendmail offered plus addressing (Plussed Detail Addressing on page 476) in its aliases file as a means to handle special aliasing needs. Usually, the plus part is stripped from the user part of the address before final delivery. That is, mail to bob+nospam would be delivered to bob.

As new delivery programs are developed, it might become desirable to pass the unstripped address to such programs. Such a delivery program would see bob+nospam as part of its command line.

If yours is such a delivery program, you can enable this latter behavior by defining this feature:

FEATURE(`preserve_local_plus_detail')

Note that this feature should not be enabled unless you are absolutely sure your delivery program will do the correct thing. If you wrongly enable this feature, mail delivery will fail.

FEATURE(preserve_luser_host)

Preserve recipient host with LUSER_RELAY V8.12 and later

Normally the LUSER_RELAY mc configuration macro (LUSER_RELAY mc Macro on page 605) causes the domain part of recipient addresses to be replaced with the value given to the LUSER_RELAY macro. If this behavior is undesirable, you can define this FEATURE(preserve_luser_host) to correct it:

FEATURE(`preserve_luser_host')

With this feature defined, the recipient hostname is preserved. But note that it is preserved only for delivery agents that take a hostname. The default local delivery agent does not.

FEATURE(queuegroup)

Select queue groups via the access database V8.12 and later

As of V8.12, you can manage queues via queue groups. This feature allows you to select queue groups by using entries in the access database. See The FEATURE(queuegroup) and the access Database on page 416 for a full description of queue groups and this feature.

FEATURE(ratecontrol)

Limit the rate at which other MTAs may connect to yours V8.13 and later

This FEATURE(ratecontrol) allows you to use the access database to control the rate at which other machines can connect to your server.[244] The rate is based on the setting of the ConnectionRateWindowSize option (ConnectionRateWindowSize on page 989), which defaults to 60 seconds. So, for example, it you want to reject more than 10 connections per minute (60 seconds) from the IP address 192.168.23.45, you would put the following into your access database source file:

ClientRate:192.168.23.45     10

Here, if the host with the IP address 192.168.23.45 connects to your server more than 10 times in a given 60 seconds (the default window of time), the 11th and subsequent connections during that interval will be rejected.

You enable the FEATURE(ratecontrol) like this:

FEATURE(`ratecontrol')

But note, if you have not already declared the access database (The access Database on page 277), you must do so before declaring this new feature, or you will get the following error when building your new configuration file:

*** ERROR: FEATURE(ratecontrol) requires FEATURE(access_db)

Once you have successfully enabled this FEATURE(ratecontrol), you may use it to control the connection rate by the IP addresses of hosts or networks, or to set the default limit:

ClientRate:192.168.23.45                             2
ClientRate:127.0.0.1                                 0
ClientRate:                                          10
ClientRate:10.5.2                                    2
ClientRate:IPv6:2002:c0a8:51d2::23f4                 5

Here, the first line (as you have seen) limits the number of connections from the IP address 192.168.25.45 to no more than two connections per minute (where the ConnectionRateWindowSize option, ConnectionRateWindowSize on page 989, is set to 60 seconds or one minute).

In the second line, which specifies a zero limit, the zero means there is no limit imposed on the number of simultaneous connections allowed. A zero limit is suitable for the loopback interface address (127.0.0.1) because that is the interface over which the local submission version of sendmail delivers its mail.

The third line omits the IP address entirely, thereby setting a default limit for all other IP (unspecified) addresses. Without this default setting, any unspecified address would be unlimited.

The fourth line shows how network addresses may also be limited.

The last line shows that IPv6 addresses can be specified merely by prefixing each with a literal IPv6:.

Note that the rates we show here are just examples, not recommendations. The rates you choose as limits will depend on your particular circumstances.

ratecontrol and delay checks

If you also declare FEATURE(delay_checks) (Accept and Reject per Recipient on page 284), rate control checks will be delayed until after the first envelope recipient has been received. Clearly this makes this rate-control check less useful than it should be. If you use delay_checks, you may add an additional argument to this FEATURE(ratecontrol) to get it to run as early as possible despite the use of that delaying feature:

FEATURE(`ratecontrol', `nodelay')

Here, the nodelay is literal and prevents FEATURE(delay_checks) from having any effect on connection-rate controls. Note that if you declare both FEATURE(delay_checks) and FEATURE(ratecontrol), FEATURE(delay_checks) must appear first in your mc file.

Terminate connections with 421

Normally, FEATURE(ratecontrol) rejects connections with a temporary error:

452 Connection rate limit exceeded

If the connecting client terminates the connection by sending an SMTP QUIT, rate control terminates as you would expect. But if the client chooses to ignore that return value, the client will be given 4yz SMTP (temporary failure) replies to all commands it sends until it sends an SMTP QUIT command. Clearly this may not be acceptable at your site. If you want the excess connection rates terminated without regard to the connecting client’s other behavior, you may do so by adding a second argument to this FEATURE(ratecontrol):

FEATURE(`ratecontrol', `nodelay', `terminate')
FEATURE(`ratecontrol',  , `terminate')

Here, the terminate is literal and, when present, causes all rejected connections to be rejected with a 421 SMTP return code. Note that 421 is special, because it allows sendmail to terminate the connection without waiting for the client to send a QUIT. Note that if you omit the nodelay first argument, you need to use two commas (as in the second example shown earlier) to make terminate the second argument.

FEATURE(rbl)

Reject connections based on rbl.maps.vix.com V8.9 through V8.11

FEATURE(rbl) was introduced in V8.10 as an aid to blocking spam email. But because it directly looked up hosts at rbl.maps.vix.com, it was soon rendered obsolete. V8.11 sendmail replaced FEATURE(rbl) with FEATURE(dnsbl) (FEATURE(dnsbl) on page 261), which allows you to specify the host to use for lookups. V8.12 sendmail extended that ability further with FEATURE(enhdnsbl) (FEATURE(enhdnsbl) on page 263), which also allows you to customize error messages and determine what to do with temporary failures.

FEATURE(redirect)

Add support for address.REDIRECT aliases V8.1 and later

FEATURE(redirect) allows aliases to be set up for retired accounts. Those aliases bounce with an indication of the new forwarding address. A couple of lines from such an aliases(5) file might look like this:

george:   george@new.site.edu.REDIRECT
william:  wc@creative.net.REDIRECT

FEATURE(redirect) causes mail addressed to george, for example, to be bounced with a message such as this:

551 5.7.1 User not local; please try <george@new.site.edu>

Note that the message is bounced and not forwarded. No notification is sent to the recipient’s new address.

The form of FEATURE(redirect) is:

FEATURE(`redirect')

The actual bounce is caused by calling the error delivery agent with an RHS such as this:

$#error $@ 5.1.1 $: "551 User not local; please try " <$1@$2>

The 5.1.1 is a DSN error code (see RFC1893), and the 551 is an SMTP code (see RFC821).

If your site’s policy is to notify and forward, you can use an entry such as this in your aliases database:

george:   george@new.site.edu.REDIRECT, george@new.site.edu

Here, the sender will receiver notification of the new address, and the recipient will receive the original messages.

A problem can arise when spam messages are sent to a REDIRECT address. Because some spam is sent with a fictitious envelope sender, the bounce caused by the REDIRECT will itself bounce too. This creates what is called a double bounce (a bounce notification that bounces). Double bounces are delivered to the address defined by the DoubleBounceAddress option (DoubleBounceAddress on page 1025). If spam bounces of REDIRECT addresses start to annoy you, consider redefining the DoubleBounceAddress option to deliver double bounce notification to a less offensive address, such as an address aliased to /dev/null. But be aware that this will cause all double bounces to be sent to that address, not just spam double bounces.

FEATURE(relay_based_on_MX)

Relay based on MX records V8.9 and later

Ordinarily, the decision to relay is not based on MX records. Relaying based on MX records poses a risk that outsiders might use your server as a relay for their site (that is, they might set up an MX record pointing to your mail server, and you will relay mail addressed to them without any prior arrangement).

This FEATURE(relay_based_on_MX) reverses that policy. This feature, how it is used, and how it fits into relaying and spam handling are explained in FEATURE(relay_based_on_MX) on page 271.

FEATURE(relay_entire_domain)

Relay based on $=m V8.9 and later

Ordinarily, only hosts listed with RELAY_DOMAIN (The RELAY_DOMAIN mc macro on page 269) are allowed to relay through the local machine. This FEATURE(relay_entire_domain) allows domains listed in the $=m class to also be relayed, including any hosts that end in any of the domains listed in the $=m class. This feature, how it is used, and how it fits into relaying and spam handling are explained in FEATURE(relay_entire_domain) on page 272.

FEATURE(relay_hosts_only)

Relay individual hosts, not domains V8.9 and later

Ordinarily, the names listed with RELAY_DOMAIN (those allowed to relay through the local machine, The RELAY_DOMAIN mc macro on page 269) are names of domains. By declaring this FEATURE(relay_hosts_only), you cause the names in that list to be interpreted as the names of hosts, not domains. This feature, how it is used, and how it fits into relaying and spam handling are explained in FEATURE(relay_hosts_only) on page 273.

FEATURE(relay_local_from)

Relay based on MAIL From: V8.9 and later

Ordinarily, permission to relay is not based on the SMTP MAIL From: command. This feature changes that behavior. How it is used and how it fits into relaying and spam handling are explained in FEATURE(relay_local_from) on page 273.

FEATURE(relay_mail_from)

Relay based on MAIL From: and on RELAY in access_db V8.10 and later

By declaring this FEATURE(relay_mail_from), you enable relaying for envelope sender addresses based on the RELAY value in the access database. This feature, how it is used, and how it fits into relaying and spam handling are explained in FEATURE(relay_mail_from) on page 274.

FEATURE(require_rdns)

Reject unresolvable IP addresses V8.14 and later

This FEATURE(require_rdns) rejects clients whose IP address cannot be properly resolved with a reverse lookup. This feature is described inFEATURE(require_rdns)—V8.14 and Later on page 296.

FEATURE(smrsh)

Use smrsh (sendmail restricted shell) V8.7 and later

Although sendmail tries to be very safe about how it runs programs from the aliases(5) and ~/.forward files (Delivery Via Programs on page 468), it still can be vulnerable to some internal attacks. To limit the selection of programs that sendmail is allowed to run, V8 sendmail includes source and documentation for the smrsh (sendmail restricted shell) program. See The smrsh Program on page 379 for a full description of the smrsh program.

FEATURE(stickyhost)

Differ user from user@local.host V8.7 and later

Beginning with V8.7 sendmail, addresses with and without a host part that resolve to local delivery are handled in the same way. For example, user and user@local.host are both looked up with the User Database (userdb on page 942) and processed by the localaddr rule set 5 (The localaddr Rule Set 5 on page 700). This processing can result in those addresses being forwarded to other machines.

With FEATURE(stickyhost), you can change this behavior:

FEATURE(`stickyhost')

By defining stickyhost, you are telling sendmail to mark addresses that have a local host part as “sticky”:

user               ← not sticky
user@local.host    ← sticky

Sticky hosts tend to be delivered on the local machine. That is, they are not looked up with the User Database and are not processed by the localaddr rule set 5.

One use for this feature is to create a domain-wide namespace. In it, all addresses without a host part will be forwarded to a central mail server. Those with a local host part will remain on the local machine and be delivered in the usual local way.

Note that this is opposite the behavior of the former FEATURE(notsticky) of V8.6.

FEATURE(use_client_ptr)

Replace IP address with ${client_ptr} in check_relay V8.13 and later

This FEATURE(use_client_ptr) causes the check_relay rule set to use the value of ${client_ptr} in place of the client’s IP address. This feature is fully described in FEATURE(use_client_ptr)—V8.13 and Later on page 297.

FEATURE(use_ct_file)

Use /etc/mail/trusted-users for a list of trusted users V8.7 and later

V6 sendmail removed the concept of trusted users (Security Features on page 173). V8.7 reintroduced trusted users, but in a form different from that used by V5 sendmail. Now, trusted users are those who can rebuild the aliases database, and who can run sendmail with the -f switch (-f on page 241) without generating an authentication warning (X-Authentication-Warning: on page 1167):

X-Authentication-Warning: host:  user  set sender to other using -f

To prevent this warning, the user should be added to a list of trusted users. Simply use this FEATURE(use_ct_file) and add user to the file /etc/mail/trusted-users (V8.10 and later) or /etc/mail/sendmail.ct (V8.9 and earlier). You declare FEATURE(use_ct_file) like this:

FEATURE(`use_ct_file')

If you want to locate the /etc/mail/trusted-users in a different place or give it a different name, you can do so with this declaration:

define(`confCT_FILE', `/etc/mail/trusted.list')

Note that the file must exist before sendmail is started, or it will complain:

fileclass: cannot open /etc/mail/trusted.list: No such file or directory

If you want the file to optionally exist, you can add a -o (The F Class Command on page 857) to the conf-CT_FILE definition:

define(`confCT_FILE', `-o /etc/mail/trusted_users')

Here, we retain the file’s default name and location, but add the -o to make the file’s presence optional.

You can also add trusted users directly in your mc configuration file like this:

define(`confTRUSTED_USERS',`root bob')

Here, two users are added to the list of trusted users, root and bob.

See also Declare trusted users (ignored V8.1 through V8.6) on page 174 for a discussion of trusted users in general.

FEATURE(use_cw_file)

Use /etc/mail/local-host-names V8.1 and later

FEATURE(use_cw_file) causes the file /etc/mail/local-host-names (V8.10 and later) or /etc/sendmail.cw (V8.9 and earlier) to be read to obtain alternative names for the local host. One use for such a file might be to declare a list of hosts for which the local host is acting as the MX recipient. The use_cw_file is used like this:

FEATURE(`use_cw_file')

This feature causes the following F configuration command (The F Class Command on page 857) to appear in the configuration file:

Fw/etc/sendmail.cw              ← V8.9 and earlier
Fw/etc/mail/local-host-names    ← V8.10 and later

The actual filename can be changed from the default by defining the confCW_FILE macro:

define(`confCW_FILE', `-o /etc/mail/local.list')

Here, we both rename the file and make its presence optional by adding the -o switch (The F Class Command on page 857).

If the local host is known by only a few names, an alternative is to instead include the mc macro in place of the earlier feature:

LOCAL_DOMAIN(`name1 name2')

Here, name1 and name2 are alternative names for the local host.

FEATURE(uucpdomain)

Convert UUCP hosts via a database Deprecated

This has been deprecated as of V8.10. If you currently use this feature, you should convert to FEATURE(domaintable) (FEATURE(domaintable) on page 621) soon.

FEATURE(uucpdomain) was similar to bitdomain (FEATURE(bitdomain) on page 617) but was used to translate addresses of the form:

user@host.UUCP

into a DNS domain format, such as host.domain.com. The database for this would contain, for example, key and data pairs such as these:

host     host.domain.com

This source text file was converted into a database with the makemap(1) program (The makemap Program on page 370).

The way you declare uucpdomain is like this:

FEATURE(`uucpdomain')

This causes rules to be added so that a host with a .UUCP suffix will be looked up in the database uudomain. FEATURE(uucpdomain) also creates the declaration for that database:

Kuudomain hash /etc/mail/uudomain

If you wish to use a different form of database or a different location for the database file, you can do so by adding an argument to the feature declaration:

FEATURE(`uucpdomain', `dbm -o /etc/mail/uudomain')

Here, we tell sendmail that we will be using the NDBM form of database instead of the original NEWDB form (Enable at Compile Time on page 879). We also add a -o to make the presence of the file optional.

If you provide a second argument that is a literal LDAP:

FEATURE(`uucpdomain', `LDAP')

the default becomes the following (we have wrapped the lines to fit the page):

Kauthinfo ldap −1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)
(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))
(sendmailMTAMapName=uucpdomain)(sendmailMTAKey=%0))

See ldap (was ldapx) on page 912 for a description of the ldap database type and its −1, -v, and -k switches.

FEATURE(virtuser_entire_domain)

Match subdomains in the virtual user table V8.10 and later

Ordinarily, domains listed in the $=w class or the $={VirtHost} class are looked up in the virtual user table as is, meaning that only host-for-host or domain-for-domain matches are made. This FEATURE(virtuser_entire_domain) changes that behavior and allows subdomains to also be looked up.

Consider, for example, that the domain wanted.com is listed with the VIRTUSER_DOMAIN mc configuration macro (VIRTUSER_DOMAIN mc macro on page 647) and the following lines are listed in the virtual host table:

info@wanted.com         hans@remote.host
info@sales.wanted.com   hans@remote.host

Here, mail sent to would ordinarily not be looked up. But by declaring this FEATURE(virtuser_entire_domain), all hosts in the subdomain wanted.com would will be looked up, so the address would now find a match.

FEATURE(virtusertable)

Support for virtual domains V8.8 and later

A virtusertable is a database that maps virtual (possibly nonexistent) domains into new addresses. Essentially, it gives you a database hook into the early part of the parse rule set 0. Note that this only reroutes delivery. It does not change mail headers.

By way of example, consider one mapping in a source text file:

info@stuff.for.sale.com       bob
info@stuff.wanted.com         hans@remote.host
info@auction.com              hans@remote.host
@fictional.com                user@another.host

The key portion (on the left) must be either a full address (user, host, and domain name), as in the first two lines, or an address without a host part (just a domain), as in the third line, or an address with the user part missing, as in the last line. This source text file is converted into a database with the makemap(1) program (The makemap Program on page 370).

The first three lines illustrate a full address for the key. The first line will be delivered to a local user (bob), the second and third to a remote user (hans@remote.host). The fourth line shows how all mail to a virtual domain (fictional.com) can be delivered to a single address, regardless of the user part.

Note that sendmail does multiple lookups, so one line can reference another. The following, for example, will work:

info@stuff.for.sale.com       forsale@fictional.com
@fictional.com                user@another.host

Here, mail to will be delivered to user@another.host.

Also note that virtual hosts, just like real hosts, need to belong to class $=w ($=w on page 876) for them to be recognized as local. Also note that beginning with V8.10, virtual hosts can also be listed in your mc file, or in an external file, by using the VIRTUSER_DOMAIN mc configuration macro (VIRTUSER_DOMAIN mc macro on page 647) or the VIRTUSER_DOMAIN_FILE mc configuration macro (VIRTUSER_DOMAIN_FILE mc macro on page 647). Hosts listed with these macros will be looked up in the virtusertable but will not be considered local.

If the value (the righthand side in virtusertable) is error:, the #error delivery agent is called. This allows error messages to be put into the database, as, for example:

info@for.sale.com    error:nouser We no longer sell things here      ← V8.9 and
earlier
info@for.sale.com    error:5.7.0:550 We no longer sell things here   ← V8.10 and
later

The text following the error: is passed to the #error delivery agent. The first token following the error: is passed in the $@ part. Note that prior to V8.10, you had to use words or <sysexits.h > codes here, not DSN values (such as 5.7.0), because the latter were wrongly broken up into five tokens. Beginning with V8.10, you can also use DSN values here, and they will be handled properly. See error on page 720 for a full description of the #error delivery agent and for tables of useful words for the $@ part.

You declare the virtusertable like this in your mc file:

FEATURE(`virtusertable')

This causes the following database declaration to appear in the configuration file:

Kvirtusertable hash /etc/mail/virtusertable

If you wish to use a different form of database (such as dbm) or a different location, FEATURE(virtusertable) accepts an argument:

FEATURE(`virtusertable',`dbm -o /etc/mail/virt_user_table')

If you provide a second argument for FEATURE(virtusertable) that is a literal LDAP:

FEATURE(`virtusertable', `LDAP')

the default becomes the following (we have wrapped the lines to fit the page):

Kauthinfo ldap −1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)
(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))
(sendmailMTAMapName=virtuser)(sendmailMTAKey=%0))

See ldap (was ldapx) on page 912 for a description of the ldap database type and its −1, -v, and -k switches.

In The parse Rule Set 0 on page 696, we deal with the flow of rules through the parse rule set 0. For now, merely note that FEATURE(virtusertable) fits into the flow of rules through the parse rule set 0 like this:

  1. Basic canonicalization (list syntax, delete local host, etc.)

  2. LOCAL_RULE_0 (LOCAL_RULE_0 mc macro on page 596)

  3. FEATURE(ldap_routing) (FEATURE(ldap_routing) on page 922)

  4. FEATURE(virtusertable)

  5. Addresses of the form “user@$=w” passed to local delivery agent

  6. FEATURE(mailertable) (FEATURE(mailertable) on page 629)

  7. UUCP, BITNET_RELAY ($B on page 808), etc.

  8. LOCAL_NET_CONFIG (LOCAL_NET_CONFIG mc macro on page 598)

  9. SMART_HOST (SMART_HOST mc macro on page 597)

  10. SMTP, local, etc. delivery agents

VIRTUSER_DOMAIN mc macro

Beginning with V8.10 sendmail, a new macro was introduced to make it easier to add domains for use with FEATURE(virtusertable). Called VIRTUSER_DOMAIN, it is used like this:

VIRTUSER_DOMAIN(`domain1 domain2 etc')

Each domain that you intend to list should be listed individually, each separated from the others by spaces. Multiple VIRTUSER_DOMAIN lists can be declared in your mc file like this:

VIRTUSER_DOMAIN(`domain1')
VIRTUSER_DOMAIN(`domain2')
VIRTUSER_DOMAIN(`etc')

If you are currently declaring virtual user domains in the $=w class, you are encouraged to convert to this new macro. Use of it will insulate you from change in the future. Note that hosts in $=w for masquerading should not be moved, but should, instead, be copied.

VIRTUSER_DOMAIN_FILE mc macro

Beginning with V8.10 sendmail, a new macro was introduced to make it easier to list domains for use with FEATURE(virtusertable). Called VIRTUSER_DOMAIN_FILE, it is used like this:

VIRTUSER_DOMAIN_FILE(`/etc/mail/virtuserdomains')

This declaration causes domains to be read from the file /etc/mail/virtuserdomain. Because VIRTUSER_DOMAIN_FILE is implemented with an F configuration command (The F Class Command on page 857), you can add whatever F command arguments you desire. For example:

VIRTUSER_DOMAIN_FILE(`-o /etc/mail/virtuserdomains')

Here, the -o switch makes the presence of the /etc/mail/virtuserdomains file optional.

If you are currently storing virtual domains in the $=w class, you are encouraged to convert to this new VIRTUSER_DOMAIN_FILE macro. Use of it will insulate you from change in the future. Note that hosts in $=w for masquerading should instead be copied.



[235] * This is not the same Build script that is documented in The Build Script on page 346. It is a small shell script that works only in the cf/cf directory and can be used only to build configuration files. You can use make in its place, but make will not automatically find the correct version of m4 for you.

[236] This is actually a good idea. It prevents new sendmail distributions from clobbering your .mc files.

[237] * We fudge for simplicity. Actually, OSTYPE can legally be preceded by VERSION (VERSIONID m4 macro on page 593) and m4 comments.

[238] * Although it can and probably should be followed by rule set declarations, as for example, LOCAL_RULESET_0.

[239] * Actually, there are only four; uucp and uucp-old are synonyms for the same agents, as are suucp and uucp-new.

[240] * This feature limits per connecting host, whereas the FEATURE(ratecontrol) (FEATURE(ratecontrol) on page 638) limits all simultaneous connections.

[241] * See cf/README for examples of how to use this feature with maildrop(1) and scanmails(1).

[242] * Note that moving the host from $=w into the mailertable database can adversely affect masquerading and relay control.

[243] * See The Envelope on page 9 for a description of the envelope and how it differs from headers.

[244] * This feature limits the aggregate of all connections, whereas FEATURE(conncontrol) (FEATURE(conncontrol) on page 619) limits connections per MTA.