[Mailman-Users] configuring mailman with courier

Mark McEahern marklists at mceahern.com
Wed Mar 12 23:32:25 CET 2003

I just spent a considerable amount of time getting Mailman to work with
Courier as the MTA.

I'm sure there's probably more than one way to do it, but here's an outline
of what I did.  I offer this here in the hopes that anyone trying to do this
in the future won't have to pursue all the deadends I did.  ;-)

Courier setup

For starters, I'm using authpgsql as the authmodule for Courier.  The domain
where I'm hosting Mailman is one of my hosteddomains.


I did NOT have to create any accounts for Mailman, local or virtual.  I do
everything with aliases.  That, to me, seems like A Good Thing (tm).  I
would have liked to use a single dot-courier file for each alias instead of
using the intermediate dummy aliases as described below, but I was unable to
get the .courier-alias at domain:com stuff to work.

After running bin/newlist, I copy the alias information it spits out into a
file (e.g., mylistname-list.aliases).  I then run a Python script on this
file that does this:

1.  Creates a file in /path/to/courier/etc/aliases/ named after the list.  I
name the alias file after the list just to keep each list's aliases separate
and easily identifiable.  In this file, I create intermediate aliases.
Suppose my list is named mailman and the hosted domain is domain.com.  Then
I'd have:

    mailman at domain.com: mailman1
    mailman-admin at domain.com: mailman2

The right-hand side is a dummy alias.

2.  For each dummy alias, create a dot-courier file in
/path/to/courier/etc/aliasdir/.  E.g.,


The contents of each dot-courier file look like this:

    |/opt/mailman/mail/mailman post mailman

In other words, the contents of the dot-courier file are the same as the
right-hand side of what bin/newlist spits out for that alias, just without
the quotation marks.

I've attached the actual script below.


// mark

#!/usr/bin/env python

Create the dot-courier files for the aliases listed in the specified file.

import os
import sys
import pwd

class IncorrectUserError(Exception):pass

def require_user(username):
    """Exit if the current user is not username."""
    current_username = pwd.getpwuid(os.getuid())[0]
    if current_username != username:
        template = 'Please run as %s (current user: %s).\n'
        message = template % (username, current_username)
        raise IncorrectUserError(message)

class Alias(object):

    def __init__(self, alias, domain, command, counter):
        self.alias = alias
        self.domain = domain
        self.command = command
        self.counter = counter

    def get_basename(self):
        alias = self.alias
        i = alias.find('-')
        if i >= 0:
            return alias[:i]
            return alias

    def get_full_alias(self):
        return '%s@%s' % (self.alias, self.domain)

    def get_dummy_alias(self):
        return '%s%d' % (self.get_basename(), self.counter)

def main():
    program = os.path.basename(sys.argv[0])
    usage = 'usage: %s listname filename etcdir [domain]\n' % (program,)
        listname = sys.argv[1]
        filename = sys.argv[2]
        etcdir = sys.argv[3]
    except IndexError:

    default_domain = 'yourlistdomain.com'
        domain = sys.argv[4]
    except IndexError:
        domain = default_domain

    courier_username = 'courier'
    except IncorrectUserError, e:
        message = str(e) + '\n'

    if not os.path.isdir(etcdir):
        message = 'etcdir %s is not a directory.\n' % etcdir

    comment_char = '#'
    separator = ':'
    quote = '"'
    aliases = []
    counter = 0
    for line in file(filename):
        if line.startswith(comment_char):
        counter += 1
        line = line.strip()
        if not line:
        alias, command = line.split(separator)
        alias = alias.strip()
        command = command.strip()
        if command.startswith(quote):
            command = command[1:]
        if command.endswith(quote):
            command = command[:-1]
        a = Alias(alias, domain, command, counter)

    # Write the intermediate aliases to $etcdir/aliases/.
    filename = os.path.join(etcdir, 'aliases', listname)
    f = file(filename, 'w')
    for a in aliases:
        f.write('%s: %s\n' % (a.get_full_alias(), a.get_dummy_alias()))

    # Write the dot-courier file to $etcdir/aliasdir/.
    dirname = os.path.join(etcdir, 'aliasdir')
    for a in aliases:
        basename = '.courier-%s' % (a.get_dummy_alias(),)
        filename = os.path.join(dirname, basename)
        f = file(filename, 'w')
        f.write(a.command + '\n')

    print 'You must run makealiases for these changes to take effect.'

if __name__ == '__main__':


More information about the Mailman-Users mailing list