import os import mimetypes from pathlib import Path from email.message import EmailMessage from email.headerregistry import Address from jinja2 import Environment, FileSystemLoader from ..config.email import EMAIL_CONFIG from ..config.paths import HTML_PATHS class EmailComposer: def __init__(self): self.sender = Address( display_name=EMAIL_CONFIG.sender_alias, addr_spec=EMAIL_CONFIG.sender_email, ) self.reply_to = EMAIL_CONFIG.reply_to def compose( self, subject: str, recipients: list[str], body_html: str, image_attachments: list[tuple[Path, str]], mode: str = "prod", ) -> EmailMessage: email = EmailMessage() email["Subject"] = subject email["From"] = self.sender email["Reply-To"] = self.reply_to email["To"] = self.reply_to if mode == "dev": email["Cc"] = recipients else: email["Bcc"] = recipients email.set_content("This is a plain text body.") email.add_alternative(body_html, subtype="html") for path, cid in image_attachments: self._attach_image(email, path, cid) return email def build_body_html( self, section_htmls: str, legend_cid: str, report_date: str = "", ) -> str: env = Environment( loader=FileSystemLoader(str(HTML_PATHS.email.parent)), autoescape=False, ) template = env.get_template(HTML_PATHS.email.name) return template.render( sections_html=section_htmls, legend_cid=f"cid:{legend_cid[1:-1]}", report_date=report_date, ) def build_section_html( self, insights_link: str, spotify_link: str, image_cid: str, spotify_cid: str, img_height: float = 76.5, img_width: float = 765, ) -> str: return f'''
''' @staticmethod def _attach_image(email: EmailMessage, path: Path, cid: str) -> None: with open(path, "rb") as img: mime_type = mimetypes.guess_type(str(path))[0] or "image/png" maintype, subtype = mime_type.split("/") email.get_payload()[1].add_related( img.read(), maintype=maintype, subtype=subtype, cid=cid, )