Update settings/admin UI and misc fixes
This commit is contained in:
@@ -3,8 +3,17 @@ import smtplib
|
||||
from email.message import EmailMessage
|
||||
|
||||
|
||||
def _truthy(v: str | None) -> bool:
|
||||
if v is None:
|
||||
return False
|
||||
return v.strip().lower() in ("1", "true", "yes", "on")
|
||||
|
||||
|
||||
def send_email(*, to_email: str, subject: str, body_text: str):
|
||||
"""Send a plain-text email using SMTP settings from environment variables.
|
||||
"""Send a plain-text email using SMTP settings from:
|
||||
|
||||
1) Environment variables (highest priority)
|
||||
2) Admin-configured settings stored in the database (AppSettings)
|
||||
|
||||
Required env vars:
|
||||
- SMTP_HOST
|
||||
@@ -19,14 +28,46 @@ def send_email(*, to_email: str, subject: str, body_text: str):
|
||||
- SMTP_DEBUG (default: "0") - set to 1 to print SMTP conversation to console
|
||||
"""
|
||||
|
||||
host = os.environ.get("SMTP_HOST")
|
||||
port = int(os.environ.get("SMTP_PORT", "587"))
|
||||
username = os.environ.get("SMTP_USERNAME")
|
||||
password = os.environ.get("SMTP_PASSWORD")
|
||||
from_email = os.environ.get("SMTP_FROM") or username
|
||||
starttls = os.environ.get("SMTP_STARTTLS", "1").lower() in ("1", "true", "yes", "on")
|
||||
timeout = float(os.environ.get("SMTP_TIMEOUT_SECONDS", "10"))
|
||||
debug = os.environ.get("SMTP_DEBUG", "0").lower() in ("1", "true", "yes", "on")
|
||||
# Pull optional defaults from DB (if available). This keeps backwards compatibility:
|
||||
# existing deployments that only use env vars keep working unchanged.
|
||||
db_defaults = {}
|
||||
try:
|
||||
# Local import to avoid import cycles and to keep this module lightweight.
|
||||
from flask import current_app
|
||||
|
||||
from .extensions import db
|
||||
from .models import AppSettings
|
||||
|
||||
# Only try if app context exists (send_email is called inside requests/CLI normally).
|
||||
_ = current_app # noqa: F841
|
||||
s = db.session.get(AppSettings, 1)
|
||||
if s:
|
||||
db_defaults = {
|
||||
"host": s.smtp_host,
|
||||
"port": s.smtp_port,
|
||||
"username": s.smtp_username,
|
||||
"password": s.smtp_password,
|
||||
"from_email": s.smtp_from,
|
||||
"starttls": s.smtp_starttls,
|
||||
"timeout": s.smtp_timeout_seconds,
|
||||
"debug": s.smtp_debug,
|
||||
}
|
||||
except Exception:
|
||||
# Best-effort; if DB isn't ready we fall back to env vars only.
|
||||
db_defaults = {}
|
||||
|
||||
host = os.environ.get("SMTP_HOST") or db_defaults.get("host")
|
||||
port = int(os.environ.get("SMTP_PORT") or db_defaults.get("port") or 587)
|
||||
username = os.environ.get("SMTP_USERNAME") or db_defaults.get("username")
|
||||
password = os.environ.get("SMTP_PASSWORD") or db_defaults.get("password")
|
||||
from_email = os.environ.get("SMTP_FROM") or db_defaults.get("from_email") or username
|
||||
starttls = _truthy(os.environ.get("SMTP_STARTTLS")) if os.environ.get("SMTP_STARTTLS") is not None else bool(
|
||||
db_defaults.get("starttls") if db_defaults.get("starttls") is not None else True
|
||||
)
|
||||
timeout = float(os.environ.get("SMTP_TIMEOUT_SECONDS") or db_defaults.get("timeout") or 10)
|
||||
debug = _truthy(os.environ.get("SMTP_DEBUG")) if os.environ.get("SMTP_DEBUG") is not None else bool(
|
||||
db_defaults.get("debug") or False
|
||||
)
|
||||
|
||||
missing = []
|
||||
if not host:
|
||||
@@ -41,13 +82,17 @@ def send_email(*, to_email: str, subject: str, body_text: str):
|
||||
raise RuntimeError(
|
||||
"Missing SMTP configuration: "
|
||||
+ ", ".join(missing)
|
||||
+ ". Set them as environment variables (or in a local .env file)."
|
||||
+ ". Set them as environment variables (or configure them in Admin → Settings)."
|
||||
)
|
||||
|
||||
msg = EmailMessage()
|
||||
msg["From"] = from_email
|
||||
msg["To"] = to_email
|
||||
msg["Subject"] = subject
|
||||
# Helps when SMTP providers force the authenticated mailbox as envelope sender,
|
||||
# but still allow replies to go to the desired address.
|
||||
if from_email and username and from_email != username:
|
||||
msg["Reply-To"] = from_email
|
||||
msg.set_content(body_text)
|
||||
|
||||
with smtplib.SMTP(host, port, timeout=timeout) as smtp:
|
||||
@@ -58,4 +103,7 @@ def send_email(*, to_email: str, subject: str, body_text: str):
|
||||
smtp.starttls()
|
||||
smtp.ehlo()
|
||||
smtp.login(username, password)
|
||||
smtp.send_message(msg)
|
||||
|
||||
# Pass explicit envelope-from to avoid falling back to the authenticated user.
|
||||
# Note: some SMTP providers will still override this for anti-spoofing.
|
||||
smtp.send_message(msg, from_addr=from_email, to_addrs=[to_email])
|
||||
|
||||
Reference in New Issue
Block a user