Plain is headed towards 1.0! Subscribe for development updates →

 1"""
 2Email backend that writes messages to console instead of sending them.
 3"""
 4
 5from __future__ import annotations
 6
 7import sys
 8import threading
 9from typing import TYPE_CHECKING, Any
10
11from .base import BaseEmailBackend
12
13if TYPE_CHECKING:
14    from ..message import EmailMessage
15
16
17class EmailBackend(BaseEmailBackend):
18    def __init__(self, *args: Any, **kwargs: Any) -> None:
19        self.stream = kwargs.pop("stream", sys.stdout)
20        self._lock = threading.RLock()
21        super().__init__(*args, **kwargs)
22
23    def write_message(self, message: EmailMessage) -> None:
24        msg = message.message()
25        msg_data = msg.as_bytes()
26        charset = (
27            msg.get_charset().get_output_charset() if msg.get_charset() else "utf-8"
28        )
29        msg_data = msg_data.decode(charset)
30        self.stream.write(f"{msg_data}\n")
31        self.stream.write("-" * 79)
32        self.stream.write("\n")
33
34    def send_messages(self, email_messages: list[EmailMessage]) -> int:
35        """Write all messages to the stream in a thread-safe way."""
36        if not email_messages:
37            return 0
38        msg_count = 0
39        with self._lock:
40            try:
41                stream_created = self.open()
42                for message in email_messages:
43                    self.write_message(message)
44                    self.stream.flush()  # flush after each message
45                    msg_count += 1
46                if stream_created:
47                    self.close()
48            except Exception:
49                if not self.fail_silently:
50                    raise
51        return msg_count