from __future__ import annotations import smtplib from email.message import EmailMessage from flask import current_app, render_template from .settings import get_bool_setting, get_int_setting, get_str_setting class MailService: def _settings(self) -> dict: security = get_str_setting('smtp_security', '') or ('ssl' if get_bool_setting('smtp_use_ssl', current_app.config.get('MAIL_USE_SSL', True)) else ('starttls' if get_bool_setting('smtp_use_tls', current_app.config.get('MAIL_USE_TLS', False)) else 'plain')) return { 'host': get_str_setting('smtp_host', current_app.config.get('MAIL_SERVER', '')), 'port': get_int_setting('smtp_port', current_app.config.get('MAIL_PORT', 465)), 'username': get_str_setting('smtp_username', current_app.config.get('MAIL_USERNAME', '')), 'password': get_str_setting('smtp_password', current_app.config.get('MAIL_PASSWORD', '')), 'sender': get_str_setting('smtp_sender', current_app.config.get('MAIL_DEFAULT_SENDER', 'no-reply@example.com')), 'security': security, } def is_configured(self) -> bool: return bool(self._settings()['host']) def send(self, to_email: str, subject: str, body: str, html: str | None = None) -> bool: cfg = self._settings() if not cfg['host']: current_app.logger.info('Mail skipped for %s: %s', to_email, subject) return False msg = EmailMessage() msg['Subject'] = subject msg['From'] = cfg['sender'] msg['To'] = to_email msg.set_content(body) if html: msg.add_alternative(html, subtype='html') if cfg['security'] == 'ssl': with smtplib.SMTP_SSL(cfg['host'], cfg['port']) as smtp: if cfg['username']: smtp.login(cfg['username'], cfg['password']) smtp.send_message(msg) else: with smtplib.SMTP(cfg['host'], cfg['port']) as smtp: if cfg['security'] == 'starttls': smtp.starttls() if cfg['username']: smtp.login(cfg['username'], cfg['password']) smtp.send_message(msg) return True def send_template(self, to_email: str, subject: str, template_name: str, **context) -> bool: html = render_template(f'mail/{template_name}.html', **context) text = render_template(f'mail/{template_name}.txt', **context) return self.send(to_email, subject, text, html=html)