Debugging check_* in sendmail 8.8/8.9 and later

Last Update 2006-03-31
Content: check_mail | check_rcpt | check_relay | Problems with FEATURE(access_db) | Misc

Some suggestions to debug the check_* rules

After you have installed the new check_* rules or you use sendmail 8.9 (and later) standard FEATUREs to avoid misuse of your system and spam from well-known sites, you need to test them. Or you can blindly trust the guys who wrote them... (never do that, someone may have made a mistake!).

First, you can use conventional debugging by testing the rewrite rules directly with sendmail -bt . If you want to test those rulesets (check_relay, check_compat) which use the $| token, you should introduce the following ruleset first:

R$* $$| $*		$: $1 $| $2		fake for -bt mode, remove for real version
since you can't enter the token $|. You have to enter then
> Start,check_compat from_addr $| to_addr
to check your rules. Thanks to Bryan Costales and Eric Allman for this tip.

A hint: nearly all of these rules require a working hostname canonicalization. They don't work if you use FEATURE(nocanonify) in your .mc file. For check_rcpt the option _NO_CANONIFY_ can overcome this problem.

A small note for Solaris 2 users from the 8.8.6 Beta Release Notes:

Solaris: a bug in strcasecmp caused characters with the
	high order bit set to apparently randomly match
	letters -- for example, $| (0233) matches "i" and "I".
	Problem noted by John Gregson of the University of

Debugging check_mail

