sendmail administration

Managing spam

Unsolicited email, or ``spam'', is an increasing problem on the Internet. The primary anti-spam features available in sendmail are listed below:


Relaying (transmission of messages from a site outside your host to another site except yours) is denied by default. You can allow specified domains to relay mail through your server by adding the domain name or IP address via the access database, /usr/lib/mail/access. This file consists of entries listed on separate lines. For example:

If source routing is used in the recipient address (for example, RCPT TO: <>), sendmail checks for relaying if is an allowed relay host in the access database.

Sender checks

sendmail will refuse mail if the "Mail From:" parameter has an unresolvable domain (i.e., one that DNS, your local name service, or special case rules in ruleset 3 cannot locate).

sendmail will also refuse mail if the "Mail From:" parameter is not fully qualified (i.e., contains a domain as well as a user).

Access database

The ``access'' database enables you to accept or reject mail from selected domains. For example, you may choose to reject all mail originating from known spammers.

Because /usr/lib/mail/access is a database, you must use makemap to create the database map after creating the text file, as described below. For example:

makemap hash /usr/lib/mail/access < /usr/lib/mail/access

The table itself uses e-mail addresses, domain names, and network numbers as keys. For example,         REJECT        REJECT
   192.168.212             REJECT
would refuse mail from, any user from (or any host within the domain), and any host on the 192.168.212.* network.

The value part of the map can contain:

Accept mail even if other rules in the running ruleset would reject it (for example, if the domain name is unresolvable).

Accept mail addressed to the indicated domain or received from the indicated domain for relaying through your SMTP server. RELAY also serves as an implicit OK for the other checks.

Reject the sender or recipient with a general purpose message.

Discard the message completely using the $#discard mailer. If it is used in the check_compat ruleset, it affects only the designated recipient, not the whole message as it does in all other cases. This should only be used if really necessary.

### [any text]
where ### is an RFC 821 compliant error code and [any text] is a message to return for the command. The string should be quoted, otherwise sendmail may remove spaces.

ERROR:### [any text]
where ### is an RFC 821 compliant error code and [any text] is a message to return for the command. Useful to mark error messages as such.

ERROR:D.S.N:### [any text]
where D.S.N is an RFC 1893 compliant error code, ### is an RFC 821 compliant error code, and [any text] is a message to return for the command.

For example:        ERROR:"550 We don't accept mail from spammers"   OK            RELAY
   128.32                  RELAY
   1:2:3:4:5:6:7           RELAY
   []             OK
   [1:2:3:4:5:6:7:8]       OK
would accept mail from, but would reject mail from all other hosts at with the indicated message. It would allow relaying mail from and to any hosts in the domain, and allow relaying from the 128.32.*.* network and the IPv6 1:2:3:4:5:6:7:* network. The latter two entries are for checks against ${client_name} if the IP address doesn't resolve to a hostname (or is considered as "may be forged").

WARNING: If you change the RFC 821 compliant error code from the default value of 550, then you should probably also change the RFC 1893 compliant error code to match it. For example, if you use:        450 mailbox full
the error returned would be 450 4.0.0 mailbox full, which is wrong. Use ``450 4.2.2 mailbox full'' or ``ERROR:4.2.2:450 mailbox full'' instead.

Note that UUCP users may need to add hostname.UUCP to the access database.

You can also use the access database to block sender addresses based on the username portion of the address. For example:

   FREE.STEALTH.MAILER@    ERROR:550 Spam not accepted

You must include the @ after the username to signify that this database entry is for checking only the username portion of the sender address.

Finer control by using tags for the LHS of the access map

If the options listed so far are not sufficient for your purposes, you can tag entries in the access map according to their type. Three tags are available:

Connect: [connection information] (${client_addr}, ${client_name})
From: [envelope sender]
To: [envelope recipient]

If the required item is looked up in a map, it will be tried first with the corresponding tag in front, then without any tag. For example:

   From:spammer@some.dom   REJECT
   To:friend.domain        RELAY
   Connect:friend.domain   OK
   Connect:from.domain     RELAY
   From:good@another.dom   OK
   From:another.dom        REJECT

This would deny mails from spammer@some.dom but you could still send mail to that address. Your system will allow relaying to friend.domain, but not from it (unless enabled by other means). Connections from that domain will be allowed even if it ends up in one of the DNS-based rejection lists. Relaying is enabled from from.domain but not to it. Because relaying is based on the connection information for outgoing relaying, the "Connect:" tag must be used; for incoming relaying, which is based on the recipient address, "To:" must be used. The last two entries allow mails from good@another.dom but reject mail from all other addresses with another.dom as domain part.

Header checks

You can also reject mail on the basis of the contents of mail headers. This is done by adding a ruleset call to the 'H' header definition command in For example, this can be used to check the validity of a "Message-ID:" header:

   HMessage-Id: $>CheckMessageId

SCheckMessageId R< $+ @ $+ > $@ OK R$* $#error $: 553 Header Error

The alternative format:

   HSubject: $>+CheckSubject

(that is, $>+ instead of $>) gives the full "Subject:" header, including comments, to the ruleset. Comments in parentheses are stripped by default.

A default ruleset for headers that do not have a specific ruleset defined for them can be given by:

   H*: $>CheckHdr

NOTE: All rules act on tokens. That may cause problems with simple header checks due to the tokenization. It might be simpler to use a regex map and apply it to $&{currHeader}.

After all of the headers are read, the check_eoh ruleset will be called for any final header-related checks. The ruleset is called with the number of headers and the size of all of the headers in bytes separated by $|. One example usage is to reject messages that do not have a "Message-Id:" header. However, the "Message-Id:" header is not a required header and is not a guaranteed spam indicator. This ruleset is an example and should probably not be used in production.

           Kstorage macro

LOCAL_RULESETS HMessage-Id: $>CheckMessageId

SCheckMessageId # Record the presence of the header R$* $: $(storage {MessageIdCheck} $@ OK $) $1 R< $+ @ $+ > $@ OK R$* $#error $: 553 Header Error

Scheck_eoh # Check the macro R$* $: < $&{MessageIdCheck} > # Clear the macro for the next message R$* $: $(storage {MessageIdCheck} $) $1 # Has a Message-Id: header R< $+ > $@ OK # Allow missing Message-Id: from local mail R$* $: < $&{client_name} > R< > $@ OK R< $=w > $@ OK # Otherwise, reject the mail R$* $#error $: 553 Header Error

Next topic: Enabling user forwarding (.forward files)
Previous topic: Stopping and restarting sendmail

© 2003 Caldera International, Inc. All rights reserved.
SCO OpenServer Release 5.0.7 -- 11 February 2003