Source code for litestar_email.backends.base

from abc import ABC, abstractmethod
from email.utils import formataddr, parseaddr
from typing import TYPE_CHECKING

from typing_extensions import Self

if TYPE_CHECKING:
    from litestar_email.message import EmailMessage

__all__ = ("BaseEmailBackend",)


[docs] class BaseEmailBackend(ABC): """Abstract base class for email backends. All email backends must inherit from this class and implement the ``send_messages`` method. Backends can optionally override ``open`` and ``close`` for connection pooling. The class supports async context manager protocol for resource management. Example: Basic usage with context manager:: async with get_backend() as backend: await backend.send_messages([message]) """ __slots__ = ("_default_from_email", "_default_from_name", "fail_silently")
[docs] def __init__( self, fail_silently: bool = False, default_from_email: str | None = None, default_from_name: str | None = None, ) -> None: """Initialize the email backend. Args: fail_silently: If True, exceptions during sending are suppressed. default_from_email: Default sender email when message.from_email is missing. default_from_name: Default sender name when message.from_email has no name. """ self.fail_silently = fail_silently self._default_from_email = default_from_email self._default_from_name = default_from_name
[docs] async def open(self) -> bool: """Open a connection to the email server. Override this method to implement connection pooling. Called automatically when entering the async context manager. Returns: True if connection was opened, False if already open or not needed. """ return True
[docs] async def close(self) -> None: """Close the connection to the email server. Override this method to clean up resources. Called automatically when exiting the async context manager. """
async def __aenter__(self) -> Self: """Enter the async context manager. Returns: The backend instance. """ await self.open() return self async def __aexit__( self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: object, ) -> None: """Exit the async context manager. Args: exc_type: The exception type, if any. exc_val: The exception value, if any. exc_tb: The exception traceback, if any. """ await self.close() def _resolve_from(self, message: "EmailMessage") -> tuple[str, str, str]: """Resolve the sender address for a message. Args: message: The email message. Returns: Tuple of (email, name, formatted) values. """ raw_from = message.from_email or self._default_from_email or "" name, email = parseaddr(raw_from) if not name and self._default_from_name: name = self._default_from_name formatted = formataddr((name, email)) if email else "" return email, name, formatted
[docs] @abstractmethod async def send_messages(self, messages: list["EmailMessage"]) -> int: """Send one or more email messages. This method must be implemented by all backends. Args: messages: A list of EmailMessage instances to send. Returns: The number of messages successfully sent. Raises: Exception: If fail_silently is False and sending fails. """ ...