sendmailSearch this book
Previous: 19.5 PitfallsChapter 19
V8 m4 Configuration
Next: 20. The checkcompat() Cookbook

19.6 Alphabetized m4 Macros

In this section we detail each of the general macros available when configuring with the m4 technique. Here we list them in alphabetical order.

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


The BITNET relay

(V8.1 and above)

The host that will forward BITNET-addressed email. If not defined, the .BITNET pseudo-domain won't work. See Section 31.10.5 for a description of this relay and of the $B macro.


The DECnet relay

(V8.7 and above)

The host that will forward DECnet addressed email. If not defined, the .DECNET pseudo-domain won't work, nor will an address of the form node::user. See Section 31.10.9 for a description of this relay and of the $C macro.

19.6.3 DOL

Insert literal $ in m4 output

(V8.1 and above)

Ordinarily, the $ character is interpreted by m4 inside its define expressions. But for ambitious undertakings, such as designing your own DOMAIN, FEATURE, or HACK files, you may need to include reference to a macro or operator (and hence a $) inside an m4 define expression. The way you do this is 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). When used in one of your .m4 files,

DOWN(badhost, outhost)

it creates a rule by substituting the above arguments for the corresponding $1 and $2 in its original definition:

R $* < @ outhost > $2

The DOL m4 macro in the original definition allowed the insertion of $ characters (such as $*) while protecting those characters from being wrongly interpreted by m4.

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


Masquerade all but these

(V8.6 and above)

Class macro $=E is used by the V8 configuration file to hold a list of usernames that should never be masqueraded (even if masquerade is enabled with the MASQUERADE_AS m4 macro). By default, the user root is always in that class. There are two ways to add usernames to the class E. They can be added individually with the EXPOSED_USER m4 macro:


Here, we cause the name user to be appended to the class E. This is identical to the following use of LOCAL_CONFIG to add to the class directly:

CE user

If you wish to store the list of nonmasqueradable users in an external file, you can cause that file to be read with an F configuration command (see Section 32.1.2, "The F Class Command"):


19.6.5 FAX-RELAY

The FAX relay

(V8.6 and above)

The host that will forward email faxes. If not defined, and if you don't have a fax delivery agent on your local machine, the .FAX pseudo-domain won't work. See Section 31.10.15 for a description of this relay and of the $F macro. Note that if you service faxes locally, you will also need to declare the fax delivery agent with the MAILER() m4 command instead (see Section 19.3.2).

19.6.6 FEATURE(allmasquerade)

Masquerade the sender too

(V8.2 and above)

If a MASQUERADE_AS host is defined, that hostname replaces all sender addresses. The allmasquerade feature 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, say thishost-users, that does not also exist on the masquerade host, this allmasquerade feature will cause the To: header to go out as:

To: thishostusers@hub.domain

Here, the address thishostusers does not exist on the masquerade host, and as a consequence, replies to messages containing this header will bounce.

The form for the allmasquerade feature is:

