Per-User-Milter: Let users filter mail individually

Written by Kim Vandry <vandry@TZoNE.ORG>

Project information and download available on Sourceforge


Per-User-Milter is a milter (sendmail plugin with the ability to filter messages at the SMTP level) that lets each prospective recipient decide whether or not they want the message and rejects it if everyone agrees it's not wanted. Each user can examine the full message.

Per-User-Milter is licensed under the GPL.

Status & News

2007-03-31: Found and fixed two elusive bugs. Releasing.

2007-03-24: Per-User-Milter was ignored for a while but is being looked at again.

2006-11-17: Per-User-Milter has been written and is going through initial testing.


When Sendmail acts as an SMTP server, Milters let an external process perform certain operations on the message including advising sendmail to reject the message. In the case of spam, the alternative to rejecting a detected spam message during the SMTP conversation is discarding it into the bit bucket later. It is useful to give Sendmail the opportunity to reject a message at this early stage because it pushes the burden of bouncing the message (if applicable) to the remote client. If the remote client is a spammer then further processing of the message is saved. If a message is erroneously rejected (a false positive for the spam detector) and the remote client is in fact legitimate then at least the sender will get a bounce, which is better than if the message had been discarded.

Milters alone only let you define site-wide policy. Indeed, this is unfortunately somewhat inherent in the way SMTP works, assuming you want to see a copy of the message before you make the decision to reject it or accept it: there is no opportunity after the message has been received by the server (end of the DATA stage) to indicate to the sender that some prospective recipients would like to reject the message and others would like to keep it — the SMTP transaction in its entirety can only be accepted or rejected (or you can indicate a temporary, retryable failure).

Per-User-Milter aims to delegate the decision to accept or reject the message to each recipient who is a local user. This is useful if different users require different policies (such as different levels of aggressivity in automatic spam detection). Given the stated limitation of how SMTP works, almost the best that can be done is to ask each prospective user the question, and reject the entire SMTP transaction if every user agrees the message should be rejected. The milter API is also a fairly complex API. per-user-milter also aims to simplify this by calling an external executable for each user with an easier interface similar to what an external program in a procmail recipe would see: the full message can be read from standard input and the decision to accept or reject is indicated by the exit status.

Additional requirements are:

Requirements that will not be met in the initial version:


I started creating user-milter script for myself that includes many of the checks I was already performing after delivery of the mail to decide whether and how to quarantine it. I expect to expand upon this but it is already working not too badly for me.

Someone who uses SpamAssassin might be interested in creating quite a simple user-milter script that calls SpamAssassin and returns the results.