56 lines
2.5 KiB
Python
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)
|