71 lines
1.9 KiB
Python
71 lines
1.9 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from email.message import EmailMessage
|
|
import smtplib
|
|
import ssl
|
|
|
|
|
|
@dataclass
|
|
class MailServerSettings:
|
|
smtp_host: str
|
|
smtp_port: int
|
|
smtp_username: str | None
|
|
smtp_password: str | None
|
|
from_email: str
|
|
from_name: str
|
|
use_starttls: bool
|
|
use_ssl: bool
|
|
verify_tls: bool
|
|
timeout_seconds: int = 15
|
|
|
|
|
|
def _build_context(verify_tls: bool) -> ssl.SSLContext:
|
|
context = ssl.create_default_context()
|
|
if verify_tls:
|
|
return context
|
|
context.check_hostname = False
|
|
context.verify_mode = ssl.CERT_NONE
|
|
return context
|
|
|
|
|
|
def send_email(
|
|
*,
|
|
settings: MailServerSettings,
|
|
to_email: str,
|
|
subject: str,
|
|
text_body: str,
|
|
) -> None:
|
|
if not settings.smtp_host.strip():
|
|
raise ValueError("SMTP host is empty")
|
|
if not settings.from_email.strip():
|
|
raise ValueError("From email is empty")
|
|
|
|
msg = EmailMessage()
|
|
msg["Subject"] = subject
|
|
msg["From"] = f"{settings.from_name} <{settings.from_email}>"
|
|
msg["To"] = to_email
|
|
msg.set_content(text_body)
|
|
|
|
ssl_context = _build_context(settings.verify_tls)
|
|
if settings.use_ssl:
|
|
with smtplib.SMTP_SSL(
|
|
settings.smtp_host,
|
|
settings.smtp_port,
|
|
timeout=settings.timeout_seconds,
|
|
context=ssl_context,
|
|
) as smtp:
|
|
if settings.smtp_username:
|
|
smtp.login(settings.smtp_username, settings.smtp_password or "")
|
|
smtp.send_message(msg)
|
|
return
|
|
|
|
with smtplib.SMTP(settings.smtp_host, settings.smtp_port, timeout=settings.timeout_seconds) as smtp:
|
|
smtp.ehlo()
|
|
if settings.use_starttls:
|
|
smtp.starttls(context=ssl_context)
|
|
smtp.ehlo()
|
|
if settings.smtp_username:
|
|
smtp.login(settings.smtp_username, settings.smtp_password or "")
|
|
smtp.send_message(msg)
|