Mailman Postfix Virtual Domain Config


Contents

Introduction

I needed to install mailman, but greatly prefered to keep it off my primary mail server and gateway. Below are the steps I took to configure mailman on it's own server using a subdomain to host the web interface and the maintenance addresses.

The MTA on both servers is Postfix.


Goals

The goal was to have mailman email lists hosted on a separate subdomain, but to allow users to address the lists using the bare domain name. I wanted mailman lists to be indistinguishable from aliases configured on the mail server.

So, normal email to and from a list will be addressed foolist@lib.example.com and the administrative addresses are just fine in the format of list-owner@lists.lib.example.com.

Restated

  • Mailman on dedicated server separate from the mail gateway.
  • Minimal configuration required on mail gateway when adding lists.
  • Mailing lists addresses in primary domain (foolist@lib.example.com).

Mail Gateway Server

Postfix Settings

There are only a few settings to put in place on the mail gateway.

Transport Delivery

The MX record for the mailman server points to the mail gateway, so we need to tell the mail gateway to forward this mail on to where it needs to be. Do this with the transport map in /etc/postfix/transport.

lists.lib.example.com      :

Masquerading

The mail gateway does cleanup of mail sent from hosts. It translates things like user@hostname.lib.example.com into user@lib.example.com. This makes things more consistent and manageable, however there need to be an exception for this scheme.

Edit main.cf to configure masquerading and list any exceptions. Also, you don't want to masq emails from root so you can easily see what server they came from.

# masquerade as @lib.example.com unless also on this list, never root
masquerade_domains = pager.lib.example.com rt.lib.example.com \
   lists.lib.example.com lib.example.com
masquerade_exceptions = root

Aliases

Email to a mailing list that is addressed to the bare domain, such as foolist@lib.example.com will of course land on the mail gateway, but it must then be shuffled off to the mailman server. This can be accomplished using aliases.

   # mailing lists that live in mailman on another server
   foolist: foolist@lists.lib.example.com

Remember, you don't need an alias for all of the maintenance addresses associated with a list (i.e. foolist-subscribe, etc), because that email will always be addressed to the explicite lists.lib.example.com domain. This meets the goal of minimal configuration on the mail gateway.

When a new list is created only a single alias needs to be added to the mail gateway.


Mailman Server

The mailman server also runs RT, so we don't want to obscure mail with a return address ending in @rt.lib.example.com nor @lists.lib.example.com.

Incoming Email

Postfix Settings

Virtual Domains

Incoming email to this server is handled by processes rather than users. The processes are Request Tracker and Mailman. Each process has it's own virtual domain, rt.lib.example.com and lists.lib.example.com respectively. We need to funnel the mail to each of these domains to the correct process. That is accomplished using virtual_alias_maps.

# http://www.list.org/mailman-install/postfix-virtual.html
virtual_alias_maps = hash:$config_directory/virtual,
   hash:/etc/mailman/virtual-mailman

The /etc/postfix/virtual file will contain the virtual mappings for RT and looks something like this which will cause emails addressed exactly as seen on the left to be delivered to the rt user where they will be processed by procmail and fed to the Request Tracker program. This file is modified by hand whenever queues are changed.

# define addresses for all the RT queues including one for comments
fooqueue@rt.lib.example.com                 rt
fooqueue-comment@rt.lib.example.com         rt

Email to fooqueue@lists.lib.example.com will not be delivered to the rt user because it does not explicitely match a virtual line above and we have lists.lib.example.com handled by the /etc/mailman/virtual-mailman file.

This fille will be manged by the mailman process and will contain the mappings for each list. It looks something like this:

   # STANZA START: foolist
   # CREATED: Tue Oct 17 10:37:21 2006
   foolist@lists.lib.example.com              foolist
   foolist-admin@lists.lib.example.com        foolist-admin
   foolist-bounces@lists.lib.example.com      foolist-bounces
   foolist-confirm@lists.lib.example.com      foolist-confirm
   foolist-join@lists.lib.example.com         foolist-join
   foolist-leave@lists.lib.example.com        foolist-leave
   foolist-owner@lists.lib.example.com        foolist-owner
   foolist-request@lists.lib.example.com      foolist-request
   foolist-subscribe@lists.lib.example.com    foolist-subscribe
   foolist-unsubscribe@lists.lib.example.com  foolist-unsubscribe
   # STANZA END: foolist

You have to configure mailman to create this file. See below.

VERP

Mailman can automate the handling of bounces using VERP. You must help it by configuring

recipient_delimiter = +

Outgoing Email

Mailman Settings

Add these settings to /etc/mailman/mm_cfg.py

DEFAULT_URL_HOST   = 'lists.lib.example.com'
DEFAULT_EMAIL_HOST = 'lists.lib.example.com'
add_virtualhost(DEFAULT_URL_HOST, DEFAULT_EMAIL_HOST)
# Because we've overriden the virtual hosts above add_virtualhost
# MUST be called after they have been defined.
MTA = 'Postfix'
# this will cause /etc/mailman/virtual-mailman to be created
POSTFIX_STYLE_VIRTUAL_DOMAINS = 

When creating a mailing list be sure to set the list host to lists.lib.example.com. But, we don't want users to see this domain name in the mail. How do we avoid that? See the Generics config below.

Postfix Settings

Relay (Smart) Host

We want all email to go through the mail gateway before leaving our domain, so add the following to main.cf

relayhost = 

Masquerading

Edit main.cf to configure masquerading and list the exceptions. Also, you don't want to masq emails from root so you can easily see what server they came from.

# masquerade as @lib.example.com unless also on this list, never root
masquerade_domains = rt.lib.example.com lists.lib.example.com lib.example.com
masquerade_exceptions = root

Generic Translation

Now that we have made sure not to masquerade @lists.lib.example.com on both the mailman server and the mail gateway server we have made sure that email from foolist-owner@lists.lib.example.com will arrive in the user's inbox unmolested. Unfortunately that also means that mail from foolist@lists.lib.example.com will do the same thing.

Add this to main.cf

# goal, on the way out:
#   foo-request@lists.lib stays foo-requests@lists.lib
#   but foo@lists.lib becomes foo@lib
smtp_generic_maps = regexp:/etc/mailman/generic.regexp

Then create /etc/mailman/generic.regexp that looks like this

# the point of this line is, if there are no dashes then masq as @lib
# if there are dashes then the from is something like foo-owner@lists
# and it should be unmolested

# this will work only if you have no hyphenated list names
#/^(+)@lists.lib.example.com$/      $1@lib.example.com

# specifically look for mailman extensions (no pre-spaces on line 2!)
if !/^(.*)-(admin|bounces|confirm|join|leave|owner|request|subscribe|unsubscribe)@lists.lib.example.com$/
/^(.*)@lists.lib.example.com$/  $1@lib.example.com
endif
# now allow the mailman extensions unmolested
/^(.*)@lists.lib.example.com$/ $1@lists.lib.example.com

You can test the expression like this:

# postmap -fq foo-talk@lists.lib.example.com regexp:/etc/mailman/generic.regexp
foo-talk@lib.example.com
# postmap -fq foo-talk-owner@lists.lib.example.com regexp:/etc/mailman/generic.regexp
foo-talk-owner@lists.lib.example.com