Add SMTP security mode selector with SSL/STARTTLS/none options and automatic port switching
Replaced boolean `smtp_use_tls` with explicit `smtp_security` enum field supporting "none", "starttls", and "ssl" modes. Added database migration to create `smtp_security` column with "starttls" default. Updated mailer to use SMTP_SSL client for direct SSL connections on port 465 and SMTP with STARTTLS for port 587. Modified admin settings UI to show dropdown selector with encryption options and auto-adjust
This commit is contained in:
@@ -23,9 +23,13 @@ def send_html_email(settings: AppSettings, recipient: str, subject: str, body_ht
|
||||
message.add_alternative(body_html, subtype="html")
|
||||
|
||||
context = ssl.create_default_context()
|
||||
with smtplib.SMTP(settings.smtp_host, settings.smtp_port or 587, timeout=20) as server:
|
||||
security = getattr(settings, "smtp_security", "") or ("starttls" if settings.smtp_use_tls else "none")
|
||||
port = settings.smtp_port or (465 if security == "ssl" else 587)
|
||||
smtp_client = smtplib.SMTP_SSL if security == "ssl" else smtplib.SMTP
|
||||
connection = smtp_client(settings.smtp_host, port, timeout=20, context=context) if security == "ssl" else smtp_client(settings.smtp_host, port, timeout=20)
|
||||
with connection as server:
|
||||
server.ehlo()
|
||||
if settings.smtp_use_tls:
|
||||
if security == "starttls":
|
||||
server.starttls(context=context)
|
||||
server.ehlo()
|
||||
if settings.smtp_username:
|
||||
|
||||
@@ -88,6 +88,14 @@ Very small, pragmatic auto-migration (no alembic).
|
||||
- supports old schema (join_code/chip_code) and new schema (code/chip)
|
||||
"""
|
||||
|
||||
# --- app settings: explicit SMTP security mode (none/starttls/ssl) ---
|
||||
if not _has_column(db, "app_settings", "smtp_security"):
|
||||
try:
|
||||
db.execute(text("ALTER TABLE app_settings ADD COLUMN smtp_security VARCHAR DEFAULT 'starttls'"))
|
||||
db.commit()
|
||||
except Exception:
|
||||
db.rollback()
|
||||
|
||||
# --- users.display_name ---
|
||||
if not _has_column(db, "users", "display_name"):
|
||||
try:
|
||||
|
||||
@@ -52,6 +52,7 @@ class AppSettings(Base):
|
||||
smtp_from_email: Mapped[str] = mapped_column(String, default="")
|
||||
smtp_from_name: Mapped[str] = mapped_column(String, default="Cluedo HP")
|
||||
smtp_use_tls: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
smtp_security: Mapped[str] = mapped_column(String, default="starttls")
|
||||
app_base_url: Mapped[str] = mapped_column(String, default="http://localhost:8081")
|
||||
|
||||
|
||||
|
||||
@@ -163,6 +163,7 @@ def read_smtp_settings(req: Request, db: Session = Depends(get_db)):
|
||||
"smtp_password_configured": bool(settings.smtp_password),
|
||||
"smtp_from_email": settings.smtp_from_email,
|
||||
"smtp_from_name": settings.smtp_from_name,
|
||||
"smtp_security": getattr(settings, "smtp_security", "starttls") or ("starttls" if settings.smtp_use_tls else "none"),
|
||||
"smtp_use_tls": settings.smtp_use_tls,
|
||||
"app_base_url": settings.app_base_url,
|
||||
}
|
||||
@@ -181,7 +182,11 @@ def update_smtp_settings(req: Request, data: dict, db: Session = Depends(get_db)
|
||||
settings.smtp_username = (data.get("smtp_username") or "").strip()
|
||||
settings.smtp_from_email = (data.get("smtp_from_email") or "").strip()
|
||||
settings.smtp_from_name = (data.get("smtp_from_name") or "Cluedo HP").strip()
|
||||
settings.smtp_use_tls = bool(data.get("smtp_use_tls", True))
|
||||
security = data.get("smtp_security") or ("starttls" if data.get("smtp_use_tls", True) else "none")
|
||||
if security not in ("none", "starttls", "ssl"):
|
||||
raise HTTPException(400, "invalid SMTP security mode")
|
||||
settings.smtp_security = security
|
||||
settings.smtp_use_tls = security == "starttls"
|
||||
settings.app_base_url = (data.get("app_base_url") or "http://localhost:8081").strip().rstrip("/")
|
||||
if "smtp_password" in data and data.get("smtp_password"):
|
||||
settings.smtp_password = data["smtp_password"]
|
||||
|
||||
Reference in New Issue
Block a user