Skip to content

Commit 6ad30ea

Browse files
committed
docs(email): add email backend document
1 parent e031db0 commit 6ad30ea

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed

utils/email/docs/email.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
## Overview
2+
This system supports **pluggable email backends** in Django, allowing dynamic switching between:
3+
4+
- SMTP-based email delivery (default Django backend)
5+
- Custom HTTP API-based email delivery
6+
7+
## Backend Selection
8+
- The email backend is controlled via environment variables:
9+
- **SMTP Backend (Development)**
10+
```env
11+
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
12+
EMAIL_HOST=mailpit
13+
EMAIL_PORT=1025
14+
EMAIL_USE_TLS=False
15+
````
16+
- **Custom API Backend (Production)**
17+
```env
18+
EMAIL_BACKEND=utils.email.CustomEmailBackend
19+
EMAIL_API_ENDPOINT=<API_ENDPOINT>
20+
EMAIL_API_KEY=<API_KEY>
21+
EMAIL_API_TIMEOUT=30
22+
```
23+
24+
25+
## High-Level Architecture
26+
```mermaid
27+
flowchart TD
28+
A["Django App<br/>(send_mail / EmailMessage)"]
29+
B["EMAIL_BACKEND<br/>(Configured via ENV)"]
30+
C["SMTP Backend"]
31+
D["Custom Email Backend"]
32+
A --> B
33+
B --> C
34+
B --> D
35+
```
36+
37+
## Custom Email Backend Components
38+
39+
- Base Email Backend (`EmailBackend`)
40+
- An abstract class extending Django’s `BaseEmailBackend`, responsible for handling HTTP-based email delivery.
41+
- Manage HTTP session lifecycle (`open`, `close`)
42+
- Ensure thread safety using `threading.RLock`
43+
- Send email messages via HTTP POST
44+
- Handle API responses (success/failure)
45+
- Provide reusable utilities (e.g., Base64 encoding)
46+
47+
- Custom Email Backend (`CustomEmailBackend`)
48+
- Implementation of `EmailBackend` for a specific external email API.
49+
- Transform `EmailMessage` into API-compatible payload
50+
- Encode email fields using Base64
51+
- Support HTML and plain text email content
52+
53+
**Key Methods**
54+
55+
| Method | Description |
56+
| ------------------- | -------------------------------------- |
57+
| `open()` | Initializes HTTP session |
58+
| `close()` | Closes HTTP session |
59+
| `send_messages()` | Sends batch of email messages |
60+
| `_send_message()` | Sends a single email |
61+
| `_build_headers()` | Constructs HTTP headers |
62+
| `_build_payload()` | Abstract method for payload generation |
63+
| `_handle_success()` | Handles successful response |
64+
| `_handle_failure()` | Handles failed response |
65+
66+
## Request Flow
67+
1. Django constructs an `EmailMessage`
68+
2. `send_messages()` is invoked by the backend
69+
3. A thread-safe session is initialized
70+
4. For each message:
71+
- `_build_headers()` prepares HTTP headers
72+
- `_build_payload()` converts message to API format
73+
- HTTP POST request is sent to the API endpoint
74+
5. Response handling:
75+
- Success → logged and counted
76+
- Failure → logged and optionally raises exception
77+
78+
## Header Construction
79+
Default headers
80+
```http
81+
Content-Type: application/json
82+
X-API-KEY: <API_KEY>
83+
```
84+
> Note: `X-API-KEY` is currently used for authentication. This can be extended in the future to support other authentication schemes.
85+
86+
87+
## Payload Format
88+
The email message is converted into a JSON payload:
89+
90+
```json
91+
{
92+
"FromAsBase64": "<encoded>",
93+
"ToAsBase64": "<encoded>",
94+
"CcAsBase64": "<encoded>",
95+
"BccAsBase64": "<encoded>",
96+
"SubjectAsBase64": "<encoded>",
97+
"BodyAsBase64": "<encoded>",
98+
"IsBodyHtml": true
99+
}
100+
```
101+
102+
### Details
103+
- All fields are Base64-encoded
104+
- HTML content is preferred if available
105+
- Falls back to plain text body otherwise
106+
107+
108+
## Thread Safety
109+
- A `threading.RLock` is used to ensure safe concurrent access
110+
- Prevents race conditions when multiple threads send emails
111+
- Ensures session reuse without corruption

0 commit comments

Comments
 (0)