From 120e59f6d1e9258f8482986a7659d422175c6d4b Mon Sep 17 00:00:00 2001 From: Jimmy Bergman Date: Mon, 13 Aug 2012 15:52:28 +0200 Subject: Write a domain map that postfix can use as relay_domains automatically on list creation/removal --- src/mailman/docs/MTA.rst | 11 ++++----- src/mailman/mta/postfix.py | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/mailman/docs/MTA.rst b/src/mailman/docs/MTA.rst index c6d2230c4..04bfc10e1 100644 --- a/src/mailman/docs/MTA.rst +++ b/src/mailman/docs/MTA.rst @@ -102,17 +102,14 @@ file:: hash:/path-to-mailman/var/data/postfix_lmtp local_recipient_maps = hash:/path-to-mailman/var/data/postfix_lmtp + relay_domains = + hash:/path-to-mailman/var/data/postfix_domains where `path-to-mailman` is replaced with the actual path that you're running Mailman from. Setting `local_recipient_maps` as well as `transport_maps` allows Postfix to properly reject all messages destined for non-existent local -users. - - -Virtual domains ---------------- - -TBD: figure out how virtual domains interact with the transport maps. +users. Setting `relay_domains` means postfix will start to accept mails for +newly added domains even if they are not part of `mydestination`. Sendmail diff --git a/src/mailman/mta/postfix.py b/src/mailman/mta/postfix.py index c04e38f02..4fc097ffc 100644 --- a/src/mailman/mta/postfix.py +++ b/src/mailman/mta/postfix.py @@ -64,6 +64,7 @@ class LMTP: # We can ignore the mlist argument because for LMTP delivery, we just # generate the entire file every time. self.regenerate() + self.regenerate_domain() delete = create @@ -107,6 +108,46 @@ class LMTP: log.error(msg, command, status, errstr) raise RuntimeError(msg % (command, status, errstr)) + def regenerate_domain(self, output=None): + """The map for all list domains + + The format for Postfix's LMTP transport map is defined here: + http://www.postfix.org/transport.5.html + """ + # Acquire a lock file to prevent other processes from racing us here. + lock_file = os.path.join(config.LOCK_DIR, 'mta') + with Lock(lock_file): + # If output is a filename, open up a backing file and write the + # output there, then do the atomic rename dance. First though, if + # it's None, we use a calculated path. + if output is None: + path = os.path.join(config.DATA_DIR, 'postfix_domains') + path_new = path + '.new' + elif isinstance(output, basestring): + path = output + path_new = output + '.new' + else: + path = path_new = None + if path_new is None: + self._do_write_file_domains(output) + # There's nothing to rename, and we can't generate the .db + # file, so we're done. + return + # Write the file. + with open(path_new, 'w') as fp: + self._do_write_file_domains(fp) + # Atomically rename to the intended path. + os.rename(path + '.new', path) + # Now that the new file is in place, we must tell Postfix to + # generate a new .db file. + command = config.mta.postfix_map_cmd + ' ' + path + status = (os.system(command) >> 8) & 0xff + if status: + msg = 'command failure: %s, %s, %s' + errstr = os.strerror(status) + log.error(msg, command, status, errstr) + raise RuntimeError(msg % (command, status, errstr)) + def _do_write_file(self, fp): """Do the actual file writes for list creation.""" # Sort all existing mailing list names first by domain, then by local @@ -137,3 +178,22 @@ class LMTP: for alias in aliases: print(ALIASTMPL.format(alias, config, width), file=fp) print(file=fp) + + def _do_write_file_domains(self, fp): + """Do the actual file writes of the domain map for list creation.""" + # Sort all existing mailing list names first by domain, then my local + # part. For postfix we need a dummy entry for the domain. + by_domain = [] + for list_name, mail_host in getUtility(IListManager).name_components: + by_domain.append(mail_host) + print("""\ +# AUTOMATICALLY GENERATED BY MAILMAN ON {0} +# +# This file is generated by Mailman, and is kept in sync with the binary hash +# file. 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. +""".format(now().replace(microsecond=0)), file=fp) + for domain in sorted(by_domain): + print("""{0} {0}""".format(domain), file=fp) + -- cgit v1.3.1 From 8271738ba287c4688173ff760118996c1590b84f Mon Sep 17 00:00:00 2001 From: Jimmy Bergman Date: Thu, 20 Sep 2012 10:08:53 +0200 Subject: Add list_id to the REST API list representation --- src/mailman/rest/docs/lists.rst | 3 +++ src/mailman/rest/lists.py | 1 + 2 files changed, 4 insertions(+) diff --git a/src/mailman/rest/docs/lists.rst b/src/mailman/rest/docs/lists.rst index 610244968..7f0abeb26 100644 --- a/src/mailman/rest/docs/lists.rst +++ b/src/mailman/rest/docs/lists.rst @@ -23,6 +23,7 @@ Create a mailing list in a domain and it's accessible via the API. display_name: Test-one fqdn_listname: test-one@example.com http_etag: "..." + list_id: test-one.example.com list_name: test-one mail_host: example.com member_count: 0 @@ -40,6 +41,7 @@ You can also query for lists from a particular domain. display_name: Test-one fqdn_listname: test-one@example.com http_etag: "..." + list_id: test-one.example.com list_name: test-one mail_host: example.com member_count: 0 @@ -89,6 +91,7 @@ It is also available via the location given in the response. display_name: Test-two fqdn_listname: test-two@example.com http_etag: "..." + list_id: test-two.example.com list_name: test-two mail_host: example.com member_count: 0 diff --git a/src/mailman/rest/lists.py b/src/mailman/rest/lists.py index f25133211..a45fa94a7 100644 --- a/src/mailman/rest/lists.py +++ b/src/mailman/rest/lists.py @@ -107,6 +107,7 @@ class _ListBase(resource.Resource, CollectionMixin): return dict( display_name=mlist.display_name, fqdn_listname=mlist.fqdn_listname, + list_id=mlist.list_id, list_name=mlist.list_name, mail_host=mlist.mail_host, member_count=mlist.members.member_count, -- cgit v1.3.1