define(`MASQUERADE_AS', `your.hub.domain')

Note that MASQUERADE_AS (see Section 19.6.42) must also be defined and must contain a fully qualified hostname.

19.6.7 FEATURE(always-add-domain)

Add the local domain even on local mail

(V8.1 and above)

Normally, header recipient addresses and header and envelope sender addresses that select the local or prog delivery agents are left as is. If the always_add_domain feature 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 $j (see Section 31.10.20, $j) are appended.

The form for the always_add_domain feature is


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

19.6.8 FEATURE(bestmx-is-local)

Accept best MX record as local if in $=w

(V8.6 and above)

The class w (see Section 32.5.8) is recommended for defining 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 the bestmx_is_local feature. When enabled, this feature looks up each hostname that it finds in the bestmx internal database map (see Section 33.8.2, bestmx). 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 the bestmx_is_local feature:


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.')

The list of domains is added to the class $=B. Only hosts in those domains 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.

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.    IN MX 0 your.real.domain

Here, mail to would be sent to your site, where the name would be looked up with the bestmx_is_local feature. Your sendmail would find itself listed as MX for 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 for example, and mail to root@sex. would be delivered to you without your knowing the reason.

19.6.9 FEATURE(bitdomain)

Convert BITNET addresses into Internet addresses

(V8.1 and above)

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


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


that can be put into database form for use with the K configuration command. The bitdomain feature 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 m4 macro and the domaintable feature.

The form of the bitdomain feature is


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

Kbitdomain hash -o /etc/bitdomain.db

The bitdomain feature is one of those that can take an argument to specify a different form of or name for the database:

FEATURE(`bitdomain',`dbm -o /etc/bitdomain')

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

Kbitdomain dbm -o /etc/bitdomain

The bitdomain feature 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.

Note that you must also define BITNET_RELAY (see Section 31.10.5) 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.

19.6.10 FEATURE(domaintable)

Accept old as equivalent to new domain

(V8.2 and above)

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


In it the left side of each line has one of possibly many fully qualified hostnames, and the right side has one of your local hostnames. The makemap(1) program (see Section 33.2, "Create Files with makemap") is then used to convert that file into a database.

The domaintable feature causes a rule like this to be included in your configuration file:

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

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

The domaintable feature enables this lookup by including a K configuration command:

Kdomaintable hash -o /etc/domaintable

The form of domaintable feature is


The domaintable feature is one of those that can take an argument to specify a different form of or different name for the database:

FEATURE(`domaintable',`dbm -o /etc/domaintable')

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

Kdomaintable dbm -o /etc/domaintable

The domaintable feature is safe. You can routinely include it in all configuration files. The database lookup is performed only if the database file exists. (See Section, "-o the database file is optional (V8.1 and above)" for a description of the K command's -o switch.)

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 the virtusertable feature instead.

19.6.11 FEATURE(genericstable)

Transform sender addresses

(V8.8 and above)

The User Database (see Section 33.5, "The User Database") 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


In it, each line begins with the user part of an 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

The makemap(1) program (see Section 33.2) is then used to convert this file into a database:

makemap hash file

The genericstable feature causes a rule like this to be included in your configuration file:

R$+ < @ $=G . >      $: < $(generics $1 $: @ $) > $1 < @ $2 . >

Here, in rule set 93, any address whose host part is in the class $=G has the user part looked up in the genericstable database. If it is found, it is rewritten to be the address from the right-hand side of the original file. Note that local and non-local hosts can appear in $=G for use with this feature. Also note that the members of $=w are not automatically placed in $=G.

The genericstable feature enables this lookup by including a K configuration command:

Kgenericstable hash -o /etc/genericstable

The form of genericstable feature's declaration is


The genericstable feature 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/genericstable')

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

Kgenericstable dbm -o /etc/genericstable

See Section for a description of the K command -o switch.

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

19.6.12 FEATURE(limited-masquerade)

Only masquerade $=M hosts

(V8.8 and above)

Ordinarily, addresses can be masqueraded if they are unqualified (lack a domain part) or if they match any hostname in $=w. 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 the limited_masquerade feature.

The limited_masquerade feature causes masquerading to be based on $=M instead of $=w. You use limited_masquerade like this:

define(`MASQUERADE_AS', `our.domain')
Cw our.domain his.domain her.domain
MASQUERADE_DOMAIN(our.domain his.domain)

MASQUERADE_AS needs to be declared first. Then the limited_masquerade feature is declared. Finally, the LOCAL_CONFIG allows two classes to be declared. The first is the normal $=w. The second uses MASQUERADE_DOMAIN to indirectly declare $=M and puts a subset of the $=w hosts in it. Specifically, the second class omits the her.domain.

The limited_masquerade feature causes sendmail to masquerade the hosts in $=M, instead of the normal masquerading of $=w. Note that $=M is also used to list the domains for the masquerade_entire_domain feature.

19.6.13 FEATURE(local-procmail)

Use procmail(1) as local delivery agent

(V8.7 and above)

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 the local_procmail feature:


The local_procmail feature changes the P=, F=, and A= equates for the local delivery agent into

P=/usr/local/bin/procmail                 <- see Section 30.4.9, P=
F=SPfhn                                   <- see Section 30.4.5, F=
A=procmail -Y -a $h -d $u                 <- see Section 30.4.1, A=

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')

If you need to use different F= flags than those shown, you may declare new flags with LOCAL_MAILER_FLAGS (see Section, "m4 modification of F="). If you need to specify different command line arguments, you may do so with LOCAL_MAILER_ARGS (see Section, "m4 A= definitions"). Both must appear before the feature.

19.6.14 FEATURE(mailertable)

Database selects new delivery agents

(V8.1 and above)

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 rule set 0. The new domain names are used for routing but are not reflected in the headers of messages. For example, one mapping in a source text file could be:

The key portion (on the left) must be either a fully qualified host and domain name, such as, or a partial domain specification with a leading dot, such as 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 (see Section 33.2). Beginning with V8.8 sendmail, the host part can also specify a user:     smtp:postmaster@mailhub.our.domain

The mailertable feature causes rules to be included in your configuration file that look up host.domain names (on the left in the source file) in the mailertable database:

R< $+ > $*                   $: < $(mailertable $1 $) > $2   lookup
R< error : $- $+ > $*        $#error $@ $1 $: $2             check - error?

Here, the host.domain is looked up in the mailertable database, and 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

The first token following the error: is passed in the $@ part of the #error delivery agent. Note that you must use words or <sysexits.h> codes here, not DSN values (such as 3.1.0), because the latter would be wrongly broken up into five tokens. See Section 30.5.2, "The error Delivery Agent" 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 rule set 90 for further mailertable lookups. Rule set 90 recursively strips the leftmost part of the host.domain away and looks 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.

The form for the mailertable feature is:


This causes the following database declaration in the configuration file:

Kmailertable hash -o /etc/mailertable.db

If you wish to use a different form of database (such as dbm), the mailertable feature accepts an argument:

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

The mailertable feature was inspired by the IDA version of sendmail.

19.6.15 FEATURE(masquerade-entire-domain)

Masquerade all hosts under a domain

(V8.8 and above)

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


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 any 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 may use the masquerade_entire_domain feature:


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@our.domain
george@host.sub.her.domain -> becomes ->    george@our.domain

Note that you may masquerade only domains that are under your direct jurisdiction and control. Also note that domain masquerading is intended for actual domains. Virtual (fictional) domains are better handled with the virtusertable feature (see Section 19.6.28). But note that the virtusertable feature handles only incoming mail.

19.6.16 FEATURE(masquerade-envelope)

Masquerade the envelope too

(V8.7 and above)

Ordinarily, masquerading (see Section 19.4.4, "Masquerading") affects only the headers of email messages, but sometimes it is also desirable to masquerade the envelope. [4] 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.

[4] See Section 1.7, "The Envelope" for a description of the envelope and how it differs from headers.

The masquerade_envelope feature 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; see Section 32.5.8) to be transformed into our.domain. See MASQUERADE_DOMAIN for a way to also masquerade other domains, and see the masquerade_entire_domain feature 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 may prefer to tailor the envelope on a subdomain-by-subdomain or host-by-host basis.

19.6.17 FEATURE(nocanonify)

Don't canonify with $[ and $]

(V8.1 and above)

Ordinarily, as part of rule set 3, sendmail tries to canonify (add a domain to) any hostname that lacks a domain part. It does this by passing the unadorned hostname to the $[ and $] operators (see Section 28.6.6, "Canonicalize Hostname: $[ and $]"). The nocanonify feature 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 the nocanonify feature is:


You might also want to use:


to turn off the usual resolver options that perform a similar function (see Section 34.8.55, ResolverOptions (I)).

Note that the nocanonify feature disables only one possible use of $[ and $] in the configuration file. If the nouucp feature 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 the nocanonify feature was declared.

Note that sending out any unqualified addresses can pose a risk. Be sure to read Section 16.5, "Qualify All Addresses?" for a discussion of why you might not want to use this feature.

19.6.18 FEATURE(nodns)

Omit DNS support from configuration file


The V8.6 sendmail configuration files usually assumed that you were using DNS to get host information. If you did not have DNS available (for example, if you were on a remote UUCP node), you could declare that fact:


This told sendmail to assume that DNS was not available. It did this by not setting any of the _res.options flag bits. Note that this was really only a suggestion, because other features (such as bestmx_is_local temporarily set those flag bits and used DNS anyway.

Beginning with V8.7 sendmail, you should either use the service-switch file (see Section 34.8.61, ServiceSwitchFile) to control use of DNS or compile a sendmail without DNS support (see Section 18.8.23, NAMED-BIND).

Note that the result of a hostname lookup failure differs depending on whether or not DNS is used. If a hostname is looked up with DNS and not found, the message will be queued, and the name will be looked up again later. If the host is looked up in /etc/hosts and the lookup fails, the message bounces.

19.6.19 FEATURE(nouucp)

Eliminate all UUCP support

(V8.1 and above)

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

You declare nouucp is like this:


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

19.6.20 FEATURE(nullclient)

Relay all mail through a mail host

(V8.6 and above)

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

FEATURE(`nullclient', `server')

See Chapter 16, The File and m4, for a lesson in how to use this feature. Also see the nocanonify feature, which can also be used with nullclient.

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


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

19.6.21 FEATURE(redirect)

Add support for address.REDIRECT

(V8.1 and above)

The redirect feature 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:


The redirect feature causes mail addressed to george, for example, to be bounced with a message like this:

551 User not local; please try <>

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

The form of the redirect feature is


This feature adds the pseudo-domain .REDIRECT to class $=P, which prevents that suffix from being looked up with DNS. It then adds rules to rule set 0 that handle this suffix only if the {opMode} macro (see Section 31.10.28, ${opMode}) has any value other than i (for initialize aliases as set by the -bi command line switch, see Section 36.1.3, "newaliases"). The actual bounce is caused by calling the error delivery agent with a RHS like 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).

To illustrate why the message is bounced rather than forwarded, consider a fictional MTA that is clever about getting this message:

551 User not local; please try <>

Instead of bouncing the outgoing message, the fictional MTA tries to be clever and to deliver to If also responds with a REDIRECT message, the MTA tries the next host in line. This is a bad idea for two reasons: First, elaborate loop detection would need to be designed to catch infinite REDIRECT loops, and second, a down host anywhere in the sequence would necessitate that the series of connections be made over and over again until they all succeeded.

19.6.22 FEATURE(smrsh)

Use smrsh (sendmail restricted shell)

(V8.7 and above)

Although sendmail tries to be very safe about how it runs programs from the aliases(5) and ~/.forward files (see Section 24.2.3, "Delivery via Programs"), it still may be vulnerable to some internal attacks. To limit the selection of programs that sendmail is allowed to run, V8 sendmail now includes source and documentation for the smrsh (sendmail restricted shell) program. See Section 22.8.2, "The smrsh Program" for a full description of the smrsh program.

After you have compiled, installed, and configured smrsh, you can include support for it in your configuration file with the smrsh feature:


Note that the smrsh feature must precede the local delivery agent declaration. If these lines are reversed, the following error will print when you run m4:

*** FEATURE(smrsh) must occur before MAILER(local)

The default location for the smrsh program is /usr/local/etc/smrsh. If you installed smrsh in another location, you will need to add an argument to the smrsh feature:

FEATURE(`smrsh', `/usr/bin/smrsh\')

Use of smrsh is recommended by CERT, so you are encouraged to use this feature as often as possible.

19.6.23 FEATURE(notsticky)

Don't differ user from

(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., is delivered locally. From V8.1 to V8.6 sendmail, if the address has a host part, lookups in the User Database (see Section 33.5) and the additional processing of rule set 5 (see Section 29.7, "Rule Set 5") are skipped. Under V8.6, addresses with just the user part are always processed by the User Database and rule set 5.

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

Beginning with V8.7, the default is now as if notsticky were used, and the stickyhost feature is used to restore the previous default.

19.6.24 FEATURE(stickyhost)

Differ user from

(V8.7 and above)

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 are both looked up with the User Database (see Section 33.5) and processed by rule set 5 (see Section 29.7). This processing can result in those addresses being forwarded to other machines.

With the stickyhost feature, you may change this behavior:


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

user               <- not sticky    <- 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 rule set 5.

One use for this feature is to create a domainwide name space. 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 notsticky feature of V8.6.

19.6.25 FEATURE(use-ct-file)

Use /etc/sendmail.ct for a list of trusted users

(V8.7 and above)

V6 sendmail removed the concept of trusted users (see Section 22.8, "Security Features"). V8.7 reintroduced trusted users, but in a different form from that used by V5 sendmail. Now, trusted users are those who may run sendmail with the -f switch (see Section 36.7.21, -f and -r) without generating an authentication warning (see Section 35.10.35, X-Authentication-Warning:):

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

To prevent this warning, the user should be added to the class $=t (see Section 32.5.7, $=t). There are three ways to do this. You may use the T configuration command:


Or you may use the class command:


Or you may use the use_ct_file and add user to the /etc/sendmail.ct file. To use this latter approach, declare the following in your mc file:


If you want to locate the /etc/sendmail.ct in a different place or give it a different name, you may 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 may add a -o (see Section 32.1.2) to the conf-CT_FILE definition:

define(`confCT_FILE', `-o /etc/sendmail.ct')

Here, we don't rename the file: we make the default file's presence optional.

19.6.26 FEATURE(use-cw-file)

Use /etc/ for local hostnames

(V8.1 and above)

The use_cw_file feature causes the file /etc/ 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:


This feature causes the following F configuration command (see Section 32.1.2) to appear in the configuration file:


The actual filename can be changed from /etc/ (the default) by defining the confCW_FILE macro:

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

Here, we both rename the file and make its presence optional by adding the -o switch (see Section 32.1.2).

If the local host is known by only a few names, an alternative is to instead include the following C configuration command (see Section 32.1.1, "The C Class Command") in place of the above feature:

Cwname1 name2

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

19.6.27 FEATURE(uucpdomain)

Convert UUCP hosts via a database

(V8.1 and above)

The uucpdomain feature is similar to bitdomain but is used to translate addresses of the form


into the ! path form or routing used by UUCP. The database for this would contain, for example, key and data pairs like this:

host     a!b!c!host

This source text file is converted into a database with the makemap(1) program (see Section 33.2). But note that no software is supplied to transform the UIUC pathalias(1) program's output into a form that is suitable for this database.

The way you declare uucpdomain is like this:


This causes a rule like this to be added to rule set 3:

R$* < @ $+ .UUCP > $*           $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3

Here, the host in the pseudo-domain .UUCP is looked up in the database uudomain. The uucpdomain feature also creates the declaration for that database:

Kuudomain hash -o /etc/uudomain

If you wish to use a different form of database or a different location for the database file, you may 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 (see Section 33.1, "Enable at Compile Time"). We also relocated the file into the /etc/mail directory.

19.6.28 FEATURE(virtusertable)

Support for virtual domains

(V8.8 and above)

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 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:       bob      

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 with the user part missing, as in the last line. This source text file is converted into a database with the makemap(1) program (see Section 33.2).

The first two lines illustrate a full address for the key. The first line will be delivered to a local user (bob) the second to a remote user ( The third line file shows how all mail to a virtual domain ( can be delivered to a single address, no matter what the user part is.

Note that sendmail does a single lookup, so one line may not reference another. The following won't work:      

Here, mail to will be delivered to, not to

Also note that virtual domains in the key (such as must be added to class w in order for them to be recognized as local.

You declare the virtusertable like this in your mc file:


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

Kvirtusertable hash -o /etc/virtusertable

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

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

If the value (the right-hand side in virtusertable) is error:, the #error delivery agent is called. This allows error messages to be put into the database, as, for example,    error:nouser We no longer sell things here

The text following the error: is passed to the #error delivery agent like this:

Rerror : $- $+       $#error $@ $1 $: $2

Thus the first token following the error: is passed in the $@ part. Note that you must use words here, not DSN values (such as 3.1.0), because the latter would be wrongly broken up into five tokens. See Section 30.5.2 for a full description of the #error delivery agent and for tables of useful words for the $@ part.

19.6.29 HACK

Temporary customizations

(V8.1 and above)

Some things just can't be called features. To make this clear, they go in the _CF_DIR_/hack directory (see Section 19.2.1, "Maintain local files with _CF_DIR_") and are referenced using the HACK macro. They tend to be site-dependent.


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 (see Section 19.3.4) and reference it there.


Add general information and rules

(V8.1 and above)

The LOCAL_CONFIG macro allows custom configuration lines to be inserted by using the mc file. The inserted lines are carried literally into the output and appear in the resulting configuration file just before the rules.

Khostmap hash /etc/hostmap.db

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

New rule sets can be inserted with LOCAL_CONFIG. For V8.7 and above we recommend using symbolic names to avoid collision with rule set numbers used by sendmail:

<- custom rules here

See the discussion of diversions (see Section 19.1.4, "m4 diversions") to cause LOCAL_CONFIG lines to output in a predetermined order.


Relay for unqualified user (deprecated)

(V8.1 and above)

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 may define that other machine with the LOCAL_RELAY m4 macro.

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

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

19.6.32 LOCAL-RULE-0

Add rules to rule set 0

(V8.6 and above)

In rule set 0, after the local delivery agent has been selected and before the uucp, smtp, and the like have been selected, you can insert custom delivery agents of your own. To do this, use the LOCAL_RULE_0 macro:

# 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.

Note that LOCAL_RULE_0 fits into flow of rules through rule set 0 like this:

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

  2. 2. LOCAL_RULE_0

  3. 3. UUCP, BITNET_RELAY (see Section 31.10.5), etc.

  4. 4. LOCAL_NET_CONFIG (see Section 19.6.37)

  5. 5. SMART_HOST (see Section 19.6.47)

  6. 6. SMTP, local, etc. delivery agents

19.6.33 LOCAL-RULE-1

Add rules to rule set 1

(V8.6 and above)


19.6.34 LOCAL-RULE-2

Add rules to rule set 2

(V8.6 and above)

Rule sets 1 and 2 are normally empty and not included in the configuration file created from your mc file. Rule set 1 processes all sender addresses (see Section 29.9, "Rule Set 1"), and rule set 2 processes all recipient addresses (see Section 29.8, "Rule Set 2"). These m4 macros are used just like LOCAL_RULE_0, above but they introduce rules that would otherwise be omitted, rather than adding rules to an existing rule set.

19.6.35 LOCAL-RULE-3

Add rules to rule set 3

(V8.6 and above)

All addresses are first rewritten by rule set 3 (see Section 29.4, "Rule Set 3"). For complex configuration needs, you can define special rules and cause them to be added to rule set 3. New rules are added to the end of rule set 3 by way of rule set 6. That is, each final decision in rule set 3 (denoted by a $@ in the RHS) calls rule set 96 (with $>96) before returning.

The m4 macro LOCAL_RULE_3 is used to introduce new rules that can be used in canonicalizing the hostnames. Note that any modifications made here are reflected in the header.

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


This causes the following address transformations:

decvax!user    becomes ->
research!user  becomes ->

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

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

The declaration and definition of local database maps with the K configuration command (see Section 33.3, "The K Configuration Command") should appear in the LOCAL_CONFIG section.


Group local rules with others

(V8.8 and above)

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

The LOCAL_RULESETS m4 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:

your new rule sets and rules here


Add rules for SMART-HOST

(V8.6 and above)

One possible setup for mail is to allow hosts on the local network to deliver directly to each other but for all other mail to be sent to a "smart host" that forwards it offsite. Commonly, such arrangements are used by sites with inhouse 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', `uucp-new:uunet')
R$* < @ $* .$m. > $*     $#smtp $@ $2.$m $: $1 < @ $2.$m > $3

Here, SMART_HOST is first defined as uucp-new:uunet (send to the host uunet with the uucp-new 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 to be handled by the SMART_HOST rules.

SMART_HOST can be a network-connected gateway too. Just use smtp in place of uucp-new in the SMART_HOST definition, and the name of the gateway.

Note that LOCAL_NET_CONFIG fits into the flow of rules through rule set 0 like this:

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

  2. 2. LOCAL_RULE_0 (see Section 19.6.32)

  3. 3. FEATURE(mailertable) (see Section 19.6.14)

  4. 4. UUCP, BITNET_RELAY (see Section 31.10.5), etc.

  5. 5. LOCAL_NET_CONFIG (see Section 19.6.37)

  6. 6. SMART_HOST (see Section 19.6.47)

  7. 7. SMTP, local, etc. delivery agents

19.6.38 LOCAL-USER

Users that must be delivered locally

(V8.1 and above)

Some unqualified (without an @host part) usernames 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 m4 macro is used to add additional usernames to the list of local users. Note that root is always a member of that list.


This causes the name operator to be appended to the list of local users. That list is stored in the class $=L. The disposition of local usernames that include the name of the local host is determined by the stickyhost feature.


Relay for local looking usernames

(V8.7 and above)

The host that handles usernames that appear to be local even though they are not. See Section 31.10.23 for a discussion of this relay.


Define custom delivery agents

(V8.8 and above)

Prior to V8.8 sendmail you had to use a divert(7) statement to force your new delivery agent definitions to be grouped with all the other delivery agent definitions. Beginning with V8.8, this bit of "black magic" has been removed.

To force your new delivery agent definitions to be grouped with the others delivery agent definitions, use the MAILER_DEFINITIONS m4 command:

your new delivery agent definitions here

See Section 30.3.1, "Tuning Without an Appropriate Keyword" for an example of this m4 command.

19.6.41 MAIL-HUB

All local delivery on a local server

(V8.1 and above)

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 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 class L are sent to the 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

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

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

If both LOCAL_RELAY and MAIL_HUB are defined as above, mail addressed to you is sent to for delivery, and mail addressed to is forwarded to

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

Note that LOCAL_RELAY and MAIL_HUB act identically (except that MAIL_HUB takes precedence) unless the stickyhost feature is used. Also note that the nullclient feature can be used if you want all mail to be forwarded to a central machine.


Masquerade as the server

(V8.1 and above)

At sites with one central mail server (see MAIL_HUB, it can be advantageous for mail from the clients 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 m4 macro:


This causes outgoing mail to be labeled as coming from the server (rather than from the value in $j see Section 31.10.20). The new label is in all but the Received: (see Section 35.10.25, Received:) and Message-ID: (see Section 35.10.19, Message-ID:) 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 m4 macro. Note that root is always exposed.

If you wish to have recipient addresses also masqueraded, cautiously use the allmasquerade feature.


Masquerade other domains

(V8.6 and above)

Ordinarily, MASQUERADE_AS enables only hosts in the local domain, to be transformed into the masquerading host. If you wish to masquerade a domain other than your local one, you can use the MASQUERADE_DOMAIN macro:


Essentially, all that MASQUERADE_DOMAIN does is to assign its argument to the class $=M, so you can list multiple domains in a single MASQUERADE_DOMAIN statement:

MASQUERADE_DOMAIN(`domain1 domain2 domain3')
CM domain1 domain2 domain3                                 <- the same

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.


Masquerade other domains

(V8.6 and above)

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


Essentially, all that MASQUERADE_DOMAIN_FILE does is to assign its argument to the class $=M via an F configuration command:

MASQUERADE_DOMAIN_FILE(`-o /etc/mail/domains')   
FM -o /etc/mail/domains                               <- the same

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

19.6.45 SITE

Declare sites for SITECONFIG (obsolete)

(V8.1 and above)

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

SITE(sonya grimble)

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


Local UUCP connections (obsolete)

(V8.1 and above)

The SITECONFIG m4 macro (now obsolete but retained for backward compatibility) 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:


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


Here, the file _CF_DIR_/cf/siteconfig/ 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 class macro $=U. The 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 m4 macro is the one used by hosts other than the one with the direct UUCP connections. It is just like the above one but with the full canonical name of the host:


This also reads the file 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 macro. The class $=W is set aside to hold lists of hosts that appear locally connected. This class is also used with the SITE 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 the nouucp feature.

19.6.47 SMART-HOST

The ultimate relay

(V8.1 and above)

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 with UUCP. To ensure delivery of all mail, such sites need to forward all nonlocal mail over the UUCP link to a smart (or well-connected) host.

You can enable this behavior by defining SMART_HOST:

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. Note that the value in SMART_HOST is assigned to $S (see Section 31.10.34, $S) for later use in rules.

19.6.48 UUCP-RELAY

The UUCP relay

(V8.1 and above)

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

If your machine or site does not support UUCP, consider disabling all UUCP with the nouucp feature.

If your machine has directly connected UUCP hosts, you might wish to use one of or more of the UUCP techniques. But before doing so, be sure to declare the uucp delivery agent (see Section 19.3.2).

19.6.49 UUCPSMTP

Individual UUCP to network translations

(V8.1 and above)

If your site has hosts that used to be UUCP sites but are now on the network, you may intercept and rewrite the old address 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 m4 macro provides the means to specify a UUCP to network translation for specific hosts. The above example would be declared like this:


The UUCPSMTP m4 macro should be used only under LOCAL_RULE_3.


Version of the mc file

(V8.1 and above)

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 of the files that is supplied with sendmail already has such an identifier. You should include a similar identifier in each of your .mc files. .ds dollar $


Here, the VERSIONID macro is being used to insert an RCS-style revision number. The \*[dollar]Revision\*[dollar] becomes an actual version number when the file is checked in with ci(1). Arbitrary text may appear between the single quotes. You may use RCS, SCCS, or any other kind of revision identification system. The text may not contain a newline because the text appears in the .cf file as a comment:

#####  \*[dollar]Revision: 1.5\*[dollar] #####

Use of VERSIONID and revision control in general is recommended.

Previous: 19.5 PitfallssendmailNext: 20. The checkcompat() Cookbook
19.5 PitfallsBook Index20. The checkcompat() Cookbook