diff --git a/backend/app/email.py b/backend/app/email.py index e700802..07da8be 100644 --- a/backend/app/email.py +++ b/backend/app/email.py @@ -8,6 +8,7 @@ import logging import smtplib import ssl from email.message import EmailMessage +from email.utils import formatdate from app.config import settings @@ -18,7 +19,11 @@ def email_enabled() -> bool: return bool(settings.smtp_host and settings.smtp_user and settings.smtp_password) -def _send(to: list[str], subject: str, body: str) -> bool: +def _admin_contact() -> str | None: + return next(iter(sorted(settings.admin_email_set)), None) + + +def _send(to: list[str], subject: str, body: str, reply_to: str | None = None) -> bool: recipients = [e for e in to if e] if not recipients: return False @@ -29,6 +34,11 @@ def _send(to: list[str], subject: str, body: str) -> bool: msg["Subject"] = subject msg["From"] = settings.smtp_from or settings.smtp_user msg["To"] = ", ".join(recipients) + # A real Date and a Reply-To (so it's a conversation, not a no-reply blast) both + # nudge spam filters the right way; reputation still does most of the work. + msg["Date"] = formatdate(localtime=True) + if reply_to: + msg["Reply-To"] = reply_to msg.set_content(body) try: with smtplib.SMTP(settings.smtp_host, settings.smtp_port, timeout=20) as s: @@ -43,18 +53,23 @@ def _send(to: list[str], subject: str, body: str) -> bool: def send_access_approved(email: str) -> bool: - return _send( - [email], - "Your Subfeed access is approved", - "Good news — your access to Subfeed has been approved.\n\n" - "Sign in with this Google account to start browsing your subscriptions.\n", + admin = _admin_contact() + body = ( + "Hi,\n\n" + "Your request to use Subfeed has been approved — welcome aboard.\n\n" + "Just open Subfeed and sign in with this Google account, and your YouTube\n" + "subscriptions feed will be ready.\n\n" + "If you weren't expecting this, you can ignore the message.\n\n" + "— Subfeed" + + (f"\n\nQuestions? Just reply to this email ({admin})." if admin else "") ) + return _send([email], "You're in — your Subfeed access is approved", body, reply_to=admin) def send_admin_new_request(admins: list[str], requester: str) -> bool: - return _send( - admins, - "Subfeed: new access request", - f"{requester} has requested access to Subfeed.\n\n" - "Approve or deny it in Settings → Admin.\n", + body = ( + f"{requester} just requested access to Subfeed.\n\n" + "Open Subfeed → Settings → Account → Access requests to approve or deny it.\n\n" + "(Reply to this email to reach the requester directly.)\n" ) + return _send(admins, f"Subfeed access request from {requester}", body, reply_to=requester)