Coverage for src/lexigram/notification/mailer/mailable.py: 90%

10 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-26 07:17 +0800

1"""Mailable — base class for structured email templates.""" 

2 

3from __future__ import annotations 

4 

5import abc 

6import html 

7 

8from lexigram.contracts.mailer import EmailMessage 

9 

10 

11class Mailable(abc.ABC): 

12 """Base class for structured email templates. 

13 

14 Subclass ``Mailable`` to encapsulate the data and rendering logic for a 

15 specific email type. Call :meth:`to_message` to build the 

16 :class:`~lexigram.contracts.mailer.types.EmailMessage` that is 

17 passed to :meth:`~lexigram.contracts.mailer.protocols.MailerProtocol.send`. 

18 

19 Example:: 

20 

21 class WelcomeMail(Mailable): 

22 def __init__(self, user_name: str, user_email: str) -> None: 

23 self.user_name = user_name 

24 self.user_email = user_email 

25 

26 def to_message(self) -> EmailMessage: 

27 return EmailMessage( 

28 to=[self.user_email], 

29 subject=f"Welcome, {self.user_name}!", 

30 body=f"Hi {self.user_name}, welcome aboard.", 

31 html_body=f"<p>Hi <b>{escape_html(self.user_name)}</b>, welcome aboard.</p>", 

32 ) 

33 """ 

34 

35 @abc.abstractmethod 

36 def to_message(self) -> EmailMessage: 

37 """Build the EmailMessage for this mailable. 

38 

39 Returns: 

40 A fully populated :class:`~lexigram.contracts.mailer.types.EmailMessage`. 

41 """ 

42 

43 

44def escape_html(text: str) -> str: 

45 """Escape text for inclusion in an HTML email body. 

46 

47 HTML email bodies are rendered by mail clients; user-controlled text 

48 interpolated unescaped (as in the pre-fix docstring example) becomes 

49 markup. Escape before building ``html_body``. 

50 

51 Args: 

52 text: Untrusted text, e.g. a user-entered name. 

53 

54 Returns: 

55 Text with ``&``, ``<``, ``>``, and ``"`` escaped so it renders as 

56 literal text in an HTML email. 

57 """ 

58 return html.escape(text, quote=True) 

59 

60 

61__all__ = ["Mailable", "escape_html"]