Florian Wagner has proposed merging lp:~wagnerflo/mailman/2.1-postfix-transport
into lp:mailman/2.1.
Requested reviews:
Mailman Coders (mailman-coders)
This branch extends the Postfix handling in Mailman to generate additional maps
for a different handling of virtual hosts then the one already included:
- virtual-transport is a transport map (as in
http://www.postfix.org/transport.5.html) for use with the transport_maps
configuration parameter. It can be used to overwrite the transport Postfix uses
to deliver mail intended for a Mailman mailinglist. All list addresses known to
the Postfix installation are included as keys. The value is set to the contents
of a new POSTFIX_VIRTUAL_TRANSPORT configuration parameter ("mailman" by
default).
- virtual-id is a virtual alias map (as in
http://www.postfix.org/virtual.5.html) for use with the virtual_alias_maps
parameter. It is a identity mapping for all list addresses known to the Mailman
installation. It can be used to make these addresses known to Postfix (for
mails not to be rejected by reject_unauth_destination in
smtpd_recipient_restrictions for example).
An implementation of the transport that passes mail to Mailman is also included
as contrib/postfix-transport.py. It is a cleaned-up version of
postfix-to-mailman.py from the Debian Mailman package and available on the net.
The setup has been running for a low volume mailinglist for a few weeks.
--
https://code.launchpad.net/~wagnerflo/mailman/2.1-postfix-transport/+merge/7901
Your team Mailman Checkins is subscribed to branch lp:mailman/2.1.
=== modified file 'Mailman/Defaults.py.in'
--- Mailman/Defaults.py.in 2008-12-23 01:24:44 +0000
+++ Mailman/Defaults.py.in 2009-06-05 20:52:57 +0000
@@ -403,6 +403,11 @@
POSTFIX_ALIAS_CMD = '/usr/sbin/postalias'
POSTFIX_MAP_CMD = '/usr/sbin/postmap'
+# Tells genaliases what to put into the generated virtual-transport
+# table. This is supposed to be one of the delivery transports defined
+# in the postfix master.cf.
+POSTFIX_VIRTUAL_TRANSPORT = 'mailman'
+
# Ceiling on the number of recipients that can be specified in a single SMTP
# transaction. Set to 0 to submit the entire recipient list in one
# transaction. Only used with the SMTPDirect DELIVERY_MODULE.
=== modified file 'Mailman/MTA/Postfix.py'
--- Mailman/MTA/Postfix.py 2008-08-22 22:21:26 +0000
+++ Mailman/MTA/Postfix.py 2009-06-05 21:06:16 +0000
@@ -34,6 +34,8 @@
LOCKFILE = os.path.join(mm_cfg.LOCK_DIR, 'creator')
ALIASFILE = os.path.join(mm_cfg.DATA_DIR, 'aliases')
VIRTFILE = os.path.join(mm_cfg.DATA_DIR, 'virtual-mailman')
+VIRTTRFILE = os.path.join(mm_cfg.DATA_DIR, 'virtual-transport')
+VIRTIDFILE = os.path.join(mm_cfg.DATA_DIR, 'virtual-id')
try:
True, False
@@ -51,13 +53,14 @@
errstr = os.strerror(status)
syslog('error', msg, acmd, status, errstr)
raise RuntimeError, msg % (acmd, status, errstr)
- if os.path.exists(VIRTFILE):
- vcmd = mm_cfg.POSTFIX_MAP_CMD + ' ' + VIRTFILE
- status = (os.system(vcmd) >> 8) & 0xff
- if status:
- errstr = os.strerror(status)
- syslog('error', msg, vcmd, status, errstr)
- raise RuntimeError, msg % (vcmd, status, errstr)
+ for mapfile in VIRTFILE, VIRTTRFILE, VIRTIDFILE:
+ if os.path.exists(mapfile):
+ vcmd = mm_cfg.POSTFIX_MAP_CMD + ' ' + mapfile
+ status = (os.system(vcmd) >> 8) & 0xff
+ if status:
+ errstr = os.strerror(status)
+ syslog('error', msg, vcmd, status, errstr)
+ raise RuntimeError, msg % (vcmd, status, errstr)
@@ -76,6 +79,8 @@
def clear():
_zapfile(ALIASFILE)
_zapfile(VIRTFILE)
+ _zapfile(VIRTTRFILE)
+ _zapfile(VIRTIDFILE)
@@ -116,20 +121,16 @@
-def _addvirtual(mlist, fp):
+def _addmap(mlist, fp, loopfunc, itemfunc):
listname = mlist.internal_name()
fieldsz = len(listname) + len('-unsubscribe')
- hostname = mlist.host_name
- # Set up the mailman-loop address
- loopaddr = Utils.get_site_email(mlist.host_name, extra='loop')
- loopdest = Utils.ParseEmail(loopaddr)[0]
# Seek to the end of the text file, but if it's empty write the standard
# disclaimer, and the loop catch address.
fp.seek(0, 2)
if not fp.tell():
print >> fp, """\
# This file is generated by Mailman, and is kept in sync with the binary hash
-# file virtual-mailman.db. YOU SHOULD NOT MANUALLY EDIT THIS FILE unless you
+# file <name-of-file>.db. YOU SHOULD NOT MANUALLY EDIT THIS FILE unless you
# know what you're doing, and can keep the two files properly in sync. If you
# screw it up, you're on your own.
#
@@ -139,25 +140,73 @@
# LOOP ADDRESSES START
%s\t%s
# LOOP ADDRESSES END
-""" % (loopaddr, loopdest)
+""" % loopfunc(mlist)
# The text file entries get a little extra info
print >> fp, '# STANZA START:', listname
print >> fp, '# CREATED:', time.ctime(time.time())
# Now add all the standard alias entries
for k, v in makealiases(listname):
- fqdnaddr = '%...@%s' % (k, hostname)
+ first,second = itemfunc(mlist, k, v)
# Format the text file nicely
- print >> fp, fqdnaddr, ((fieldsz - len(k)) * ' '), k
+ print >> fp, first, ((fieldsz - len(k)) * ' '), second
# Finish the text file stanza
print >> fp, '# STANZA END:', listname
print >> fp
+
+def _addvirtual_loop(mlist):
+ # Set up the mailman-loop address
+ loopaddr = Utils.get_site_email(mlist.host_name, extra='loop')
+ loopdest = Utils.ParseEmail(loopaddr)[0]
+ return (loopaddr, loopdest)
+
+
+def _addvirtual_item(mlist, k, v):
+ return ('%...@%s' % (k, mlist.host_name), k)
+
+
+def _addvirtual(mlist, fp):
+ return _addmap(mlist, fp, _addvirtual_loop, _addvirtual_item)
+
+
+def _addvirtualtransport_loop(mlist):
+ # Set up the mailman-loop address
+ loopaddr = Utils.get_site_email(mlist.host_name, extra='loop')
+ return (loopaddr, mm_cfg.POSTFIX_VIRTUAL_TRANSPORT)
+
+
+def _addvirtualtransport_item(mlist, k, v):
+ return ('%...@%s' % (k, mlist.host_name),
+ mm_cfg.POSTFIX_VIRTUAL_TRANSPORT)
+
+
+def _addvirtualtransport(mlist, fp):
+ return _addmap(mlist, fp,
+ _addvirtualtransport_loop,
+ _addvirtualtransport_item)
+
+
+def _addvirtualid_loop(mlist):
+ # Set up the mailman-loop address
+ loopaddr = Utils.get_site_email(mlist.host_name, extra='loop')
+ print loopaddr
+ return (loopaddr, loopaddr)
+
+
+def _addvirtualid_item(mlist, k, v):
+ fqaddr = '%...@%s' % (k, mlist.host_name)
+ return (fqaddr, fqaddr)
+
+
+def _addvirtualid(mlist, fp):
+ return _addmap(mlist, fp,
+ _addvirtualid_loop,
+ _addvirtualid_item)
# Blech.
-def _check_for_virtual_loopaddr(mlist, filename):
- loopaddr = Utils.get_site_email(mlist.host_name, extra='loop')
- loopdest = Utils.ParseEmail(loopaddr)[0]
+def _check_for_virtual_loop(mlist, filename, loopfunc):
+ loopaddr,loopdest = loopfunc(mlist)
infp = open(filename)
omask = os.umask(007)
try:
@@ -196,6 +245,17 @@
outfp.close()
os.rename(filename + '.tmp', filename)
+
+def _check_for_virtual_loopaddr(mlist, filename):
+ _check_for_virtual_loop(mlist, filename, _addvirtual_loop)
+
+
+def _check_for_virtualtransport_loopaddr(mlist, filename):
+ _check_for_virtual_loop(mlist, filename, _addvirtualtransport_loop)
+
+
+def _check_for_virtualid_loopaddr(mlist, filename):
+ _check_for_virtual_loop(mlist, filename, _addvirtualid_loop)
def _do_create(mlist, textfile, func):
@@ -216,6 +276,10 @@
# Now double check the virtual plain text file
if func is _addvirtual:
_check_for_virtual_loopaddr(mlist, textfile)
+ elif func is _addvirtualtransport:
+ _check_for_virtualtransport_loopaddr(mlist, textfile)
+ elif func is _addvirtualid:
+ _check_for_virtualid_loopaddr(mlist, textfile)
def create(mlist, cgi=False, nolock=False, quiet=False):
@@ -229,6 +293,8 @@
_do_create(mlist, ALIASFILE, _addlist)
if mlist and mlist.host_name in mm_cfg.POSTFIX_STYLE_VIRTUAL_DOMAINS:
_do_create(mlist, VIRTFILE, _addvirtual)
+ _do_create(mlist, VIRTTRFILE, _addvirtualtransport)
+ _do_create(mlist, VIRTIDFILE, _addvirtualid)
_update_maps()
finally:
if lock:
@@ -297,6 +363,8 @@
_do_remove(mlist, ALIASFILE, False)
if mlist.host_name in mm_cfg.POSTFIX_STYLE_VIRTUAL_DOMAINS:
_do_remove(mlist, VIRTFILE, True)
+ _do_remove(mlist, VIRTTRFILE, True)
+ _do_remove(mlist, VIRTIDFILE, True)
# Regenerate the alias and map files
_update_maps()
finally:
@@ -306,7 +374,7 @@
def checkperms(state):
targetmode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
- for file in ALIASFILE, VIRTFILE:
+ for file in ALIASFILE, VIRTFILE, VIRTTRFILE, VIRTIDFILE:
if state.VERBOSE:
print _('checking permissions on %(file)s')
stat = None
=== added file 'contrib/postfix-transport.py'
--- contrib/postfix-transport.py 1970-01-01 00:00:00 +0000
+++ contrib/postfix-transport.py 2009-06-10 12:42:31 +0000
@@ -0,0 +1,101 @@
+#! @PYTHON@
+
+# postfix-transport.py
+#
+# Interface mailman to a postfix with a mailman transport.
+#
+# based on postfix-to-mailman.py from Debian package by
+# Dax Kelson <[email protected]>,
+# Simen E. Sandberg <[email protected]>,
+# Henrique de Moraes Holschuh <[email protected]> and
+# Siggy Brentrup <[email protected]>
+#
+# and on qmail-to-mailman.py by
+# Bruce Perens <[email protected]>
+#
+# by
+# Florian Wagner <[email protected]>
+#
+#
+# This is free software under the GNU General Public License.
+#
+# This scripts implements a postfix transport intended to be used by
+# the postfix pipe delivery system. It expects a single commandline
+# parameter being the mailinglist name and suffix (listname,
+# listname-admin, listname-bounces, ...) and the mail to be passed
+# in on stdin.
+#
+# It requires postfix to be configured with a custom transport map
+# for mailing list destination addresses.
+#
+
+import os
+import sys
+
+# Exit codes accepted by postfix
+# from postfix-2.0.16/src/global/sys_exits.h
+#
+EX_USAGE = 64 # command line usage error
+EX_NOUSER = 67 # addressee unknown
+EX_SOFTWARE = 70 # internal software error
+
+
+def main():
+ # handle mailing lists at non-interactive priority
+ os.nice(5)
+
+ import re
+ import os.path as path
+
+ sys.path.append(path.join('@prefix@', 'bin'))
+
+ import paths
+ import Mailman.Utils
+ import Mailman.mm_cfg
+
+ if len(sys.argv) != 2:
+ sys.stderr.write('Illegal invocation: %s\n' % ' '.join(sys.argv))
+ sys.stderr.write('Did you forget to set '
+ 'mailman_destination_recipient_limit=1 '
+ 'in main.cf?\n')
+ return EX_USAGE
+
+ local = sys.argv[1].lower()
+ mlist = local
+ func = 'post'
+
+ for action in ('admin', 'bounces', 'confirm', 'join', 'leave', 'owner',
+ 'request', 'subscribe', 'unsubscribe', 'loop'):
+ if not local.endswith('-' + action):
+ continue
+
+ func = action
+ mlist = local[:-len(action)-1]
+ break
+
+ if func == 'loop':
+ cmd = Mailman.mm_cfg.SENDMAIL_CMD
+ os.execv(cmd, (cmd, 'postmaster'))
+ errno = os.errno
+
+ elif Mailman.Utils.list_exists(mlist):
+ cmd = path.join(paths.prefix, 'mail', 'mailman')
+ os.execv(cmd, (cmd, func, mlist))
+ errno = os.errno
+
+ else:
+ sys.stderr.write('Mail to invalid mailing list \'%s\'.\n' % mlist)
+ return EX_NOUSER
+
+ sys.stderr.write('execv error: %s.\n' % os.strerror(errno))
+ return EX_SOFTWARE
+
+
+if __name__ == '__main__':
+ try:
+ os._exit(main())
+
+ except:
+ import traceback
+ sys.stderr.write(traceback.format_exc())
+ os._exit(EX_SOFTWARE)
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe:
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org