[Mailman-Developers] Postfix, Mailman, no aliases file, neat setup?

Barry A. Warsaw barry@digicool.com
Fri, 17 Nov 2000 22:07:10 -0500


Here's a slightly better version of auto, which works with
cross-posting.  The key insight was that Postfix calls auto once for
each mailing list recipient, with the Delivered-To: header set to the
mailing list address.  So this version sucks out the Delivered-To:'s
and parses the necessary information out of there.  Turns out the
recipient_delimiter is necessary in order to get the name of the
mailing list in the Delivered-To: header (with the `mm' prefix, which
is stripped off).  Because of this, each sha hash will be unique so
they shouldn't step on each other's toes.

The (potential) performance issue isn't addressed here, nor is the
bogus address bounce notifications.  The former will need a little bit
of extra help from other parts of Mailman, and the latter may take
some changes in Postfix.  But IMO, it's not a bad hack!

Enjoy,
-Barry

-------------------- snip snip --------------------
#! /usr/bin/env python
#
# Copyright (C) 1998,1999,2000 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software 
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

import sys

import paths
from Mailman import mm_cfg
from Mailman import Utils
from Mailman import MailList
from Mailman import Message
from Mailman.Logging.Utils import LogStdErr
from Mailman.Logging.Syslog import syslog

# Error code if it's really not a Mailman list addr destination
EX_NOUSER = 67

LogStdErr('auto', 'auto')



def fqdn_listname(listname, hostname):
    return ('%s@%s' % (listname, hostname)).lower()



def main():
    syslog('auto', 'Running the auto deliver script')

    # valid destinations
    valids = {}
    lists = {}
    for listname in Utils.list_names():
        mlist = MailList.MailList(listname, lock=0)
        lists[listname] = mlist
        valids[fqdn_listname(listname, mlist.host_name)] = 1

    # Get the message from standard input
    msg = Message.Message(sys.stdin)
    addrs = [addr for name, addr in msg.getaddrlist('delivered-to')]

    syslog('auto', 'found these addresses: %s' % addrs)

    # Parse the headers.  Keys are 'post', 'request', 'owner'
    destinations = {}
    for addr in addrs:
        localpart, hostname = addr.split('@', 1)
        try:
            listname, subdest = localpart.split('-', 1)
        except ValueError:
            listname = localpart
            subdest = 'post'
        try:
            prefix, listname = listname.split('+')
        except ValueError:
            prefix = None
        if subdest in ('post', 'request', 'owner', 'admin') and \
               valids.has_key(fqdn_listname(listname, hostname)) and \
               prefix == 'mm':
            destinations.setdefault(subdest, []).append(listname)

    if not destinations:
        # Tell Postfix we found no valid list destinations
        syslog('auto', 'No Mailman destination found')
        return EX_NOUSER

    syslog('auto', 'destinations: %s' % destinations)

    # TBD: This may not work for cross-posted messages
    for subdest, listnames in destinations.items():
        for listname in listnames:
            syslog('auto', 'Enqueuing to %s-%s' % (listname, subdest))
            mlist = lists[listname]
            if subdest == 'post':
                msg.Enqueue(mlist, tolist=1)
            elif subdest == 'request':
                msg.Enqueue(mlist, torequest=1)
            elif subdest in ('owner', 'admin'):
                msg.Enqueue(mlist, toadmin=1)
    # success
    return 0



if __name__ == '__main__':
    code = main()
    sys.exit(code)