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

J C Lawrence claw@kanga.nu writes:
I'm looking to setup a test Mailman site under Postfix (need to do some performance modelling of Exim against Postfix under Mailman for a given membership list). I can get a basic setup working no problem -- now I'm looking to duplicate the neater aspects I already have under Exim, such as losing the Mailman aliases file, etc. Anybody already done this?
Well, you can't lose the aliases file, but you can make it pretty darn invisible.
From postfix's main.cf:
alias_maps = hash:/etc/aliases,hash:/home/mailman/aliases
And the following patch automatically updates the file.
Regards, Owen

"OT" == Owen Taylor otaylor@redhat.com writes:
OT> Well, you can't lose the aliases file, but you can make it
OT> pretty darn invisible.
>> From postfix's main.cf:
OT> alias_maps = hash:/etc/aliases,hash:/home/mailman/aliases
I do this.
OT> And the following patch automatically updates the file.
A couple of notes. First, the version of newlist that's going to be in rc3 (some time today) has a -o/--output switch that does the appending to a specified file, somewhat like the way your patch does (although the file name is taken from the command line and a few other minor differences).
But the real problem is a permissions problem. Say you run postalias
as yourself, because you installed Mailman. Or say you installed it
as user mailman', and that's the user you run postalias as. Then the resulting aliases.db file will be owned by you (or
mailman') and
Postfix will try to deliver email destined for those addresses as your
(or mailman's) gid, but not as the gid you compiled into the wrapper
script.
Thus I found that I had to run newaliases (a.k.a. postalias) as root for the gids to be correct.
Not an insurmountable problem, but it's a pain. It would be nice if Postfix could be configured to automatically run newaliases if necessary (maybe there already is such an option?).
-Barry

On Thu, 16 Nov 2000 16:22:20 -0500 Barry A Warsaw barry@digicool.com wrote:
A couple of notes. First, the version of newlist that's going to be in rc3 (some time today) has a -o/--output switch that does the appending to a specified file, somewhat like the way your patch does (although the file name is taken from the command line and a few other minor differences).
I'm currently toying about to see if I can't persuade some of the alias re-writing and procmail to play to get the sme hiding level as Exim. The most obvious attack is via the $luser, but I'm not real happy with that.

"JCL" == J C Lawrence claw@kanga.nu writes:
JCL> I'm currently toying about to see if I can't persuade some of
JCL> the alias re-writing and procmail to play to get the sme
JCL> hiding level as Exim. The most obvious attack is via the
JCL> $luser, but I'm not real happy with that.
"AM" == Andrew McNamara andrewm@connect.com.au writes:
AM> Mailman would then receive all unknown local destinations, and
AM> would have to recognise owner- and -request style addresses
AM> also. It would also need to return EX_NOUSER (exit 67). Not as
AM> pretty, but should work okay.
Bling! You guys just put the puzzle together for me. What follows is a one hour hack, but it works well enough that I'm fairly certain it could be fleshed out into a real solution.
First, add these configuration options to Postfix's main.cf:
luser_relay = mm+$user@wooz.org recipient_delimiter = +
(changing of course wooz.org to whatever your own domain is). Now all unknown recipients will be forwarded to mm+recipient@wooz.org, but they'll /really/ be sent to the `mm' alias. Which is defined as:
mm: "|/home/mailman/mail/wrapper auto"
This will send all such email through the `auto' script (given below) after traveling as normal through the wrapper safety net. You'll need this patch to src/mail-wrapper.c:
-------------------- snip snip -------------------- Index: mail-wrapper.c =================================================================== RCS file: /cvsroot/mailman/mailman/src/mail-wrapper.c,v retrieving revision 1.16 diff -u -r1.16 mail-wrapper.c --- mail-wrapper.c 2000/08/02 03:23:25 1.16 +++ mail-wrapper.c 2000/11/17 05:19:41 @@ -36,6 +36,7 @@ "post", "mailcmd", "mailowner",
- "auto", NULL /* Sentinel, don't remove */
}; -------------------- snip snip --------------------
and this patch to scripts/Makefile.in:
-------------------- snip snip -------------------- Index: Makefile.in =================================================================== RCS file: /cvsroot/mailman/mailman/scripts/Makefile.in,v retrieving revision 1.5 diff -u -r1.5 Makefile.in --- Makefile.in 2000/03/21 06:26:37 1.5 +++ Makefile.in 2000/11/17 05:20:37 @@ -40,7 +40,7 @@
SHELL= /bin/sh
-SCRIPTS= answer_majordomo_mail mailcmd mailowner post driver +SCRIPTS= answer_majordomo_mail mailcmd mailowner post driver auto
# Modes for directories and executables created by the install # process. Default to group-writable directories but -------------------- snip snip --------------------
The new auto script is the heart of the beast. Briefly what it does is look at the recipients list (To:, Cc:, Resent-To:, and Resent-Cc: headers) to see if it has a valid Mailman list destination. It gathers this from all the list objects on the system and should be virtual host aware.
Next it matches the recipients its found in the message against the list of possible valid Mailman destinations. If if finds no matches, it exits with EX_NOUSER. If it does find a match, it enqueues the message in a manner similar to the post, mailcmd, and mailowner scripts. qrunner would handle those enqueued messages without ever knowing the difference.
Here are some gotchas, which I believe can either be worked out or lived with:
Say I send a message to bogus@wooz.org. This message will travel through the auto script and I've verified that you get a user unknown bounce, but the bounce message says that mm+bogus@wooz.org is the bouncing address, not bogus@wooz.org, which is what I'd like to see.
On a system with a lot of lists, auto either should just a trampoline into a long running daemon, or it should try to cache more information. Trying to open and read every config.db file for every received message is probably way overkill.
I'm not sure that auto as it's currently written will handle cross-posting correctly, since enqueuing the message multiple times (say for list1@, list2@, and list3@) will still result in just one .db and .msg file for the received message. Shouldn't be too hard to craft a different sha hash for each separately.
This won't live very nicely with other $luser_relay's if you've got them. It would be nice if Postfix had a slightly more elaborate hookable framework here, where I could say: "let auto try to handle the address, but if it can't, pass it on to the next hook in the sequence."
The recipient_delimiter bit is probably extraneous.
So anyway, time for sleep. Have fun! If this can be fleshed out and completed, it can be added to 2.1.
-Barry
P.S. auto below requires Python 2.0. Taste of things to come. :)
-------------------- 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
syslog('auto', 'valids: %s' % valids)
# Get the message from standard input
msg = Message.Message(sys.stdin)
addrs = []
for header in ('to', 'cc', 'resent-to', 'resent-cc'):
addrs.extend(msg.getaddrlist(header))
syslog('auto', 'found these addresses: %s' % addrs)
# Parse the headers. Keys are 'post', 'request', 'owner'
destinations = {}
for name, addr in addrs:
localpart, hostname = addr.split('@', 1)
try:
listname, subdest = localpart.split('-', 1)
except ValueError:
listname = localpart
subdest = 'post'
if subdest in ('post', 'request', 'owner', 'admin') and \
valids.has_key(fqdn_listname(listname, hostname)):
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
# 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)
return 0
if __name__ == '__main__': code = main() sys.exit(code)

barry@digicool.com said:
The new auto script is the heart of the beast. Briefly what it does is look at the recipients list (To:, Cc:, Resent-To:, and Resent-Cc: headers) to see if it has a valid Mailman list destination. It gathers this from all the list objects on the system and should be virtual host aware.
Parsing out of headers could be rather interesting... what about a message copied to 2 lists - its not going to get replicated is it?
Can you just pass the target address one the command line to the auto script - makes life a *lot* easier.
Alternatively, all the exim stuff does is a file existence test on a transformed address - sure that ought to be relatively easy to postfix.
Nigel.
Nigel.

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)
participants (4)
-
barry@digicool.com
-
J C Lawrence
-
Nigel Metheringham
-
Owen Taylor