diff --git a/api/libs/smtp.py b/api/libs/smtp.py index da93d485cd..36abf10165 100644 --- a/api/libs/smtp.py +++ b/api/libs/smtp.py @@ -3,10 +3,10 @@ import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText - class SMTPClient: def __init__( - self, server: str, port: int, username: str, password: str, _from: str, use_tls=False, opportunistic_tls=False + self, server: str, port: int, username: str, password: str, _from: str, + use_tls=False, opportunistic_tls=False ): self.server = server self.port = port @@ -19,18 +19,26 @@ class SMTPClient: def send(self, mail: dict): smtp = None try: - # Always use STARTTLS for ports like 587 (Office365/modern SMTP) + # Port 465 is implicit SSL, always use SMTP_SSL. if self.port == 465: smtp = smtplib.SMTP_SSL(self.server, self.port, timeout=10) - elif self.use_tls or self.opportunistic_tls: - smtp = smtplib.SMTP(self.server, self.port, timeout=10) - smtp.ehlo(self.server) - smtp.starttls() - smtp.ehlo(self.server) else: smtp = smtplib.SMTP(self.server, self.port, timeout=10) + smtp.ehlo(self.server) + if self.use_tls: + # Strict: fail if STARTTLS fails + smtp.starttls() + smtp.ehlo(self.server) + elif self.opportunistic_tls: + # Try STARTTLS, but continue if it fails + try: + smtp.starttls() + smtp.ehlo(self.server) + logging.info("Opportunistic STARTTLS succeeded") + except Exception as e: + logging.warning(f"Opportunistic STARTTLS failed, continuing unencrypted: {e}") - # Only authenticate if both username and password are non-empty + # Authenticate if needed if self.username and self.password and self.username.strip() and self.password.strip(): smtp.login(self.username, self.password) @@ -48,8 +56,11 @@ class SMTPClient: logging.exception("Timeout occurred while sending email") raise except Exception as e: - logging.exception(f"Unexpected error occurred while sending email to {mail['to']}") + logging.exception(f"Unexpected error occurred while sending email to {mail['to']}: {e}") raise finally: if smtp: - smtp.quit() + try: + smtp.quit() + except Exception: + pass