I've had lots of success with mailman on <lists.zx2c4.com>. Here's my
config for it:

listen on eth0 hostname krantz.zx2c4.com
accept from any for domain lists.zx2c4.com virtual { "@lists.zx2c4.com" =>
mailman } deliver to mda "/var/lib/mailman/smtpd-deliver %{rcpt.user}"

Mailman is configured with the usual setup in /var/lib/mailman according to
their manual. smtpd-deliver is the clever part that makes the whole thing
really easy to work with:

krantz opensmtpd # cat /var/lib/mailman/smtpd-deliver.c
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>

static const char *verbs[] = { "admin", "bounces", "confirm", "join",
"leave", "owner", "request", "subscribe", "unsubscribe" };
#define verbs_len (sizeof(verbs) / sizeof(const char *))
static const char *empty_verb = "post";

int main(int argc, char *argv[])
{
        DIR *lists;
        struct dirent *list;
        int list_len, rcpt_len, i;
        const char *verb;

        if (argc != 2)
                return 1;

        rcpt_len = strlen(argv[1]);

        lists = opendir("/var/lib/mailman/lists");
        if (!lists) {
                perror("opendir");
                return 1;
        }
        while ((list = readdir(lists))) {
                if (list->d_name[0] == '.')
                        continue;
                list_len = strlen(list->d_name);
                if (list_len > rcpt_len)
                        continue;
                if (strncasecmp(argv[1], list->d_name, list_len))
                        continue;
                verb = argv[1] + list_len;
                if (!verb[0])
                        verb = empty_verb;
                else if (verb[0] == '-') {
                        ++verb;
                        for (i = 0; i < verbs_len; ++i) {
                                if (!strcmp(verbs[i], verb))
                                        break;
                        }
                        if (i == verbs_len)
                                continue;
                } else
                        continue;
                execl("/var/lib/mailman/mail/mailman", "mailman", verb,
list->d_name, NULL);;
                return 1;
        }
        closedir(lists);
        return 1;
}

Or if you prefer, here's a version in python:

krantz opensmtpd # cat /var/lib/mailman/smtpd-deliver.py
#!/usr/bin/env python2
import sys
import os

lists = os.listdir("/var/lib/mailman/lists")
verbs = { "": "post", "admin": "admin", "bounces": "bounces", "confirm":
"confirm", "join": "join", "leave": "leave", "owner": "owner", "request":
"request", "subscribe": "subscribe", "unsubscribe": "unsubscribe" }

mail = sys.argv[1].lower()

for ml in lists:
        if mail.startswith(ml):
                verb = mail[len(ml) + 1:]
                if verb not in verbs:
                        sys.exit(1)
                verb = verbs[verb]
                os.execl("/var/lib/mailman/mail/mailman",
"/var/lib/mailman/mail/mailman", verb, ml)
                sys.exit(1)
sys.exit(1)


So far, mailman has been a joy to use and administer. Everything is super
super simple once it's rolling.

Reply via email to