summaryrefslogtreecommitdiff
path: root/src/mailman/mta
diff options
context:
space:
mode:
authorBarry Warsaw2017-05-23 18:23:32 +0000
committerBarry Warsaw2017-05-23 18:23:32 +0000
commit3dc9e4c7f2cbed2bbfac9b76fdc74ffdf564b208 (patch)
treed650c8dc5c24e8a2b13754d196beac891d543fd4 /src/mailman/mta
parenta7c563e9048d302c52558e6e2202fdfb49961843 (diff)
parent30a21e0aacd4fcf755816e31b031aec81f83c98e (diff)
downloadmailman-3dc9e4c7f2cbed2bbfac9b76fdc74ffdf564b208.tar.gz
mailman-3dc9e4c7f2cbed2bbfac9b76fdc74ffdf564b208.tar.zst
mailman-3dc9e4c7f2cbed2bbfac9b76fdc74ffdf564b208.zip
Merge branch 'issue-318' into 'master'
Add support for regex based postfix transport maps and relay_domains. Closes #318 See merge request !263
Diffstat (limited to 'src/mailman/mta')
-rw-r--r--src/mailman/mta/postfix.py49
-rw-r--r--src/mailman/mta/tests/test_aliases.py168
2 files changed, 155 insertions, 62 deletions
diff --git a/src/mailman/mta/postfix.py b/src/mailman/mta/postfix.py
index d819533a3..6e71d0651 100644
--- a/src/mailman/mta/postfix.py
+++ b/src/mailman/mta/postfix.py
@@ -56,6 +56,8 @@ class LMTP:
# Locate and read the Postfix specific configuration file.
mta_config = external_configuration(config.mta.configuration)
self.postmap_command = mta_config.get('postfix', 'postmap_command')
+ self.transport_file_type = mta_config.get(
+ 'postfix', 'transport_file_type')
def create(self, mlist):
"""See `IMailTransportAgentLifecycle`."""
@@ -84,19 +86,21 @@ class LMTP:
self._generate_domains_file(fp)
# Atomically rename to the intended path.
os.rename(domains_path_new, domains_path)
- # Now, run the postmap command on both newly generated files. If
- # one files, still try the other one.
- errors = []
- for path in (lmtp_path, domains_path):
- command = self.postmap_command + ' ' + 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)
- errors.append(msg % (command, status, errstr))
- if errors:
- raise RuntimeError(NL.join(errors))
+ # If the transport_file_type is 'hash' then run the postmap command
+ # on newly generated file to convert them in to hash table like
+ # Postfix wants.
+ if self.transport_file_type == 'hash':
+ errors = []
+ for path in (lmtp_path, domains_path):
+ command = self.postmap_command + ' ' + 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)
+ errors.append(msg % (command, status, errstr))
+ if errors:
+ raise RuntimeError(NL.join(errors))
def _generate_lmtp_file(self, fp):
# The format for Postfix's LMTP transport map is defined here:
@@ -125,12 +129,23 @@ class LMTP:
file=fp)
for mlist in sorted(by_domain[domain], key=sort_key):
aliases = list(utility.aliases(mlist))
- width = max(len(alias) for alias in aliases) + 3
- print(ALIASTMPL.format(aliases.pop(0), config, width), file=fp)
+ width = max(len(alias) for alias in aliases) + \
+ aliases[0].count('.') + 7
+ print(ALIASTMPL.format(self._decorate(aliases.pop(0)),
+ config, width), file=fp)
for alias in aliases:
- print(ALIASTMPL.format(alias, config, width), file=fp)
+ print(ALIASTMPL.format(self._decorate(alias),
+ config, width), file=fp)
print(file=fp)
+ def _decorate(self, name):
+ # Postfix regex tables need regex matching listname or domains. This
+ # method just decorates the name to be printed in the transport map
+ # file or relay domains file.
+ if self.transport_file_type == 'regex':
+ return '/^{}$/'.format(name).replace('.', '\.')
+ return name
+
def _generate_domains_file(self, fp):
# Uniquify the domains, then sort them alphabetically.
domains = set()
@@ -145,5 +160,5 @@ class LMTP:
# you're on your own.
""".format(now().replace(microsecond=0)), file=fp)
for domain in sorted(domains):
- print('{0} {0}'.format(domain), file=fp)
+ print('{} {}'.format(self._decorate(domain), domain), file=fp)
print(file=fp)
diff --git a/src/mailman/mta/tests/test_aliases.py b/src/mailman/mta/tests/test_aliases.py
index d5cea3ecb..b8090c86d 100644
--- a/src/mailman/mta/tests/test_aliases.py
+++ b/src/mailman/mta/tests/test_aliases.py
@@ -154,15 +154,15 @@ example.com example.com
contents = _strip_header(fp.read())
self.assertMultiLineEqual(contents, """\
# Aliases which are visible only in the @example.com domain.
-test@example.com lmtp:[127.0.0.1]:9024
-test-bounces@example.com lmtp:[127.0.0.1]:9024
-test-confirm@example.com lmtp:[127.0.0.1]:9024
-test-join@example.com lmtp:[127.0.0.1]:9024
-test-leave@example.com lmtp:[127.0.0.1]:9024
-test-owner@example.com lmtp:[127.0.0.1]:9024
-test-request@example.com lmtp:[127.0.0.1]:9024
-test-subscribe@example.com lmtp:[127.0.0.1]:9024
-test-unsubscribe@example.com lmtp:[127.0.0.1]:9024
+test@example.com lmtp:[127.0.0.1]:9024
+test-bounces@example.com lmtp:[127.0.0.1]:9024
+test-confirm@example.com lmtp:[127.0.0.1]:9024
+test-join@example.com lmtp:[127.0.0.1]:9024
+test-leave@example.com lmtp:[127.0.0.1]:9024
+test-owner@example.com lmtp:[127.0.0.1]:9024
+test-request@example.com lmtp:[127.0.0.1]:9024
+test-subscribe@example.com lmtp:[127.0.0.1]:9024
+test-unsubscribe@example.com lmtp:[127.0.0.1]:9024
""")
def test_two_lists(self):
@@ -185,25 +185,25 @@ example.com example.com
contents = _strip_header(fp.read())
self.assertMultiLineEqual(contents, """\
# Aliases which are visible only in the @example.com domain.
-other@example.com lmtp:[127.0.0.1]:9024
-other-bounces@example.com lmtp:[127.0.0.1]:9024
-other-confirm@example.com lmtp:[127.0.0.1]:9024
-other-join@example.com lmtp:[127.0.0.1]:9024
-other-leave@example.com lmtp:[127.0.0.1]:9024
-other-owner@example.com lmtp:[127.0.0.1]:9024
-other-request@example.com lmtp:[127.0.0.1]:9024
-other-subscribe@example.com lmtp:[127.0.0.1]:9024
-other-unsubscribe@example.com lmtp:[127.0.0.1]:9024
+other@example.com lmtp:[127.0.0.1]:9024
+other-bounces@example.com lmtp:[127.0.0.1]:9024
+other-confirm@example.com lmtp:[127.0.0.1]:9024
+other-join@example.com lmtp:[127.0.0.1]:9024
+other-leave@example.com lmtp:[127.0.0.1]:9024
+other-owner@example.com lmtp:[127.0.0.1]:9024
+other-request@example.com lmtp:[127.0.0.1]:9024
+other-subscribe@example.com lmtp:[127.0.0.1]:9024
+other-unsubscribe@example.com lmtp:[127.0.0.1]:9024
-test@example.com lmtp:[127.0.0.1]:9024
-test-bounces@example.com lmtp:[127.0.0.1]:9024
-test-confirm@example.com lmtp:[127.0.0.1]:9024
-test-join@example.com lmtp:[127.0.0.1]:9024
-test-leave@example.com lmtp:[127.0.0.1]:9024
-test-owner@example.com lmtp:[127.0.0.1]:9024
-test-request@example.com lmtp:[127.0.0.1]:9024
-test-subscribe@example.com lmtp:[127.0.0.1]:9024
-test-unsubscribe@example.com lmtp:[127.0.0.1]:9024
+test@example.com lmtp:[127.0.0.1]:9024
+test-bounces@example.com lmtp:[127.0.0.1]:9024
+test-confirm@example.com lmtp:[127.0.0.1]:9024
+test-join@example.com lmtp:[127.0.0.1]:9024
+test-leave@example.com lmtp:[127.0.0.1]:9024
+test-owner@example.com lmtp:[127.0.0.1]:9024
+test-request@example.com lmtp:[127.0.0.1]:9024
+test-subscribe@example.com lmtp:[127.0.0.1]:9024
+test-unsubscribe@example.com lmtp:[127.0.0.1]:9024
""")
def test_two_lists_two_domains(self):
@@ -229,24 +229,102 @@ example.net example.net
contents = _strip_header(fp.read())
self.assertMultiLineEqual(contents, """\
# Aliases which are visible only in the @example.com domain.
-test@example.com lmtp:[127.0.0.1]:9024
-test-bounces@example.com lmtp:[127.0.0.1]:9024
-test-confirm@example.com lmtp:[127.0.0.1]:9024
-test-join@example.com lmtp:[127.0.0.1]:9024
-test-leave@example.com lmtp:[127.0.0.1]:9024
-test-owner@example.com lmtp:[127.0.0.1]:9024
-test-request@example.com lmtp:[127.0.0.1]:9024
-test-subscribe@example.com lmtp:[127.0.0.1]:9024
-test-unsubscribe@example.com lmtp:[127.0.0.1]:9024
+test@example.com lmtp:[127.0.0.1]:9024
+test-bounces@example.com lmtp:[127.0.0.1]:9024
+test-confirm@example.com lmtp:[127.0.0.1]:9024
+test-join@example.com lmtp:[127.0.0.1]:9024
+test-leave@example.com lmtp:[127.0.0.1]:9024
+test-owner@example.com lmtp:[127.0.0.1]:9024
+test-request@example.com lmtp:[127.0.0.1]:9024
+test-subscribe@example.com lmtp:[127.0.0.1]:9024
+test-unsubscribe@example.com lmtp:[127.0.0.1]:9024
# Aliases which are visible only in the @example.net domain.
-other@example.net lmtp:[127.0.0.1]:9024
-other-bounces@example.net lmtp:[127.0.0.1]:9024
-other-confirm@example.net lmtp:[127.0.0.1]:9024
-other-join@example.net lmtp:[127.0.0.1]:9024
-other-leave@example.net lmtp:[127.0.0.1]:9024
-other-owner@example.net lmtp:[127.0.0.1]:9024
-other-request@example.net lmtp:[127.0.0.1]:9024
-other-subscribe@example.net lmtp:[127.0.0.1]:9024
-other-unsubscribe@example.net lmtp:[127.0.0.1]:9024
+other@example.net lmtp:[127.0.0.1]:9024
+other-bounces@example.net lmtp:[127.0.0.1]:9024
+other-confirm@example.net lmtp:[127.0.0.1]:9024
+other-join@example.net lmtp:[127.0.0.1]:9024
+other-leave@example.net lmtp:[127.0.0.1]:9024
+other-owner@example.net lmtp:[127.0.0.1]:9024
+other-request@example.net lmtp:[127.0.0.1]:9024
+other-subscribe@example.net lmtp:[127.0.0.1]:9024
+other-unsubscribe@example.net lmtp:[127.0.0.1]:9024
+""")
+
+ def test_missing_postmap_command_raises_runtime_errorr(self):
+ # Changing the postmap command to false will always
+ # return a non-zero exit code.
+ self.postfix.postmap_command = 'false'
+ # Generating postmap hash files will raise a runtimerror.
+ with self.assertRaises(RuntimeError):
+ self.postfix.regenerate(self.tempdir)
+ # Now change the command back to true will make the
+ # command run normally.
+ self.postfix.postmap_command = 'true'
+ self.postfix.regenerate(self.tempdir)
+ # There should be two files in the tempdir.
+ self.assertEqual(sorted(os.listdir(self.tempdir)),
+ ['postfix_domains', 'postfix_lmtp'])
+
+ def test_aliases_regex(self):
+ # Test aliases generation for regex maps for postfix.
+ # Set the transport map type to regex.
+ self.postfix.transport_file_type = 'regex'
+ self.postfix.regenerate(self.tempdir)
+ # The domains file just contains the example.com domain.
+ with open(os.path.join(self.tempdir, 'postfix_domains')) as fp:
+ contents = _strip_header(fp.read())
+ self.assertMultiLineEqual(contents, """\
+/^example\.com$/ example.com
+""")
+
+ # the lmtp file contains transport mapping to the lmtp server.
+ with open(os.path.join(self.tempdir, 'postfix_lmtp')) as fp:
+ contents = _strip_header(fp.read())
+ self.assertMultiLineEqual(contents, """\
+# Aliases which are visible only in the @example.com domain.
+/^test@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-bounces@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-confirm@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-join@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-leave@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-owner@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-request@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-subscribe@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-unsubscribe@example\.com$/ lmtp:[127.0.0.1]:9024
+""")
+
+ def test_aliases_regex_with_dots(self):
+ # Test regex is generated for listnames with multiple dots.
+ self.postfix.transport_file_type = 'regex'
+ create_list('test.list.name.dots@example.com')
+ self.postfix.regenerate(self.tempdir)
+ with open(os.path.join(self.tempdir, 'postfix_domains')) as fp:
+ contents = _strip_header(fp.read())
+ self.assertMultiLineEqual(contents, """\
+/^example\.com$/ example.com
+""")
+ with open(os.path.join(self.tempdir, 'postfix_lmtp')) as fp:
+ contents = _strip_header(fp.read())
+ self.assertMultiLineEqual(contents, """\
+# Aliases which are visible only in the @example.com domain.
+/^test@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-bounces@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-confirm@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-join@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-leave@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-owner@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-request@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-subscribe@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test-unsubscribe@example\.com$/ lmtp:[127.0.0.1]:9024
+
+/^test\.list\.name\.dots@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test\.list\.name\.dots-bounces@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test\.list\.name\.dots-confirm@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test\.list\.name\.dots-join@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test\.list\.name\.dots-leave@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test\.list\.name\.dots-owner@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test\.list\.name\.dots-request@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test\.list\.name\.dots-subscribe@example\.com$/ lmtp:[127.0.0.1]:9024
+/^test\.list\.name\.dots-unsubscribe@example\.com$/ lmtp:[127.0.0.1]:9024
""")