From 27e37577c61067fb9dec77a895238ee6d05d616e Mon Sep 17 00:00:00 2001 From: Philip Rosenberg-Watt Date: Mon, 3 Feb 2020 14:53:04 -0700 Subject: [PATCH 1/4] Add IPv6 to allow_nets Roundcube was not connecting to sieve with IPv6 enabled. Fixes #1336 --- core/admin/mailu/configuration.py | 1 + core/admin/mailu/internal/views/dovecot.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/core/admin/mailu/configuration.py b/core/admin/mailu/configuration.py index 7dcd7c3a..66b0b832 100644 --- a/core/admin/mailu/configuration.py +++ b/core/admin/mailu/configuration.py @@ -67,6 +67,7 @@ DEFAULT_CONFIG = { 'HOST_REDIS': 'redis', 'HOST_FRONT': 'front', 'SUBNET': '192.168.203.0/24', + 'SUBNET6': None, 'POD_ADDRESS_RANGE': None } diff --git a/core/admin/mailu/internal/views/dovecot.py b/core/admin/mailu/internal/views/dovecot.py index f44f59bc..9c665977 100644 --- a/core/admin/mailu/internal/views/dovecot.py +++ b/core/admin/mailu/internal/views/dovecot.py @@ -11,6 +11,8 @@ def dovecot_passdb_dict(user_email): user = models.User.query.get(user_email) or flask.abort(404) allow_nets = [] allow_nets.append(app.config["SUBNET"]) + if app.config["SUBNET6"]: + allow_nets.append(app.config["SUBNET6"]) if app.config["POD_ADDRESS_RANGE"]: allow_nets.append(app.config["POD_ADDRESS_RANGE"]) return flask.jsonify({ From ff1dfec39aa85df24a6f6e8bf74aec3337b88883 Mon Sep 17 00:00:00 2001 From: Philip Rosenberg-Watt Date: Sun, 9 Feb 2020 07:25:45 -0700 Subject: [PATCH 2/4] Add port to relay if it contains a colon This closes #1357 --- core/admin/mailu/internal/views/postfix.py | 6 +++++- towncrier/newsfragments/1357.feature | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 towncrier/newsfragments/1357.feature diff --git a/core/admin/mailu/internal/views/postfix.py b/core/admin/mailu/internal/views/postfix.py index 21a4aa91..0843b147 100644 --- a/core/admin/mailu/internal/views/postfix.py +++ b/core/admin/mailu/internal/views/postfix.py @@ -36,7 +36,11 @@ def postfix_transport(email): return flask.abort(404) localpart, domain_name = models.Email.resolve_domain(email) relay = models.Relay.query.get(domain_name) or flask.abort(404) - return flask.jsonify("smtp:[{}]".format(relay.smtp)) + ret = "smtp:[{0}]".format(relay.smtp) + if ":" in relay.smtp: + split = relay.smtp.split(':') + ret = "smtp:[{0}]:{1}".format(split[0], split[1]) + return flask.jsonify(ret) @internal.route("/postfix/sender/login/") diff --git a/towncrier/newsfragments/1357.feature b/towncrier/newsfragments/1357.feature new file mode 100644 index 00000000..56fa443f --- /dev/null +++ b/towncrier/newsfragments/1357.feature @@ -0,0 +1 @@ +Relay a domain to a nonstandard SMTP port by adding ":" to the remote hostname or IP address. \ No newline at end of file From 94cfc31e04f2ac2f408b6f37b9a394f0b0793de1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2020 15:33:41 +0000 Subject: [PATCH 3/4] Bump validators from 0.12.5 to 0.12.6 in /core/admin Bumps [validators](https://github.com/kvesteri/validators) from 0.12.5 to 0.12.6. - [Release notes](https://github.com/kvesteri/validators/releases) - [Changelog](https://github.com/kvesteri/validators/blob/master/CHANGES.rst) - [Commits](https://github.com/kvesteri/validators/commits) Signed-off-by: dependabot[bot] --- core/admin/requirements-prod.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/admin/requirements-prod.txt b/core/admin/requirements-prod.txt index 1fcffbcd..e04089c4 100644 --- a/core/admin/requirements-prod.txt +++ b/core/admin/requirements-prod.txt @@ -44,7 +44,7 @@ SQLAlchemy==1.3.3 srslib==0.1.4 tabulate==0.8.3 tenacity==5.0.4 -validators==0.12.5 +validators==0.12.6 visitor==0.1.3 Werkzeug==0.15.3 WTForms==2.2.1 From 313e98c1a2130f35c42554c8b1bc3bf3433903e5 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sun, 5 Jan 2020 14:00:00 +0100 Subject: [PATCH 4/4] fetchmail: print unhandled exceptions, but don't crash refs #1295 --- optional/fetchmail/fetchmail.py | 84 +++++++++++++++++---------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/optional/fetchmail/fetchmail.py b/optional/fetchmail/fetchmail.py index f3ee6a70..fb0c6f04 100755 --- a/optional/fetchmail/fetchmail.py +++ b/optional/fetchmail/fetchmail.py @@ -8,6 +8,7 @@ import subprocess import re import requests import sys +import traceback FETCHMAIL = """ @@ -45,47 +46,50 @@ def fetchmail(fetchmailrc): def run(debug): - fetches = requests.get("http://admin/internal/fetch").json() - smtphost, smtpport = extract_host_port(os.environ.get("HOST_SMTP", "smtp"), None) - if smtpport is None: - smtphostport = smtphost - else: - smtphostport = "%s/%d" % (smtphost, smtpport) - for fetch in fetches: - fetchmailrc = "" - options = "options antispam 501, 504, 550, 553, 554" - options += " sslmode wrapped" if fetch["tls"] else "" - options += " keep" if fetch["keep"] else " fetchall" - fetchmailrc += RC_LINE.format( - user_email=escape_rc_string(fetch["user_email"]), - protocol=fetch["protocol"], - host=escape_rc_string(fetch["host"]), - port=fetch["port"], - smtphost=smtphostport, - username=escape_rc_string(fetch["username"]), - password=escape_rc_string(fetch["password"]), - options=options - ) - if debug: - print(fetchmailrc) - try: - print(fetchmail(fetchmailrc)) - error_message = "" - except subprocess.CalledProcessError as error: - error_message = error.output.decode("utf8") - # No mail is not an error - if not error_message.startswith("fetchmail: No mail"): - print(error_message) - user_info = "for %s at %s" % (fetch["user_email"], fetch["host"]) - # Number of messages seen is not a error as well - if ("messages" in error_message and - "(seen " in error_message and - user_info in error_message): - print(error_message) - finally: - requests.post("http://admin/internal/fetch/{}".format(fetch["id"]), - json=error_message.split("\n")[0] + try: + fetches = requests.get("http://admin/internal/fetch").json() + smtphost, smtpport = extract_host_port(os.environ.get("HOST_SMTP", "smtp"), None) + if smtpport is None: + smtphostport = smtphost + else: + smtphostport = "%s/%d" % (smtphost, smtpport) + for fetch in fetches: + fetchmailrc = "" + options = "options antispam 501, 504, 550, 553, 554" + options += " sslmode wrapped" if fetch["tls"] else "" + options += " keep" if fetch["keep"] else " fetchall" + fetchmailrc += RC_LINE.format( + user_email=escape_rc_string(fetch["user_email"]), + protocol=fetch["protocol"], + host=escape_rc_string(fetch["host"]), + port=fetch["port"], + smtphost=smtphostport, + username=escape_rc_string(fetch["username"]), + password=escape_rc_string(fetch["password"]), + options=options ) + if debug: + print(fetchmailrc) + try: + print(fetchmail(fetchmailrc)) + error_message = "" + except subprocess.CalledProcessError as error: + error_message = error.output.decode("utf8") + # No mail is not an error + if not error_message.startswith("fetchmail: No mail"): + print(error_message) + user_info = "for %s at %s" % (fetch["user_email"], fetch["host"]) + # Number of messages seen is not a error as well + if ("messages" in error_message and + "(seen " in error_message and + user_info in error_message): + print(error_message) + finally: + requests.post("http://admin/internal/fetch/{}".format(fetch["id"]), + json=error_message.split("\n")[0] + ) + except Exception: + traceback.print_exc() if __name__ == "__main__":