Message-ID Headers From Non-Local SMTP Clients

Rejecting spam from non-local SMTP clients with local Message-ID headers

I was looking at some of the spam I received today and found a message that had a Message-Id: header that was generated by my mail host. This is an indication of a message that was passed via SMTP to my host with no Message-Id: header passed during the DATA phase. Since the Message-Id: header was missing, my host generated one and inserted into the message. I got to thinking about this and realized that the sendmail 8.9 feature of sending headers to check_* type rulesets could be used to reject non-local messages with a locally generated Message-Id: header.

There are three cases in which a local Message-Id: header is generated:
1) Local messages generated on the local system with a local MUA
2) A POP or IMAP type SMTP client that is part of the local domain
3) Everything else (which implies the sender is remote and the message is spam)

Use this header ruleset to test if the client is local, in which case accept any Message-Id: header. Otherwise if the Message-Id: header ends with the local host's FQDN, <anything@$j>, then the client is remote and passed us a SMTP message without a Message-Id: header. If this is the case, then the message is probably spam and should be rejected.

Here is the ruleset. I hope my comments explain what I am trying to do.

	HMessage-Id: $>CheckMessageId

	# check for local Message-Id: header for non-local SMTP clients
	# put client hostname in an initial lookup focus
	# anything	->	   <  lookup focus   > anything
	R$*			$: < $&{client_name} > $1

	# test if client hostname in lookup focus ends with one of our
	#	domains, $=m, if so the message is locally generated and all
	#	Message-Id: headers are OK
	R< $+.$=m > < $+ >	$@ OK

	# reject all other locally generated Message-Id: headers because
	#	client hostname is not local
	R< $+ > < $+ @ $j >	$#error $:"553 Header error, use your own header"

	# strip trash lookup focus leaving the original header
	R< $+ > < $+ >		< $2 >

	# now do the normal header check from the sendmail 8.9.1 cf/README file
	R< $+ @ $+ >		$@ OK
	R$*			$#error $: "553 Header error"

This is something I whipped together and have not tested extensively.
Issues that come to mind are:
What about local mail where $&{client_name} is <NULL>?
Should I include some rules to check for deferred delivery mode?
My header ruleset does not take into account issues of complex sites like class $=R or the access database.

A copy of an m4 template with these definitions in it can be downloaded from here
You would include it in a template file by putting it in the cf/hack directory and using:


or putting it in the cf/feature directory and using:


Ideas and feedback are welcome.
Just another "Harker's Helpful Hints"