The access database was introduced in V8.9 sendmail, and improved upon in V8.10. It provides a single, central database with rules to accept, reject, and discard messages based on the sender name, address, or IP number. It is enabled with the access_db configuration feature.
 Another feature, blacklist_recipients, allows recipients to also be rejected. Yet another feature, delay_checks, allows even finer tuning based on the desire of individual recipients.
For example, consider an access database with the following contents:
From:firstname.lastname@example.org OK From:spam.com REJECT
Here, mail from postmaster at the site spam.com is accepted, while mail from any other sender at that site is rejected.
Note that this example uses V8.10 syntax. Next we will describe the access database using the old V8.9 syntax, then describe the V8.10 and V8.12 updates.
To enable use of this access database, declare it in your mc configuration file like this:
This enables use of the access database, and enables the default database type and path as:
hash /etc/mail/access V8.11 and earlier hash -T<TMPF> /etc/mail/access V8.12 and above
Note that with V8.12 and above a -T<TMPF> has been added to specify that temporary errors should return a 4xy SMTP code.
If you wish to use a different database type or pathname, you can do so by providing an appropriate argument to the access_db feature:
FEATURE(`access_db', `hash -o /etc/mail/access') V8.11 and earlier FEATURE(`access_db', `hash -o -T<TMPF> /etc/mail/access') V8.12 and above
Here, we add the -o switch (-o) to the definition to make the existence of the /etc/mail/access database file optional.
Beginning with V8.12, this feature takes two more arguments:
FEATURE(`access_db', `db specification', `skip', `lookupdotdomain')
The skip (the third argument), if present, enables SKIP as a possible return value for the access database (Section 220.127.116.11).
The lookupdotdomain (the fourth argument), if present, enables the same behavior as if you independently declared the lookupdotdomain feature (FEATURE(lookupdotdomain)).
To create the access database, you first create a text file that contains lines of hosts, addresses, and IP numbers paired with keywords and values. After that you run makemap to create the actual database from the text file. If the text file is named /etc/mail/access, you would build the database like this:
# cd /etc/mail # makemap hash access < access
The text file itself looks like this:
key value whitespace: one or more tabs or spaces
The text file is composed of two columns of information. The lefthand column is the key which is composed of a prefix and an address expression. The prefix depends on the rule set doing the lookup. For some it is Connect: or From:, while for others it is TLS_Srv: or TLS_Clt:. These are described in the sections of this book dealing with the appropriate rule set.
The address expression can be any of the following depending on what the rule set is trying to do:
host.your.domain a hostname your.domain a domain name user@ a username email@example.com a user address 18.104.22.168 an IPv4 host address 123.45 an IPv4 network (leftmost numbers) IPv6:2002:c0a8:51d2::23f4 an IPv6 host address IPv6:2002:c0a8:02c7 an IPv6 network (leftmost numbers)
Note that for usernames the @ is mandatory. More address expressions can be used than we show here. These are the most common. Others are described under the rule sets that use them.
The righthand column contains the value, which can be keywords or values that determine what should be done with the item described on the left. They are shown in Table 7-3, and described in the sections indicated.
Accept the lefthand side entry
Allow the lefthand side to relay mail through this machine
Reject the lefthand side (bounce the message)
Reject the lefthand side (bounce the message)
Stop looking for the key, and don't look for any future parts of the key
Reject with custom SMTP code and message
Reject with optional custom SMTP code and message
Reject with a more precise DSN code
Also look up the CERT subject
Verify the certificate
Verify the certificate and require minimum number of encryption bits
The minimum number of encryption bits
The OK righthand value for the access database tells sendmail to accept the user, host, domain, or address on the lefthand side. That is, even if other rules in the rule set that did the lookup reject it (because the domain cannot be looked up with DNS, for example), this return value will still cause it to be accepted by that rule set. Note, however, that other rule sets can subsequently reject it.
The RELAY access database righthand value tells sendmail to allow the user (if the relay_mail_from feature is defined), host, domain, or address listed on the lefthand side to relay mail through this machine. It also allows mail to be relayed by anyone when routing is to the host, domain, or IP numbers listed. Note that RELAY also includes the behavior of OK.
The REJECT access database righthand value tells sendmail to reject the user, host, domain, or address listed on the lefthand side. The rejection will use the default message defined by the confREJECT_MSG mc macro (Section 7.5.4).
The DISCARD access database righthand value tells sendmail to accept any sender that is listed on the lefthand side (either as a user, host, or IP number), but to silently discard the message using the discard delivery agent (discard). The DISCARD keyword can also be used for recipients if the blacklist_recipients feature (Section 7.5.5) is declared. When a recipient is discarded and when there are other recipients in the envelope, all recipients are discarded. The one exception is if DISCARD is returned to the check_compat rule set, established by the compat_check mc feature (Section 7.5.7), then only the one recipient is discarded.
This keyword provides a way to list hosts, domains, or addresses that can give a default behavior. Such defaults are defined by your selection of features to enable. Sometimes, for example, you might desire to have the lookup of a host, domain, or address return (if found) but have no further checks performed on it. One way to do that is by using this special SKIP keyword as the return value for the lookup:
If the lookup was done to see if relaying is OK for the domain bob.domain, this SKIP instructs sendmail to act as though the lookup did not find bob.com. Thus, if the default is to deny relaying, relaying for bob.com will be denied. If the default is to allow relaying, relaying for bob.com will be allowed.
The main use for SKIP is with the lookupdotdomain feature (FEATURE(lookupdotdomain)). With that feature defined, you could set up the access database like this:
From:server.bob.com SKIP From:.bob.com RELAY
Here, mail from the machine server.bob.com will be handled by the default rules. All other hosts in the bob.com domain will be allowed to relay.
The SMTP protocol, as documented in RFC2821, defines a set of three-digit codes that have special meaning to the sending site. When sendmail rejects the envelope sender, it does so by printing a 550 code in reply to the MAIL FROM: command. This special form of keyword in your access database allows you to cause sendmail to print a code, followed by words of your choice. Consider this entry in the access database:
From:firstname.lastname@example.org ERROR:554 Spam delivery is unavailable.
Here we chose 554, which stands for "service unavailable." When mail is received at your site, this rule will cause the following interaction in the SMTP conversation:
MAIL FROM:<email@example.com> 554 5.0.0 <firstname.lastname@example.org>... Spam delivery is unavailable.
The text you give following the SMTP might or might not appear in the bounced mail that sales receives.
The XYZ code you specify does not have to be a 500 code (meaning failure). You are also free to use 400 codes (to defer the mail) too. Deferral might be appropriate as a means to handle a temporary resource limitation:
email@example.com 421 Our database is down for two days for repair
This righthand value is the same as the "XYX text" expression discussed earlier, but the ERROR: signals that the envelope-sender should be rejected. The XYZ is optional, and sendmail will supply a value if it is missing. This provides a handy way to reject mail without having to remember the correct SMTP numbers:
firstname.lastname@example.org ERROR: Stop spamming us
When this address arrives from the outside, the SMTP will look like this:
MAIL FROM:<email@example.com> 553 5.3.0 <firstname.lastname@example.org>... Stop spamming us
This righthand value is the same as ERROR:XYZ text, but it allows you finer control of the SMTP rejection message. The D.S.N can be any of the DSN codes defined in RFC1893. You should use this form if you change the SMTP code from the default used by sendmail:
 In support of the examples in this section, we are assuming the blacklist_recipients feature (Section 7.5.5) has also been declared so that the access database can reject mail to specific local recipients.
email@example.com 450 Cache mailbox disk is full
Here, for example, you reject mail to newsupdates at your site because the database is down so you cannot drain the cache file. By changing the SMTP error from its default, you will cause sendmail to wrongly report the DNS error:
RCPT TO:<firstname.lastname@example.org> 450 4.0.0 Cache mailbox disk is full
The 4.0.0 is not the correct DSN code for a full mailbox. Instead, you should specify 4.2.2, like this:
email@example.com ERROR:4.2.2:450 Cache mailbox disk is full
This form uses three colon-delimited fields on the righthand side of the access database. The first field is the literal ERROR string. That is followed by your specification for the correct DSN code. The third field is the SMTP error text as we described earlier.
Prior to V8.10, the lefthand side of the access database could only contain a user, host, domain, or address, and would only look them up based on the client name or address, the MAIL FROM:. address, or the RCPT TO: address.
Beginning with V8.10, sendmail offers much finer control of addresses and rejections in the access database. The lefthand side of the access database can begin with one of three possible prefixes:
 Note that V8.11 and above have added prefixes by embodying them in new features. See the sections that follow for a description of these new prefixes.
The address is either the IP number or hostname of a connecting host.
The address is that of an envelope-sender.
The address is that of an envelope-recipient.
When an address is looked up in the access database, it is first looked up with the prefix. If it is not found, it is looked up again without a prefix, meaning that the old access databases will still work with newer versions of sendmail. To illustrate, consider this update to the access database shown in the previous section:
From:firstname.lastname@example.org REJECT From:cybermarkets.com REJECT Connect:example.org REJECT Connect:192.168.212 REJECT
This access database will cause mail from email@example.com to be rejected. Mail from any user at cybermarkets.com will be rejected, connections from the host example.org will be rejected, and any mail from any host with an IP number ranging from 192.168.212.0 through 192.168.212.255 will have the initial connection rejected. In that last example, any missing righthand part of an IP address is assumed to be a wildcard for matching purposes.
This behavior is exactly the same as the example without prefixes, with one exception. The example.org line, without a prefix, will reject mail from all users at example.org as well as connections from example.org.
A more complex example will better illustrate the properties of the three prefixes:
To:friend.domain RELAY From:friend.domain RELAY Connect:friend.domain OK Connect:bad.domain REJECT
Here, we reject or allow based only on the envelope-recipient or the connecting host.
The first line says that mail arriving at your site, regardless of its origin, will be allowed to be relayed to any user at the site friend.domain. This provides a way to allow relaying on a host-by-host basis, even if you have all relaying turned off with the various antirelay features (Section 7.4). This is useful if you are a secondary MX site for friend.domain.
The second line says that we will also relay mail from the site friend.domain. A line such as this requires that you have declared the relay_mail_from feature (Section 7.4.8) with a literal domain second argument. Here, if the envelope sender is any user at friend.domain, the envelope recipient can be a local or remote address.
The third line says that we will specifically accept connections from the host friend.domain. We do this because that site might be rejected if it is listed on some DNSBL site (Section 7.2). An OK via a Connect prefix overrides any rejection based on DNSBL lists.
The fourth line rejects connections from the host bad.domain no matter what. This is one way to reject connections on a site-by-site basis, if, for example, you want to block messages from a site that is pushy but not eligible for listing with a DNSBL server.
Even if you lack an immediate use for these prefixes you should consider using them, just to experience their power.
When an address is rejected because of the presence of REJECT in the access database, it is rejected with the default message:
550 5.7.1 Access denied
Beginning with V8.9 sendmail, you can change that message (to augment it or to clarify the reason for the rejection) using the confREJECT_MSG mc file macro. For example, to show why the message was rejected, you could place the following in your mc file:
define(`confREJECT_MSG', `550 Access denied. See http://www.your.domain/access_ denied')
Because the message you specify will be quoted in the configuration file, you cannot place any m4 macros or positional m4 macros in the message. They will be silently stripped from the message.
The access_db feature (Section 7.5) provides a way to selectively reject envelope-sender addresses. By declaring this blacklist_recipients feature, you enable the access database to also selectively reject envelope-recipient addresses:
Consider the need to prevent outsiders from posting to strictly inside mailing lists. In this example, the mailing lists are handled on a machine different from that on which outside mail is received. On the receiving machine, you would put lines such as these in your access database:
firstname.lastname@example.org 550 Outside access to private mailing list banned email@example.com 550 Outside access to private mailing list banned firstname.lastname@example.org 550 Outside access to private mailing list banned
By declaring this blacklist_recipients feature, these addresses will be prevented from receiving outside mail.
All forms of addresses in the access database can be used for this recipient rejection. Consider:
To:badguy@ ERROR:550 Mailbox disabled for this user To:host.our.domain ERROR:550 This machine bans email To:22.214.171.124 ERROR:550 Printers cannot receive email
Be careful when rejecting recipients based on the username alone, as in the first line in this example, because the username is rejected for both the envelope-sender and the envelope-recipient. Thus, this line will reject mail to both badguy locally, and from badguy at all other sites in the world.
When a connection is made to your site by another, the access database is checked to reject unwanted connections. It is checked again when the SMTP MAIL FROM: command is given to accept or reject the envelope sender. It is checked a third time when the SMTP RCPT TO: command is given to accept or reject the envelope recipient, and prevent unwanted relaying.
 If the host is listed with the RELAY_DOMAIN mc macro (Section 126.96.36.199) or in the file specified by the RELAY_DOMAIN_FILE mc macro (Section 188.8.131.52), it is relayed without checking the access database.
This order is good for most sites, but might not be the best for your particular needs. In case it isn't, the delay_checks feature offers a way to check the SMTP RCPT TO: address first, before the other two checks, and then proceed with those other two checks, if appropriate. Delayed checks are enabled with the delay_checks feature, which you declare in your mc file like this:
Note that the access_db feature needs to be enabled before you enable the delay_checks feature.
Once enabled, the order of checks is changed. If the righthand side in the access database is either REJECT or an SMTP error for the envelope-recipient, the envelope-recipient is rejected as usual. But if the envelope-recipient is allowed, the envelope-sender is then checked, and if it is rejected, the envelope-recipient is rejected with the envelope-sender's error message. If the envelope-sender is allowed, the connecting host is checked, and if it is rejected, the envelope-recipient is rejected with the connecting host's error message.
For example, consider the following abstract from an access database:
To:postmaster@ OK From:larry@ REJECT Connect:spammer.domain REJECT
With the delay_checks feature enabled, the first check will come as part of the SMTP RCPT TO: command, and that address will be looked up in the access database. In this example, if the user part of the recipient address is postmaster, the message will be accepted by the current calling rule set. Subsequent rule sets can still reject it.
 Accepting and rejecting based on the user part of an address require that you also declare the blacklist_recipients feature (Section 7.5.5).
If the user part of the envelope-sender address is not postmaster, the address given to the earlier SMTP MAIL FROM: command will be looked up. If that envelope-sender address has a user part that is larry (in our example) the message will be rejected, but because it is too late to reject the SMTP MAIL FROM:, the rejection will be given to the SMTP RCPT TO: command.
If the envelope-sender is OK, the name of the connecting host will be looked up. If the host is found in the access database, and if the righthand side is REJECT, the message is rejected and the error will be reported in reply to the SMTP RCPT TO: command. If the host is found in the access database, and if the righthand side is RELAY, the message is allowed to be relayed. If the host is not found, and if no other relaying is allowed, the message will not be allowed to be relayed and the denial of relay error, if any, will be reported in reply to the SMTP RCPT TO: command.
One reason to check the SMTP RCPT TO: address first might be to allow mail from a spam site to be delivered to a specific local user, but still block mail from that site for all other users. Another reason might be to block mail from a spam site for a specific user, but allow it to be delivered to all others. You can tune the access database to do one (but only one) of these two things by defining the delay_checks feature with an extra argument that must be one, and only one, of two possible lowercase words:
FEATURE(access_db) FEATURE(`delay_checks', `friend') this one or FEATURE(`delay_checks', `hater') this one, but not both
When the extra argument is friend, you can allow mail from a spam site to a specific local user, while still blocking mail from that site for all other users. When the extra argument is hater, you can block mail from a spam site for a specific user, while allowing it to be delivered to all other users. If the extra argument is neither (or was uppercase), the following error will be printed when you build your configuration file, and that file will be incomplete:
*** ERROR: illegal argument bad word here for FEATURE(delay_checks)
The check_rcpt (Section 7.1.3) rule set performs the lookup, and the relationship found (friend or hater) determines whether the check_mail (Section 7.1.2) and check_relay (Section 7.1.1) rule sets should be called to perform further checks.
If the extra argument is friend and if the database lookup returns FRIEND, those further rule set checks will be skipped and the message will be accepted. But if the database lookup fails to find the address, or returns something other than FRIEND, further screening by the check_mail and check_relay rule sets is performed.
If the extra argument is hater and the database lookup returns HATER, further screening by the check_mail and check_relay rule sets is performed. But if the database lookup fails to find the address, or returns something other than HATER, those additional rule sets will be skipped.
As a first step, decide which of the two forms you prefer (remember, you can only do one or the other), then add the new definition to your mc file, generate a new configuration file, and install it. Once the new configuration is ready, you can use one of two new righthand side keywords in your access database:
This address is allowed to receive messages that would otherwise be rejected by the check_mail and check_relay rule sets. You can use this keyword only if you defined friend when you declared the delay_checks feature.
This address will only receive messages that are also accepted by the check_mail and check_relay rule sets. An address not listed as SPAMHATER (V8.10 and V8.11) or HATER (V8.12) will have processing by those additional rule sets skipped. You can use this keyword only if you defined hater when you declared the delay_checks feature.
To illustrate, consider the following abstract from such an access database where we declared the delay_checks feature as friend:
Connect:spam-mail.com REJECT To:email@example.com SPAMFRIEND V8.10 through V8.11 Spam:firstname.lastname@example.org FRIEND V8.12
The site spam-mail.com is one of possibly many sites that will be rejected by our site because they are known spammers. Mail addressed to email@example.com will be accepted even if it is from any of the rejected spam sites.
In the following example we declared the delay_checks feature as hater:
Connect:spam-mail.com REJECT To:firstname.lastname@example.org SPAMHATER V8.10 through V8.11 Spam:email@example.com HATER V8.12 To:firstname.lastname@example.org OK
Here, the site spam-mail.com is one of possibly many sites that will be rejected by our site because they are known spammers. Mail to email@example.com will have spam sites rejected. Mail to firstname.lastname@example.org will still be allowed to receive mail from otherwise rejected sites.
Whether you choose the spam haters or spam friends approach is entirely dependent on your site's unique needs. Think through the logic of your choice before setting up your access database. If you make a mistake, you might inadvertently allow spam to a user who doesn't want it.
Note that you cannot mix friends and haters. If you do, sendmail will ignore the mismatch. For example, if you declare the delay_checks feature as friend and place the following entry into your access database, that entry will be ignored:
Spam:email@example.com HATER ignored because delay_checks specified friend
Remember, you must choose one, and only one: either friend or hater. You cannot choose both, nor can you mix the two.
Note that the syntax of this delay_checks feature has changed. It differs between V8.10 through V8.11 and V8.12. If you have already used this feature with V8.10 or V8.11 sendmail, you will need to change it for V8.12. You will need to add the Spam: prefix and new righthand side values to your access database.
As an aid to conversion, the old syntax will be ignored. Once you have finished converting from the earlier syntax to the new, you can redeclare this V8.12 delay_checks by adding a literal n as a third argument:
FEATURE(`delay_checks', `friend', `n') V8.12 and above FEATURE(`delay_checks', `hater', `n') V8.12 and above
This n turns off backward compatibility (the ability to ignore the old syntax) and causes the old syntax to produce an error. The is a good way to check to be sure your conversion was good.
Also note that, with V8.12, if an envelope-recipient is found to be trusted, using one of the mechanisms listed with the AuthMechanisms option (AuthMechanisms), that envelope-recipient is accepted and further access database checks are skipped.
Beginning with V8.12 sendmail, you can create a rule set that makes decisions about envelope-sender and envelope-recipient pairs with entries in the access database. To enable these checks, just add the check_compat feature to your mc configuration file:
FEATURE(access_db) must be first FEATURE(check_compat)
Once this is enabled, you can then add entries such as the following to your access database (note that the <@ > is literal):
Here, the Compat: prefix is literal and must be present. It is immediately followed (with no intervening spaces) by the envelope-sender address, a literal <@>, and the envelope-recipient address (where the envelope-recipient address has already undergone aliasing and processing by a user's ~/.forward file). Neither address should be surrounded with angle braces. The address pair is followed by whitespace (spaces and tabs) and then a keyword. There are three possible keywords:
Mail from this sender to this recipient is accepted, then discarded and logged. DISCARD can be followed by a colon. It can also be followed by optional text that will be logged as the reason for the discard.
Mail from this sender to this recipient is rejected with a temporary error (causing the message to be deferred for a later delivery attempt). This keyword must be followed by a valid 4xy SMTP code and text that describes the reason for the temporary failure.
Mail from this sender to this recipient is rejected with a permanent error (causing the message to bounce). This keyword must be followed by a valid 5xy SMTP code and text that describes the reason for the rejection.
To illustrate, consider the following example of such entries in an access database:
Compat:firstname.lastname@example.org<@>email@example.com DISCARD Compat:firstname.lastname@example.org<@>email@example.com DISCARD Compat:firstname.lastname@example.org<@>email@example.com TEMP:421 printer is down for repair Compat:firstname.lastname@example.org<@>email@example.com ERROR:553 Interoffice banter banned Compat:firstname.lastname@example.org<@>email@example.com ERROR:553 Interoffice banter banned
The first line might be used at a site where the pseudo-user bin generates a great deal of automated email and that email is sent to admin, among others. This line causes that automated mail to be accepted and discarded.
The second line might be used to prevent mail from a known spam list from being sent to the user taka at your site. This line causes that spam mail to be accepted and discarded.
The third line might be used to defer mail to a printer from the database. The TEMP will cause the message to be deferred for a later try. You could then remove this line after the printer is repaired and back in service.
The last two lines show a way to prevent two users at your site from sending email to each other. The idea is that it is OK for them to send email to each other at other sites, but not this one. Each such prohibited message is rejected and bounced. For this scheme to work, however, you will need to place an empty root-owned ~/.forward file in each of the two users' home directories to prevent them from bypassing this restriction by setting up their own ~/.forward files.
This last example underscores a weakness in this compat_check feature. Because each envelope-recipient undergoes aliases translation, and ~/.forward translation before the lookup, the entry in the access database must correctly represent the translated address. For example, consider a pseudo-user named nill who has an aliases file entry such as this:
# deep six mail to nill nill: /dev/null
Here, the intention is to have all mail to nill delivered to the /dev/null file. If you wanted selected mail to nill to be rejected, do not do this:
Compat:firstname.lastname@example.org<@>email@example.com ERROR:553 Don't mail to nill note
The firstname.lastname@example.org will never be found because by the time this lookup happens nill has been transformed into /dev/null. The correct way to set up your access database to handle this situation would look like this:
Compat:email@example.com<@>/dev/null ERROR:553 Don't mail to nill note
Also note that when the recipient is an actual user (as, for example, bob):
Compat:firstname.lastname@example.org<@>email@example.com ERROR:553 Don't mail to nill
bob can alter his ~/.forward file at any time, thus rendering his recipient entry useless.
Normally, lookups of hosts in the access database are literal. That is, host.domain is looked up first as host.domain and then as domain. If you declare the lookupdotdomain feature (FEATURE(lookupdotdomain)), or add a literal lookupdotdomain fourth argument (Section 7.5.1) to the access_db feature's declaration, you cause the sequence to become host.domain, then .domain, and lastly domain. This feature allows you to structure an access database to handle the domain differently than it handles hosts in the domain:
 If you have already not done so, you will also first need to declare the access_db feature.
From:.domain REJECT From:domain OK
Here, envelope-senders with a host part of @anything.domain will be rejected, but those with a host part of @domain will be accepted. To illustrate, consider the following attempt to accept mail only from cs.Berkeley.EDU and to reject mail from hosts in that subdomain:
From:.cs.Berkeley.EDU REJECT From:cs.Berkeley.EDU OK
Beginning with V8.12, it is possible to select queue groups using the access database by declaring the queuegroup feature. Queue groups and the queuegroup feature are discussed in detail in Section 11.4.
Beginning with V8.12, it is possible to accept, reject, and allow relaying based on the STARTTLS and AUTH= SMTP extensions. These abilities, and the features that support them, are detailed in Section 10.10.8.