"""SMTP email provider implementation.""" import logging import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from flask import current_app from gatehouse_app.services.email_provider import EmailMessage, EmailProvider logger = logging.getLogger(__name__) class SmtpEmailProvider(EmailProvider): """SMTP-based email provider implementation.""" # Configuration keys EMAIL_ENABLED_KEY = "EMAIL_ENABLED" SMTP_HOST_KEY = "SMTP_HOST" SMTP_PORT_KEY = "SMTP_PORT" SMTP_USERNAME_KEY = "SMTP_USERNAME" SMTP_PASSWORD_KEY = "SMTP_PASSWORD" SMTP_USE_TLS_KEY = "SMTP_USE_TLS" FROM_ADDRESS_KEY = "FROM_ADDRESS" def send(self, message: EmailMessage) -> bool: """Send an email via SMTP. Args: message: EmailMessage instance containing email details Returns: bool: True if email was sent successfully, False otherwise """ email_enabled = current_app.config.get(self.EMAIL_ENABLED_KEY, False) if not email_enabled: logger.info( f"[EMAIL DISABLED] Would have sent to: {message.to} | " f"Subject: {message.subject}" ) return False smtp_host = current_app.config.get(self.SMTP_HOST_KEY, "") from_address = message.from_address or current_app.config.get(self.FROM_ADDRESS_KEY, "") missing = [k for k, v in [("SMTP_HOST", smtp_host), ("FROM_ADDRESS", from_address)] if not v] if missing: logger.error( f"[EMAIL] Cannot send — missing config: {', '.join(missing)}. " f"Would have sent to: {message.to} | Subject: {message.subject}" ) return False smtp_port_raw = current_app.config.get(self.SMTP_PORT_KEY, 587) try: smtp_port = int(smtp_port_raw) except (TypeError, ValueError): logger.error(f"[EMAIL] Invalid SMTP_PORT value: {smtp_port_raw!r}") return False smtp_username = current_app.config.get(self.SMTP_USERNAME_KEY) smtp_password = current_app.config.get(self.SMTP_PASSWORD_KEY) smtp_use_tls = current_app.config.get( self.SMTP_USE_TLS_KEY, smtp_port not in (25, 1025), ) try: msg = MIMEMultipart("alternative") msg["Subject"] = message.subject msg["From"] = from_address msg["To"] = message.to msg.attach(MIMEText(message.body, "plain")) if message.html_body: msg.attach(MIMEText(message.html_body, "html")) with smtplib.SMTP(smtp_host, smtp_port) as server: server.ehlo() if smtp_use_tls: server.starttls() server.ehlo() if smtp_username and smtp_password: server.login(smtp_username, smtp_password) server.send_message(msg) logger.info(f"[EMAIL] Sent to {message.to} | Subject: {message.subject}") return True except Exception as e: logger.error(f"[EMAIL] Failed to send to {message.to}: {e}") return False