Files
expense_monitor/app/services/mail.py
Mateusz Gruszczyński 986ffb200a first commit
2026-03-13 15:17:32 +01:00

56 lines
2.5 KiB
Python

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)