Revision 2 as of 2008-04-12 11:33:09

Clear message

LMTP in Mailman

RFC 2033, Local Mail Transport Protocol (LMTP) provides Mailman with a unique opportunity to provide a better user experience when accepting initial postings. Two improvements in the process are available with LMTP.

First, we can eliminate most of the integration cruft we currently have with supporting multiple MTAs for incoming mail. Most of the major SMTP servers support LMTP delivery, so by providing an LMTP server in Mailman, the hope is that we can avoid all the crufty MTA-specific alias hackery.

Second, and perhaps more importantly, we can support better anti-backscatter and anti-spam defenses for messages sent to the mailing lists, by rejecting messages in the SMTP dialog instead of having to make the determination way later and sending a bounce message. Ian Eiloart describes what is possible:

on connect:
accept the connection
HELO/EHLO:
reject if the sending MTA isn't known
MAIL FROM:
accept (perhaps unless the sender address is forbidden to post to all 
lists).
RCPT TO:
accept if the sender has permissions to post to the list, otherwise reject. 
This is the last chance to give a list specific response to an MTA that is 
engaged in a callout.
DATA:
reject null senders here if appropriate. Rejecting a null sender at RCPT TO 
or earlier might break callouts.
.............
.
Check the data, reject if inappropriate for a specific list (but this is 
likely to cause a bounce from our MTA). Because we've decided to trust the 
sender, we should be OK to bounce a message here, unless the list is an 
open list.

I believe MM3's architecture can easily support this, and I've been working with Ian on the mailing list to sketch out a design. I think we should do this for MM3.


Comments

Ian Eiloart

William Mead has been working on LMTP code for me. He's produced implementations for version 3.0 and for version 2.2, with these tests applied after RCPT TO in the LMTP conversation:

1. message will be rejected if the list name is not known.
2. message will be accepted if the sender matches "accept_these_nonmembers".
3. message will be accepted if "generic_nonmember_action" is not reject.
4. message will be accepted if the sender is a list member.
5. if we get this far, the message will be rejected - the sender is a non-member of a closed list.

We could also reject other members if they're moderated, for example. However, we've adopted the view that it is relatively safe to generate a bounce message for someone who is a member of the list.

William has completely reimplemented the SMTPD code in Python, to support ENHANCEDSTATUSCODES, because the LMTP RFC requires that - even though the examples in the RFC don't show them being used! However, the code doesn't implement PIPELINING - also required by LMTP - because the underlying ASYNCHAT/ASYNCORE architecture doesn't seem to support it. We discovered that advertising PIPELINING causes the test smtp client to fail, but we've not even thought about how to fix that - LMTP clients which are re-implementations of SMTP clients might just live with the fact that PIPELINING isn't advertised.

William's code is at https://code.launchpad.net/~wilunix

The LMTP queue runner allows us to run Mailman on a server that's unrelated to the main MTA. With an Exim MTA, you could use a recipient callout to verify that the sender is permitted to post to the list, before accepting the message for deliver. This means that rejecting an unwanted message should not create collateral spam.