Recently Written · git

subplz-web

git clone https://github.com/equwal/subplz-web

Log | Files | Refs


backend/mailer.py (2206 bytes)

1 """Outbound email. Plain SMTP, so any provider works; nothing else is sent."""
2 
3 from __future__ import annotations
4 
5 import logging
6 import smtplib
7 from email.message import EmailMessage
8 
9 from .settings import settings
10 
11 log = logging.getLogger(__name__)
12 
13 
14 class MailError(RuntimeError):
15     pass
16 
17 
18 def send_login_link(to: str, url: str) -> bool:
19     """Email a sign-in link. Returns False when there is no mail server.
20 
21     That only happens in development (dev_login_links), where the API hands
22     the link back itself. It is deliberately not logged: a sign-in link in a
23     log file is a credential in a log file.
24     """
25     if not settings.email_configured:
26         return False
27 
28     minutes = settings.login_link_minutes
29     msg = EmailMessage()
30     msg["Subject"] = "Your sign-in link"
31     msg["From"] = settings.smtp_from
32     msg["To"] = to
33     msg.set_content(
34         f"Open this link to sign in:\n\n{url}\n\n"
35         f"It works once and expires in {minutes} minutes. "
36         "If you did not ask for it, ignore this email - nothing happens "
37         "unless the link is opened.\n"
38     )
39     msg.add_alternative(
40         f"<p>Open this link to sign in:</p>"
41         f'<p><a href="{url}">Sign in</a></p>'
42         f'<p style="color:#666;font-size:13px">It works once and expires in '
43         f"{minutes} minutes. If you did not ask for it, ignore this email - "
44         f"nothing happens unless the link is opened.</p>",
45         subtype="html",
46     )
47 
48     try:
49         if settings.smtp_port == 465:
50             smtp = smtplib.SMTP_SSL(settings.smtp_host, settings.smtp_port, timeout=20)
51         else:
52             smtp = smtplib.SMTP(settings.smtp_host, settings.smtp_port, timeout=20)
53         with smtp:
54             if settings.smtp_port != 465 and settings.smtp_starttls:
55                 smtp.starttls()
56             if settings.smtp_user:
57                 smtp.login(settings.smtp_user, settings.smtp_password)
58             smtp.send_message(msg)
59     except (smtplib.SMTPException, OSError) as exc:
60         log.warning("could not send sign-in link to %s: %s", to, exc)
61         raise MailError(
62             "The sign-in email could not be sent. Try again shortly."
63         ) from exc
64     return True