Ideas about check_* in sendmail 8.9

Last Update 2000-06-24

sendmail 8.10 is available so some of the proposals below have actually been implemented.


sendmail 8.9 introduced standard FEATUREs for the new rulesets to check who can use your machine to send/relay e-mail and to avoid UBE from well known sites.

However, some of you are not satisfied with the available "grain" of control. sendmail 8.9 use a single access map to control nearly all anti-UBE features. This causes several problems, which are explained below.


There are at least two ways to deal with relaying in 8.9: class R and the access map. An member of class R or an entry in access with RHS "RELAY" allows relaying in both directions (in and out). Moreover, the access map is used for many purposes: overriding rejections by other rules in the same check_* ruleset (RBL, unresolvable domains, etc), rejection and discarding of mail. Those who followed the development of 8.9.0 Beta noticed a change of the possible RHSs: RELAY has been introduced in addition to OK to allow for finer control (OK: accept, RELAY: accept and relay).

So what do you need/want? Frank Cusack already wrote a patch which introduced RELAYTO and RELAYFROM (with the obvious meaning) for finer control. With this patch, a hierarchy of values is introduced:

RELAY                 implies


Rejections have as RHS:
XYZ some error text

Note: the feature blacklist_recipients will not only prevent local recipients from receiving mail:

badlocaluser		550 Mailbox disabled for this username	550 That host does not accept mail	550 Mailbox disabled for this recipient
but it will also keep you from sending mails to all addresses/domains that have an error message or REJECT as RHS. For example, if you blocked mail from these addresses:		REJECT	REJECT
then mail can't be sent to or anyone at

Even worse, if you block mail to a local user with the (unusual?) name com, then you can't communicate via e-mail with any domain that ends in .com. This problem occurs since usernames for feature blacklist_recipients are not tagged with a @ is it is done for check_mail.


The access map can have domain names, e-mail addresses, local parts of e-mail addresses, and IP addresses (complete or subnets), as LHS. The lookup of data in the check_* rulesets is usually done against the most specific entry first. So it is possible to override rejections of full domains with acceptance of e-mail addresses. For example, it seems to be possible to reject all mail from SOME.DOMAIN but accept mail from FRIEND@SOME.DOMAIN by using:

However, the access map is also used in check_relay ruleset. So if e-mail with an address like user@SOME.DOMAIN comes from a site with the hostname SOME.DOMAIN (or HOST.SOME.DOMAIN), it will be rejected by check_relay .


What do you think? Is a hierarchy of "permissions" sufficient? Or should there be different values for different purposes? (my HACKs used different maps for different purposes, but this has "historical" reasons :-).

Where is the access map used?

  1. check_relay
    1. rejection: REJECT, DISCARD, XYZ some error text,
    2. or override the RBL (there's a bug in 8.9.{0,1} (patch for cf/m4/proto.m4)): OK, RELAY.

    check_relay may reject mail from a host while check_mail would allow it: OK for user, REJECT for host so we need something like:

    (and we have a problem with Custom-Error-Messages...)
  2. check_mail
    1. rejection: REJECT, XYZ some error text
    2. override the various checks (unqual. address, unresolvable domain): OK, RELAY,
  3. check_rcpt
    1. blacklist_recipients reject mail to an address (REJECT, error message)
    2. relay to an e-mail address: RELAY
    3. relay from a host address (FQHN, IP number): RELAY
RELAY_LOCAL_FROM currently only works for local domains (class w), no check in the access map is done. This can be added by Local_check_rcpt for POP authentification.

Possible Solutions?

Different RHS

We could use different RHS for these cases, e.g.,
RBL_OK		override RBL

Do you think this is necessary/useful?

The idea is to have "multiple" RHSs, and check for the occurence of the required keyword, e.g.,

R<$* OKUNQUAL $*>	$@ OK
However, I haven't started yet to write rules, so I'm not sure whether it will really work. BTW: there is a small gotcha: the keywords must be "unique", i.e., they should not appear in a user written error message. This could be achieved by using delimiters, e.g.,
134.245		:OKRBL:RelayFrom:
dialup.some.domain	:RejectRelay::;550 no direct access for dialups.
which at least minimizes the problem of getting a wrong match.

However, there is still a problem with this: if we do a lookup of an entry, we may get something in return we aren't interested in. So the rules become more complicated since they have to filter relevant results, and for those values that are not relevant in the particular context, lookups of other data must continue. Example:

user@domain		:ToReject:
@domain			:FromOK:
If check_mail looks up the sender address user@domain it will get a match on the first entry which, however, isn't relevant here, because it is intended for check_rcpt (blacklist_recipients). So the rules have to recognize this and continue lookups to find the second entry.

Another problem is the identification of error messages. Since we can have a list of possible values as RHS and only some of them are relevant in the particular rulesets, we need to make sure that the others are not interpreted as user-defined error messages as it is currently the default.

Tag the LHS

Another idea is to tag the LHS (which would be optional, the default is the current behavior to be compatible):
Connect:1.2.3			REJECT
Connect:			OK
Connect:relay.domain	RELAY
To:another.domain		RELAY
From:1.2.4				OK
From:some.domain		REJECT
From:friend@some.domain	OK
To:olduser@				REJECT
This will give high flexibility. Even though the table might be hard to read, it should be easy to generate it from simpler descriptions (different files). This should only be optional, the default behavior (and map content) should be the one which is currently supported (except for maybe some slight enhancements). Since we tag the LHS, we can have `multiple' entries, because they are distinguished by the tags. A drawback might be that it is possible to create `inconsistent' maps, that is, allow relaying by one entry, but reject mail by another. However, just as Unix isn't supposed to stop you from doing stupid things (because it would stop you doing clever things), why should sendmail? Another drawback might be a larger map, as can be seen from the example.

The tags used are

for connection information, i.e., ${client_name} and ${client_addr}.
From: for envelope sender
To: for envelope recipient
The entries above will allow connections from the IP number and reject everything else in the net 1.2.3. It allows relaying from relay.domain and to another.domain.

Order of calls

As explained the new rulesets for SMTP connections are called in the order: check_relay (host name and host address when a client connects), check_mail for the MAIL command, and check_rcpt for the RCPT command. Hence it is per default not possible to override rejections in check_relay by the sender address, or rejections in check_mail for individual recipients. There are some HACKs available which provide the opportunity to change the order by modifying some rulesets. This allows you to:
  1. accept mail from specific (envelope) senders, even though the server rejects connections from some clients,
  2. accept mail for specific recipients, e.g., postmaster, even though the mail would be rejected by other means.
The HACKs for 8.8 have also appropriate options: _CHECK_MAIL_IN_RCPT_ and _CHECK_RELAY_IN_RCPT_. This enables the exemption from senders or recipients from rejecting mail from/for them.

Should such a feature also be included in a future sendmail release?

[(links)] [Hints] [Avoiding UBE] [cf/README] [New]
Copyright © Claus Aßmann Please send comments to: <ca at>
Disclaimer: the information provided may be inaccurate or outdated or incomplete. Please contact me if you find an error.