aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md8
-rw-r--r--app.py11
-rw-r--r--email_client.py104
3 files changed, 123 insertions, 0 deletions
diff --git a/README.md b/README.md
index 9f8f582..96d6683 100644
--- a/README.md
+++ b/README.md
@@ -32,6 +32,14 @@ You can also run the app without containerization:
| DB_PORT | Postgres port (default: 5432) |
| DB_DATABASE | Postgres database (default: postgres) |
| DB_USER | Postgres user (default: postgres) |
+| EMAIL_HOST | SMTP host address |
+| EMAIL_PORT | SMTP port |
+| EMAIL_HOST_USER | SMTP host user |
+| EMAIL_HOST_PASSWORD | SMTP host password |
+| EMAIL_USE_TLS | Use TLS with SMTP? |
+| EMAIL_MESSAGE_FROM | Email message from header |
+
+`EMAIL_` variables are only required if at least one of them is defined.
## Screenshots
diff --git a/app.py b/app.py
index 4c9b9f7..ca06e37 100644
--- a/app.py
+++ b/app.py
@@ -2,11 +2,17 @@ from dotenv import load_dotenv
load_dotenv()
import datetime
+import sys
+import os
+import traceback
from dataclasses import dataclass
from flask import Flask, render_template, redirect, request, make_response
app = Flask(__name__)
import db
+import email_client
+
+BASE_URL = os.environ["BASE_URL"]
@dataclass
class ChoicesByVoter:
@@ -65,6 +71,9 @@ def create():
form["author_email"],
choices,
)
+
+ email_client.send_poll_created_email_if_enabled(poll_id=poll.id)
+
resp = make_response(
redirect(f"/manage/{poll.manage_code}")
)
@@ -123,6 +132,8 @@ def vote_poll(id):
db.vote_poll(id, voter_name, choice_ids)
+ email_client.send_participation_email_if_enabled(poll_id=id, voter_name=voter_name)
+
return redirect(f"/poll/{id}")
@app.post("/manage/<code>/update_info")
diff --git a/email_client.py b/email_client.py
new file mode 100644
index 0000000..0f0802f
--- /dev/null
+++ b/email_client.py
@@ -0,0 +1,104 @@
+import os
+import sys
+import traceback
+import smtplib
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+
+import db
+
+BASE_URL = os.environ["BASE_URL"]
+
+def send_email(subject: str, body: str, recipient: str):
+ pass
+
+email_env_vars = [
+ "EMAIL_HOST",
+ "EMAIL_PORT",
+ "EMAIL_HOST_USER",
+ "EMAIL_HOST_PASSWORD",
+ "EMAIL_USE_TLS",
+ "EMAIL_MESSAGE_FROM",
+]
+
+email_enabled = any(var in os.environ for var in email_env_vars)
+if email_enabled:
+ for var in email_env_vars:
+ if var not in os.environ:
+ raise Exception(f"Some EMAIL_ variables are set but {var} is not set")
+
+ email_host = os.environ["EMAIL_HOST"]
+ email_port = int(os.environ["EMAIL_PORT"])
+ email_host_user = os.environ["EMAIL_HOST_USER"]
+ email_host_password = os.environ["EMAIL_HOST_PASSWORD"]
+ email_use_tls = os.environ["EMAIL_USE_TLS"].lower() in ["true", "1", "yes"]
+ email_message_from = os.environ["EMAIL_MESSAGE_FROM"]
+
+ print(f"SMTP email client enabled using email host {email_host}")
+
+ def _actual_send_email(subject: str, body: str, recipient: str):
+ if not email_enabled:
+ return
+
+ print("debug: subject:", subject)
+ print("debug: body:", body)
+ print("debug: recipient:", recipient)
+ print("debug: email_host:", email_host)
+ print("debug: email_port:", email_port)
+ print("debug: email_host_user:", email_host_user)
+ print("debug: email_host_password:", email_host_password)
+ print("debug: email_use_tls:", email_use_tls)
+ print("debug: email_message_from:", email_message_from)
+
+ msg = MIMEMultipart()
+ msg['From'] = email_host_user
+ msg['To'] = recipient
+ msg['Subject'] = subject
+ msg.attach(MIMEText(body, 'plain'))
+
+ with smtplib.SMTP(email_host, email_port) as server:
+ if email_use_tls:
+ server.starttls()
+
+ server.login(email_host_user, email_host_password)
+ server.send_message(msg)
+
+ send_email = _actual_send_email
+else:
+ print("SMTP email client not enabled")
+
+def send_participation_email_if_enabled(poll_id: str, voter_name: str):
+ if email_enabled:
+ poll = db.get_poll(poll_id)
+ if not poll or poll.author_email is None:
+ return
+
+ try:
+ send_email(
+ subject=f"{voter_name} participated in your poll \"{poll.title}\"",
+ body=f"{voter_name} participated in your diddle \"{poll.title}\".\n\n"
+ f"View the results at {BASE_URL}/poll/{poll.id}\n"
+ f"Manage your diddle at {BASE_URL}/manage/{poll.manage_code}\n"
+ "You will be notified by email when someone participates.",
+ recipient=poll.author_email,
+ )
+ except Exception as e:
+ traceback.print_exc(file=sys.stderr)
+ print(f"Failed to send participation email to {poll.author_email}", file=sys.stderr)
+
+def send_poll_created_email_if_enabled(poll_id: str):
+ if email_enabled:
+ poll = db.get_poll(poll_id)
+ if not poll or poll.author_email is None:
+ return
+
+ try:
+ send_email(
+ subject=f"You created a new diddle \"{poll.title}\"",
+ body=f"Manage your diddle at {BASE_URL}/manage/{poll.manage_code}\n"
+ "You will be notified by email when someone participates.",
+ recipient=poll.author_email,
+ )
+ except Exception as e:
+ traceback.print_exc(file=sys.stderr)
+ print(f"Failed to send poll created email to {poll.author_email}", file=sys.stderr) \ No newline at end of file