82 lines
2.0 KiB
Python
82 lines
2.0 KiB
Python
|
from collections.abc import Sequence
|
||
|
from typing import Any, ClassVar, TypeAlias
|
||
|
|
||
|
from django.core import mail
|
||
|
from django.template import loader
|
||
|
|
||
|
import mdformat
|
||
|
from markdownify import markdownify
|
||
|
|
||
|
Context: TypeAlias = dict[str, Any]
|
||
|
|
||
|
|
||
|
class EmailBase:
|
||
|
subject: ClassVar[str]
|
||
|
from_email: ClassVar[str | None] = None
|
||
|
reply_to: ClassVar[Sequence[str] | None] = None
|
||
|
|
||
|
context: Context
|
||
|
|
||
|
def __init__(self, context: Context) -> None:
|
||
|
self.context = context
|
||
|
|
||
|
def render_body(self) -> str:
|
||
|
raise NotImplementedError
|
||
|
|
||
|
@classmethod
|
||
|
def render(
|
||
|
cls,
|
||
|
context: Context,
|
||
|
to: list[str] | None = None,
|
||
|
cc: list[str] | None = None,
|
||
|
bcc: list[str] | None = None,
|
||
|
) -> mail.EmailMessage:
|
||
|
self = cls(context)
|
||
|
|
||
|
body = self.render_body()
|
||
|
|
||
|
return mail.EmailMessage(
|
||
|
self.subject,
|
||
|
body,
|
||
|
from_email=self.from_email,
|
||
|
reply_to=self.reply_to,
|
||
|
to=to,
|
||
|
cc=cc,
|
||
|
bcc=bcc,
|
||
|
)
|
||
|
|
||
|
|
||
|
class TemplatedMultipartEmail(EmailBase):
|
||
|
template: ClassVar[str]
|
||
|
|
||
|
def render_html_body(self) -> str:
|
||
|
template = loader.get_template(self.template)
|
||
|
return template.render(self.context)
|
||
|
|
||
|
def render_body(self, html_body: str) -> str:
|
||
|
return mdformat.text(markdownify(html_body), extensions={"tables"})
|
||
|
|
||
|
@classmethod
|
||
|
def render(
|
||
|
cls,
|
||
|
context: Context,
|
||
|
to: list[str] | None = None,
|
||
|
cc: list[str] | None = None,
|
||
|
bcc: list[str] | None = None,
|
||
|
) -> mail.EmailMessage:
|
||
|
self = cls(context)
|
||
|
|
||
|
html_body = self.render_html_body()
|
||
|
plain_body = self.render_body(html_body)
|
||
|
|
||
|
return mail.EmailMultiAlternatives(
|
||
|
self.subject,
|
||
|
plain_body,
|
||
|
from_email=self.from_email,
|
||
|
reply_to=self.reply_to,
|
||
|
to=to,
|
||
|
cc=cc,
|
||
|
bcc=bcc,
|
||
|
alternatives=[(html_body, "text/html")],
|
||
|
)
|