From 6ba6d23047fdf14f7f67f246b1c80cdc8af71ed7 Mon Sep 17 00:00:00 2001 From: grillazz Date: Sat, 28 Dec 2024 08:10:09 +0100 Subject: [PATCH] refactor and black --- app/config.py | 1 + app/services/scheduler.py | 1 - app/services/smtp.py | 54 +++++++++++++++++++++++++++++---------- app/utils/singleton.py | 2 +- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/app/config.py b/app/config.py index 5c617d3..b0b2c7a 100644 --- a/app/config.py +++ b/app/config.py @@ -10,6 +10,7 @@ class SMTPConfig(BaseModel): port: int = os.getenv("EMAIL_PORT", 587) username: str = os.getenv("EMAIL_HOST_USER", "smtp_user") password: str = os.getenv("EMAIL_HOST_PASSWORD", "smtp_password") + template_path: str = os.getenv("EMAIL_TEMPLATE_PATH", "templates") class Settings(BaseSettings): diff --git a/app/services/scheduler.py b/app/services/scheduler.py index 6a642d3..739e369 100644 --- a/app/services/scheduler.py +++ b/app/services/scheduler.py @@ -45,4 +45,3 @@ class SchedulerMiddleware: await self.app(scope, receive, send) else: await self.app(scope, receive, send) - diff --git a/app/services/smtp.py b/app/services/smtp.py index d4a2ce0..914d460 100644 --- a/app/services/smtp.py +++ b/app/services/smtp.py @@ -1,3 +1,4 @@ +from attrs import define, field import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText @@ -15,23 +16,35 @@ from app.utils.singleton import SingletonMetaNoArgs logger = AppLogger().get_logger() +@define class SMTPEmailService(metaclass=SingletonMetaNoArgs): - def __init__(self): - self.server = smtplib.SMTP( - global_settings.smtp.server, global_settings.smtp.port - ) - self.server.starttls() - self.server.login(global_settings.smtp.username, global_settings.smtp.password) - self.templates = Jinja2Templates("templates") + # SMTP configuration + server_host: str = field(default=global_settings.smtp.server) + server_port: int = field(default=global_settings.smtp.port) + username: str = field(default=global_settings.smtp.username) + password: str = field(default=global_settings.smtp.password) - def send_email( + # Dependencies + templates: Jinja2Templates = field( + factory=lambda: Jinja2Templates(global_settings.templates_dir) + ) + server: smtplib.SMTP = field(init=False) # Deferred initialization in post-init + + def __attrs_post_init__(self): + """Initialize the SMTP server connection after object creation.""" + self.server = smtplib.SMTP(self.server_host, self.server_port) + self.server.starttls() + self.server.login(self.username, self.password) + + def _prepare_email( self, sender: EmailStr, recipients: list[EmailStr], subject: str, - body_text: str = "", - body_html=None, - ): + body_text: str, + body_html: str, + ) -> MIMEMultipart: + """Prepare the email message.""" msg = MIMEMultipart() msg["From"] = sender msg["To"] = ",".join(recipients) @@ -39,16 +52,29 @@ class SMTPEmailService(metaclass=SingletonMetaNoArgs): msg.attach(MIMEText(body_text, "plain")) if body_html: msg.attach(MIMEText(body_html, "html")) + return msg + + def send_email( + self, + sender: EmailStr, + recipients: list[EmailStr], + subject: str, + body_text: str = "", + body_html: str = None, + ): + """Send a regular email (plain text or HTML).""" + msg = self._prepare_email(sender, recipients, subject, body_text, body_html) self.server.sendmail(sender, recipients, msg.as_string()) def send_template_email( self, recipients: list[EmailStr], subject: str, - template: str = None, - context: dict = None, - sender: EmailStr = global_settings.smtp.from_email, + template: str, + context: dict, + sender: EmailStr, ): + """Send an email using a template with the provided context.""" template_str = self.templates.get_template(template) body_html = template_str.render(context) self.send_email(sender, recipients, subject, body_html=body_html) diff --git a/app/utils/singleton.py b/app/utils/singleton.py index 85df17e..4bda944 100644 --- a/app/utils/singleton.py +++ b/app/utils/singleton.py @@ -33,4 +33,4 @@ class SingletonMetaNoArgs(type): if cls not in cls._instances: instance = super().__call__() cls._instances[cls] = instance - return cls._instances[cls] \ No newline at end of file + return cls._instances[cls]