Let's assume you implemented the rules to block mail from spammers. Checking these is fairly simple. Let's assume you have and in your class (or map) of spammers/spamdomains. Then run:
sendmail -bt
> check_mail <>
> check_mail <>
In both cases you should get an error code back, like:
rewrite: ruleset 196 returns: $# error $@ 5 . 7 . 1 $: "550 You are banned, contact your local admin."
rewrite: ruleset 196 returns: $# error $@ 5 . 7 . 1 $: "550 This domain is banned, contact your local admin."
If it doesn't work as expected you can have a look at the class you defined:
sendmail -bt
> $={Spammer}
> $={SpamDomains}
or check the map you use:
sendmail -bt
> /map junk
map_lookup: junk ( returns JUNK (0)
map_lookup: junk ( returns "some error text"@JUNK (0)

Debugging check_rcpt (Anti-Relay)

check_rcpt makes use of the macro ${client_name} or ${client_addr}. You can set the value like this:
sendmail -bt -d21.4
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> .D{client_addr}
> .D{client_name}
You should try the following tests:
  1. e-mail from intern to extern,
  2. e-mail from extern to intern,
  3. e-mail from extern to extern.
Let's assume the following: you use {LocalIP} , one of the entries in it is , and extern IP address is , a local hostname is , and an extern name is . So you have to perform these tests:
  1. e-mail from intern to extern:
    sendmail -bt -d21.4
    > .D{client_addr}
    > .D{client_name}
    > check_rcpt <>
    (sample output from 8.8, 8.9 (and later))
  2. e-mail from extern to intern,
    sendmail -bt -d21.4
    > .D{client_addr}
    > .D{client_name}
    > check_rcpt <>
    (sample output from 8.8, 8.9 (and later))
  3. e-mail from extern to extern.
    sendmail -bt -d21.4
    > .D{client_addr}
    > .D{client_name}
    > check_rcpt <>
    (sample output from 8.8, 8.9 (and later))
Only the last test should produce an error (8.8):
rewrite: ruleset 195 returns: $# error $@ 5 . 7 . 1 $: 550 we do not relay
or (8.9 (and later)):
rewrite: ruleset 181 returns: $# error $@ 5 . 7 . 1 $: "550 Relaying denied"


  1. You have to set ${client_addr} for HACK(use_ip) and ${client_name} for HACK(use_names) . If both HACKs or the standard FEATUREs of sendmail 8.9 (and later) are used, both macros have to be set.
  2. If you use maps for the relay test (like the access Map in sendmail 8.9 (and later) or _LOCAL_IP_MAP_ from my check_rcpt ), then you can test the map with:
    sendmail -bt
    > /map access
    > /map localip
    You probably need to check the nets too, depending on the entries in the map:
    sendmail -bt
    > /map access 1.2.3
    > /map localip 1.2.4
    etc. The mapname access is for sendmail 8.9 (and later) , localip is for my check_rcpt HACK.
  3. If it doesn't work as expected you can have a look at the class you defined:
    sendmail -bt
    > $=R
  4. The code to remove those hostnames or domains for which you accept incoming mail as relay relies on DNS to canonicalize these names. The rule
    # pass to name server to make hostname canonical
    R$* < @ $* $~P > $*		$: $1 < @ $[ $2 $3 $] > $4
    in S96 adds a trailing dot to the names which is required for matching. So if you test the rules, make sure you use real names with entries in the DNS. (this doesn't apply to 8.9 (and later)).
  5. If you use _ALLOW_SOME_, _RELAY_ACCESS_FROM_ or _CHECK_MAIL_IN_RCPT_ you also have to set $f:
    sendmail -bt
    ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
    Enter <ruleset> <address>
    > .Dfuser@some.domain

check_rcpt and entries in the logfile

Blocked relay attempts can be found in the logfile, like this one:

QAA02454: <ESCAPEFOUR@AOL.COM>... we do not relay
QAA02454: ruleset=check_rcpt, arg1=<ESCAPEFOUR@AOL.COM>, [], reject=550
	<ESCAPEFOUR@AOL.COM>... we do not relay
QAA02454: from=<Anonymous>, size=0, class=0, pri=0, nrcpts=0,
	proto=SMTP, []
If you have a problem with check_rcpt denying relaying which should be allowed, you can use the entries from the logfile to check your rules and classes/maps. The relay= should be used for ${client_name} , i.e.,
> .D{client_name}
or ${client_addr} , i.e.,
> .D{client_addr}
and arg1 for the ruleset, i.e.,
> check_rcpt <ESCAPEFOUR@AOL.COM>
This way you can see which classes/maps you have to modify. For this example,
would have to be added to the class {LocalIP} or
to the class {LocalNames} (if the standard configuration is used, otherwise one of this entries needs to be added to the used map).

Debugging check_relay

check_relay can be used to deny access to your server. If you use a map, please check whether it works. Also make sure that you have the additional ruleset for testing. Then you can try:
sendmail -bt -d21.4
> .D{client_addr}from_IP_addr
> Start,check_relay from_host $| from_IP_addr
Don't forget to set ${client_addr} because otherwise the test of the DNS based rejection lists won't work.

Problems with FEATURE(access_db) (Map lookups)

If your access map (or any other map) doesn't work, try the following:
  1. You didn't forget to actually create the map? Use the makemap(8) command, e.g., makemap hash /etc/mail/access </etc/mail/access
  2. Remove the '-o' option and test again. Now sendmail will complain if there are problems with the map, like: unsafe map file.
  3. Use the debug mode to test the entries:
    sendmail -bt
    > /map access ENTRY
    where ENTRY is something which is on the LHS of the map. It should return the RHS, e.g.,
    map_lookup: access (ENTRY) returns "550 no mail from ENTRY" (0)

Running sendmail as daemon with debug flags

To check the rules which refer to special macros such as ${client_name} or ${client_addr} you can run sendmail in debug mode: sendmail -bd -d21.4 (or other debug flags, see src/TRACEFLAGS in the actual source). Do this testing only on a special machine of course, don't put it on a production machine, if there is a mistake in your rules, you may receive no mail at all...
BTW: sendmail uses internally only numbers for the rulesets, so you won't see: ruleset check_mail or something similar, but numbers just below 200 for the check_* rulesets.

Now you can connect from another machine either by hand telnet test.machine smtp or use the -v flag of Mail to see the actual SMTP dialogue.

Scripts to test mail relaying capabilities

Andrew Daviel wrote a nice script to check whether e-mail can be relayed through your system. (It requires PERL 5). Make sure you read the

 DISCLAIMER: This script is intended to test mail relaying capabilities.
 Unauthorized use of this script on non-local hosts may be interpreted as 
 a network attack.
 Each copy of this script is identified by a unique serial number and  
 may be traced back to the user.   

The CIAC Email Relay Problem Test uses a script written by Chip Rosenthal.

Scripts to analyze the logfile

smreject: A perl script written by Ted George which analyzes the sendmail logfile for rejected messages based on the check_* rules. Shows rejected message counts for each junk file entry. Also shows counts of failed messages for the top mail relay hosts and email addresses attempting to use your mail server.
Tim Wicinski wrote another perl script for a similar purpose.

Another sendmail daemon on a different port

Stefan Bethke pointed out that it is also possible to run another sendmail daemon with a test configuration file on a different port, e.g., sendmail -bd -oOP=4321 . Now it is possible to use telnet 4321 or mconnect -p 4321 for testing purposes.


If you have other proposals to debug the new rules, please let me know.

[(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.