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__":