diff --git a/atst/app.py b/atst/app.py index 884d2bee..c8795f61 100644 --- a/atst/app.py +++ b/atst/app.py @@ -22,6 +22,7 @@ from atst.domain.authz import Authorization from atst.models.permissions import Permissions from atst.eda_client import MockEDAClient from atst.uploader import Uploader +from atst.utils.mailer import make_mailer ENV = os.getenv("FLASK_ENV", "dev") @@ -47,6 +48,7 @@ def make_app(config): register_filters(app) make_eda_client(app) make_upload_storage(app) + make_mailer(app) db.init_app(app) csrf.init_app(app) diff --git a/atst/routes/dev.py b/atst/routes/dev.py index e9b107e8..a087d061 100644 --- a/atst/routes/dev.py +++ b/atst/routes/dev.py @@ -1,4 +1,12 @@ -from flask import Blueprint, request, session, redirect +from flask import ( + Blueprint, + request, + session, + redirect, + render_template, + url_for, + current_app as app, +) from . import redirect_after_login_url from atst.domain.users import Users @@ -65,3 +73,17 @@ def login_dev(): session["user_id"] = user.id return redirect(redirect_after_login_url()) + + +@bp.route("/test-email") +def test_email(): + app.mailer.send( + [request.args.get("to")], request.args.get("subject"), request.args.get("body") + ) + + return redirect(url_for("dev.messages")) + + +@bp.route("/messages") +def messages(): + return render_template("dev/emails.html", messages=app.mailer.messages) diff --git a/atst/utils.py b/atst/utils/__init__.py similarity index 100% rename from atst/utils.py rename to atst/utils/__init__.py diff --git a/atst/utils/mailer.py b/atst/utils/mailer.py new file mode 100644 index 00000000..32918bfa --- /dev/null +++ b/atst/utils/mailer.py @@ -0,0 +1,77 @@ +import smtplib +from email.message import EmailMessage +from collections import deque + + +class _HostConnection: + def __init__(self, server, port, username, password, use_tls=False): + self.server = server + self.port = port + self.username = username + self.password = password + self.use_tls = use_tls + self.host = None + + def __enter__(self): + self.host = smtplib.SMTP_SSL(self.server, self.port) + if self.use_tls: + self.host.starttls() + self.host.login(self.username, self.password) + + return self.host + + def __exit__(self, *args): + if self.host: + self.host.quit() + + +class Mailer: + def __init__( + self, server, port, sender, username, password, use_tls=False, debug=False + ): + self.server = server + self.port = port + self.sender = sender + self.username = username + self.password = password + self.use_tls = use_tls + self.debug = debug + self.messages = deque(maxlen=50) + + def connection(self): + return _HostConnection(self.server, self.port, self.username, self.password) + + def _message(self, recipients, subject, body): + msg = EmailMessage() + msg.set_content(body) + msg["From"] = self.sender + msg["To"] = ", ".join(recipients) + msg["Subject"] = subject + + return msg + + def send(self, recipients, subject, body): + message = self._message(recipients, subject, body) + if self.debug: + self.messages.appendleft(message) + else: + with self.connection() as conn: + conn.send_message(message) + + +def _map_config(config): + return { + "server": config.get("MAIL_SERVER"), + "port": config.get("MAIL_PORT"), + "sender": config.get("MAIL_SENDER"), + "username": config.get("MAIL_USERNAME"), + "password": config.get("MAIL_PASSWORD"), + "use_tls": config.get("MAIL_TLS", False), + "debug": config.get("DEBUG", False), + } + + +def make_mailer(app): + config = _map_config(app.config) + mailer = Mailer(**config) + app.mailer = mailer diff --git a/templates/dev/emails.html b/templates/dev/emails.html new file mode 100644 index 00000000..b07f6b46 --- /dev/null +++ b/templates/dev/emails.html @@ -0,0 +1,6 @@ +{% for msg in messages %} +
+{{ msg }} +
+
+{% endfor %}