euromail 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- euromail-0.1.0/.github/workflows/publish.yml +35 -0
- euromail-0.1.0/.gitignore +5 -0
- euromail-0.1.0/PKG-INFO +472 -0
- euromail-0.1.0/README.md +458 -0
- euromail-0.1.0/examples/all_methods.py +252 -0
- euromail-0.1.0/pyproject.toml +29 -0
- euromail-0.1.0/requirements.lock.txt +6 -0
- euromail-0.1.0/src/euromail/__init__.py +109 -0
- euromail-0.1.0/src/euromail/async_client.py +1049 -0
- euromail-0.1.0/src/euromail/client.py +1034 -0
- euromail-0.1.0/src/euromail/errors.py +55 -0
- euromail-0.1.0/src/euromail/types.py +627 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
name: Build & Test
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
- run: pip install -e ".[dev]"
|
|
18
|
+
- run: python -m pytest --no-header -q || true
|
|
19
|
+
- run: pip install build && python -m build
|
|
20
|
+
|
|
21
|
+
publish:
|
|
22
|
+
name: Publish to PyPI
|
|
23
|
+
needs: test
|
|
24
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
environment: pypi
|
|
27
|
+
permissions:
|
|
28
|
+
id-token: write
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
- uses: actions/setup-python@v5
|
|
32
|
+
with:
|
|
33
|
+
python-version: "3.12"
|
|
34
|
+
- run: pip install build && python -m build
|
|
35
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
euromail-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: euromail
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for the EuroMail transactional email service
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Keywords: email,euromail,smtp,transactional
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Requires-Dist: httpx>=0.27
|
|
9
|
+
Provides-Extra: dev
|
|
10
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
11
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
12
|
+
Requires-Dist: respx>=0.22; extra == 'dev'
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# euromail
|
|
16
|
+
|
|
17
|
+
Official Python SDK for the [EuroMail](https://euromail.dev) transactional email service.
|
|
18
|
+
|
|
19
|
+
[](https://pypi.org/project/euromail/)
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install euromail
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from euromail import EuroMail
|
|
31
|
+
|
|
32
|
+
client = EuroMail(api_key="em_live_your_api_key_here")
|
|
33
|
+
|
|
34
|
+
result = client.send_email(
|
|
35
|
+
from_address="sender@yourdomain.com",
|
|
36
|
+
to="recipient@example.com",
|
|
37
|
+
subject="Hello from EuroMail",
|
|
38
|
+
html_body="<h1>Welcome!</h1><p>Your account is ready.</p>",
|
|
39
|
+
)
|
|
40
|
+
print(f"Email queued: {result.id}")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Configuration
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
client = EuroMail(
|
|
47
|
+
api_key="em_live_...", # Required
|
|
48
|
+
timeout=30.0, # Default: 30 seconds
|
|
49
|
+
)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Context manager
|
|
53
|
+
|
|
54
|
+
The client can be used as a context manager to ensure the HTTP connection is properly closed:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
with EuroMail(api_key="em_live_...") as client:
|
|
58
|
+
client.send_email(
|
|
59
|
+
from_address="noreply@yourdomain.com",
|
|
60
|
+
to="user@example.com",
|
|
61
|
+
subject="Hello",
|
|
62
|
+
text_body="Welcome aboard!",
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Async client
|
|
67
|
+
|
|
68
|
+
For async/await applications, use `AsyncEuroMail`:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from euromail import AsyncEuroMail
|
|
72
|
+
|
|
73
|
+
async with AsyncEuroMail(api_key="em_live_...") as client:
|
|
74
|
+
result = await client.send_email(
|
|
75
|
+
from_address="noreply@yourdomain.com",
|
|
76
|
+
to="user@example.com",
|
|
77
|
+
subject="Hello",
|
|
78
|
+
text_body="Welcome aboard!",
|
|
79
|
+
)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The async client has the same API as the sync client, with all methods being `async`.
|
|
83
|
+
|
|
84
|
+
## Sending Emails
|
|
85
|
+
|
|
86
|
+
### Direct send
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
result = client.send_email(
|
|
90
|
+
from_address="noreply@yourdomain.com",
|
|
91
|
+
to="user@example.com",
|
|
92
|
+
subject="Order Confirmation",
|
|
93
|
+
html_body="<h1>Thanks for your order!</h1>",
|
|
94
|
+
text_body="Thanks for your order!",
|
|
95
|
+
reply_to="support@yourdomain.com",
|
|
96
|
+
cc=["manager@yourdomain.com"],
|
|
97
|
+
tags=["order", "confirmation"],
|
|
98
|
+
metadata={"order_id": "12345"},
|
|
99
|
+
)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Send with template
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
result = client.send_email(
|
|
106
|
+
from_address="noreply@yourdomain.com",
|
|
107
|
+
to="user@example.com",
|
|
108
|
+
template_alias="welcome-email",
|
|
109
|
+
template_data={
|
|
110
|
+
"name": "John",
|
|
111
|
+
"activation_url": "https://example.com/activate/abc123",
|
|
112
|
+
},
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Batch send
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from euromail import SendEmailParams
|
|
120
|
+
|
|
121
|
+
batch = client.send_batch(
|
|
122
|
+
emails=[
|
|
123
|
+
SendEmailParams(
|
|
124
|
+
from_address="noreply@yourdomain.com",
|
|
125
|
+
to="user1@example.com",
|
|
126
|
+
subject="Hello User 1",
|
|
127
|
+
text_body="Welcome aboard!",
|
|
128
|
+
),
|
|
129
|
+
SendEmailParams(
|
|
130
|
+
from_address="noreply@yourdomain.com",
|
|
131
|
+
to="user2@example.com",
|
|
132
|
+
subject="Hello User 2",
|
|
133
|
+
text_body="Welcome aboard!",
|
|
134
|
+
),
|
|
135
|
+
]
|
|
136
|
+
)
|
|
137
|
+
print(f"Sent: {len(batch.data)}, Errors: {len(batch.errors)}")
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Idempotent sends
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
client.send_email(
|
|
144
|
+
from_address="noreply@yourdomain.com",
|
|
145
|
+
to="user@example.com",
|
|
146
|
+
subject="Payment Receipt",
|
|
147
|
+
html_body="<p>Payment received.</p>",
|
|
148
|
+
idempotency_key="payment-receipt-12345",
|
|
149
|
+
)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Retrieve and list emails
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
email = client.get_email("email-uuid")
|
|
156
|
+
|
|
157
|
+
emails = client.list_emails(page=1, per_page=50, status="delivered")
|
|
158
|
+
for e in emails.data:
|
|
159
|
+
print(f"{e.to_address}: {e.status}")
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Domains
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
# Add a sending domain
|
|
166
|
+
domain = client.add_domain("mail.yourdomain.com")
|
|
167
|
+
print("Configure DNS records:", domain.dns_records)
|
|
168
|
+
|
|
169
|
+
# Trigger verification
|
|
170
|
+
verification = client.verify_domain(domain.id)
|
|
171
|
+
if verification.fully_verified:
|
|
172
|
+
print("Domain verified! SPF, DKIM, DMARC, and return-path all confirmed.")
|
|
173
|
+
|
|
174
|
+
# List all domains
|
|
175
|
+
domains = client.list_domains(page=1, per_page=25)
|
|
176
|
+
|
|
177
|
+
# Remove a domain
|
|
178
|
+
client.delete_domain(domain.id)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Templates
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
# Create a template with Jinja2-style variables
|
|
185
|
+
template = client.create_template(
|
|
186
|
+
alias="welcome-email",
|
|
187
|
+
name="Welcome Email",
|
|
188
|
+
subject="Welcome, {{ name }}!",
|
|
189
|
+
html_body="<h1>Hello {{ name }}</h1><p>Welcome to {{ company }}.</p>",
|
|
190
|
+
text_body="Hello {{ name }}, welcome to {{ company }}.",
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Update a template
|
|
194
|
+
client.update_template(template.id, subject="Welcome to {{ company }}, {{ name }}!")
|
|
195
|
+
|
|
196
|
+
# List and delete
|
|
197
|
+
templates = client.list_templates(page=1, per_page=25)
|
|
198
|
+
client.delete_template(template.id)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Webhooks
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
# Subscribe to delivery events
|
|
205
|
+
webhook = client.create_webhook(
|
|
206
|
+
url="https://yourdomain.com/webhooks/euromail",
|
|
207
|
+
events=["delivered", "bounced", "complained", "email.inbound"],
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# Update webhook
|
|
211
|
+
client.update_webhook(
|
|
212
|
+
webhook.id,
|
|
213
|
+
url="https://yourdomain.com/webhooks/v2",
|
|
214
|
+
events=["delivered", "bounced"],
|
|
215
|
+
is_active=True,
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# Send a test event
|
|
219
|
+
test = client.test_webhook(webhook.id)
|
|
220
|
+
|
|
221
|
+
# List and delete
|
|
222
|
+
webhooks = client.list_webhooks()
|
|
223
|
+
client.delete_webhook(webhook.id)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Supported events: `sent`, `delivered`, `bounced`, `opened`, `clicked`, `complained`, `email.inbound`
|
|
227
|
+
|
|
228
|
+
## Suppressions
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
# Suppress an address manually
|
|
232
|
+
client.add_suppression("bounced@example.com", reason="hard_bounce")
|
|
233
|
+
|
|
234
|
+
# List all suppressions
|
|
235
|
+
suppressions = client.list_suppressions(page=1, per_page=50)
|
|
236
|
+
|
|
237
|
+
# Remove a suppression
|
|
238
|
+
client.delete_suppression("bounced@example.com")
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Contact Lists
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
# Create a list with double opt-in
|
|
245
|
+
contact_list = client.create_contact_list(
|
|
246
|
+
name="Newsletter",
|
|
247
|
+
description="Monthly product updates",
|
|
248
|
+
double_opt_in=True,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
# Add a single contact
|
|
252
|
+
contact = client.add_contact(
|
|
253
|
+
contact_list.id,
|
|
254
|
+
email="user@example.com",
|
|
255
|
+
metadata={"first_name": "Jane", "source": "signup"},
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
# Bulk add contacts
|
|
259
|
+
result = client.bulk_add_contacts(
|
|
260
|
+
contact_list.id,
|
|
261
|
+
contacts=[
|
|
262
|
+
{"email": "a@example.com", "metadata": {"name": "Alice"}},
|
|
263
|
+
{"email": "b@example.com", "metadata": {"name": "Bob"}},
|
|
264
|
+
],
|
|
265
|
+
)
|
|
266
|
+
print(f"Inserted: {result.inserted} of {result.total_requested}")
|
|
267
|
+
|
|
268
|
+
# List contacts with filters
|
|
269
|
+
contacts = client.list_contacts(contact_list.id, page=1, per_page=50, status="active")
|
|
270
|
+
|
|
271
|
+
# Remove contact and delete list
|
|
272
|
+
client.remove_contact(contact_list.id, "user@example.com")
|
|
273
|
+
client.delete_contact_list(contact_list.id)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Inbound Email
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
# List received emails
|
|
280
|
+
inbound = client.list_inbound_emails(page=1, per_page=25)
|
|
281
|
+
|
|
282
|
+
# Get details
|
|
283
|
+
email = client.get_inbound_email("inbound-uuid")
|
|
284
|
+
print(f"From: {email.from_address}, Subject: {email.subject}")
|
|
285
|
+
|
|
286
|
+
# Delete
|
|
287
|
+
client.delete_inbound_email("inbound-uuid")
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Inbound Routes
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
# Route incoming email to a webhook
|
|
294
|
+
route = client.create_inbound_route(
|
|
295
|
+
domain_id="domain-uuid",
|
|
296
|
+
pattern="support@",
|
|
297
|
+
match_type="prefix",
|
|
298
|
+
priority=10,
|
|
299
|
+
webhook_url="https://yourdomain.com/inbound/support",
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
# Update a route
|
|
303
|
+
client.update_inbound_route(route.id, webhook_url="https://yourdomain.com/inbound/v2", is_active=True)
|
|
304
|
+
|
|
305
|
+
# Catch-all route
|
|
306
|
+
client.create_inbound_route(
|
|
307
|
+
domain_id="domain-uuid",
|
|
308
|
+
pattern="*",
|
|
309
|
+
match_type="catch_all",
|
|
310
|
+
priority=100,
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
# List and delete
|
|
314
|
+
routes = client.list_inbound_routes()
|
|
315
|
+
client.delete_inbound_route(route.id)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Analytics
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
# Overview for the last 30 days
|
|
322
|
+
overview = client.get_analytics_overview(period="30d")
|
|
323
|
+
print(f"Delivery rate: {overview.delivery_rate}%")
|
|
324
|
+
|
|
325
|
+
# Custom date range
|
|
326
|
+
custom = client.get_analytics_overview(from_date="2025-01-01", to_date="2025-01-31")
|
|
327
|
+
|
|
328
|
+
# Time series data
|
|
329
|
+
timeseries = client.get_analytics_timeseries(period="7d", metrics=["sent", "delivered", "bounced"])
|
|
330
|
+
|
|
331
|
+
# Per-domain breakdown
|
|
332
|
+
domains = client.get_analytics_domains(period="30d", limit=10)
|
|
333
|
+
|
|
334
|
+
# Export as CSV
|
|
335
|
+
csv_data = client.export_analytics_csv(period="30d")
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Account
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
account = client.get_account()
|
|
342
|
+
print(f"Plan: {account.plan}, Used: {account.emails_sent_this_month}/{account.monthly_quota}")
|
|
343
|
+
|
|
344
|
+
# Export all account data (GDPR)
|
|
345
|
+
export_data = client.export_account()
|
|
346
|
+
|
|
347
|
+
# Delete account permanently
|
|
348
|
+
client.delete_account()
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Audit Logs
|
|
352
|
+
|
|
353
|
+
```python
|
|
354
|
+
logs = client.list_audit_logs(page=1, per_page=50)
|
|
355
|
+
for log in logs.data:
|
|
356
|
+
print(f"{log.created_at}: {log.action} on {log.resource_type}")
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Dead Letters
|
|
360
|
+
|
|
361
|
+
```python
|
|
362
|
+
# List failed emails
|
|
363
|
+
dead_letters = client.list_dead_letters(count=20)
|
|
364
|
+
|
|
365
|
+
# Retry delivery
|
|
366
|
+
client.retry_dead_letter("dead-letter-uuid")
|
|
367
|
+
|
|
368
|
+
# Remove permanently
|
|
369
|
+
client.delete_dead_letter("dead-letter-uuid")
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## Error Handling
|
|
373
|
+
|
|
374
|
+
All API errors raise typed exceptions:
|
|
375
|
+
|
|
376
|
+
```python
|
|
377
|
+
from euromail import (
|
|
378
|
+
EuroMail,
|
|
379
|
+
EuroMailError,
|
|
380
|
+
AuthenticationError,
|
|
381
|
+
RateLimitError,
|
|
382
|
+
ValidationError,
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
try:
|
|
386
|
+
client.send_email(...)
|
|
387
|
+
except AuthenticationError:
|
|
388
|
+
# Invalid or missing API key (401)
|
|
389
|
+
print("Check your API key")
|
|
390
|
+
except ValidationError as e:
|
|
391
|
+
# Invalid request parameters (422)
|
|
392
|
+
print(f"{e.code}: {e.message}")
|
|
393
|
+
except RateLimitError as e:
|
|
394
|
+
# Too many requests (429)
|
|
395
|
+
print(f"Retry after {e.retry_after} seconds")
|
|
396
|
+
except EuroMailError as e:
|
|
397
|
+
# Other API errors (4xx/5xx)
|
|
398
|
+
print(f"[{e.status}] {e.code}: {e.message}")
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
| Exception | HTTP Status | Description |
|
|
402
|
+
|---|---|---|
|
|
403
|
+
| `AuthenticationError` | 401 | Invalid or missing API key |
|
|
404
|
+
| `ValidationError` | 422 | Invalid request parameters |
|
|
405
|
+
| `RateLimitError` | 429 | Too many requests (includes `retry_after`) |
|
|
406
|
+
| `EuroMailError` | 4xx/5xx | Base class for all API errors |
|
|
407
|
+
|
|
408
|
+
## API Reference
|
|
409
|
+
|
|
410
|
+
| Category | Method | Description |
|
|
411
|
+
|---|---|---|
|
|
412
|
+
| **Emails** | `send_email(...)` | Send a single email |
|
|
413
|
+
| | `send_batch(emails=...)` | Send up to 500 emails in one request |
|
|
414
|
+
| | `get_email(id)` | Get email details and status |
|
|
415
|
+
| | `list_emails(...)` | List emails with pagination and status filter |
|
|
416
|
+
| **Templates** | `create_template(...)` | Create an email template |
|
|
417
|
+
| | `get_template(id)` | Get template by ID |
|
|
418
|
+
| | `update_template(id, ...)` | Update template fields |
|
|
419
|
+
| | `delete_template(id)` | Delete a template |
|
|
420
|
+
| | `list_templates(...)` | List templates with pagination |
|
|
421
|
+
| **Domains** | `add_domain(domain)` | Register a sending domain |
|
|
422
|
+
| | `get_domain(id)` | Get domain details and DNS records |
|
|
423
|
+
| | `verify_domain(id)` | Trigger DNS verification |
|
|
424
|
+
| | `delete_domain(id)` | Remove a domain |
|
|
425
|
+
| | `list_domains(...)` | List domains with pagination |
|
|
426
|
+
| **Webhooks** | `create_webhook(...)` | Subscribe to events |
|
|
427
|
+
| | `get_webhook(id)` | Get webhook details |
|
|
428
|
+
| | `update_webhook(id, ...)` | Update URL, events, or status |
|
|
429
|
+
| | `test_webhook(id)` | Send a test event |
|
|
430
|
+
| | `delete_webhook(id)` | Remove a webhook |
|
|
431
|
+
| | `list_webhooks(...)` | List webhooks with pagination |
|
|
432
|
+
| **Suppressions** | `add_suppression(email, ...)` | Suppress an email address |
|
|
433
|
+
| | `delete_suppression(email)` | Remove a suppression |
|
|
434
|
+
| | `list_suppressions(...)` | List suppressions with pagination |
|
|
435
|
+
| **Contact Lists** | `create_contact_list(...)` | Create a contact list |
|
|
436
|
+
| | `get_contact_list(id)` | Get list details |
|
|
437
|
+
| | `update_contact_list(id, ...)` | Update list settings |
|
|
438
|
+
| | `delete_contact_list(id)` | Delete a list |
|
|
439
|
+
| | `list_contact_lists()` | List all contact lists |
|
|
440
|
+
| | `add_contact(list_id, ...)` | Add a contact to a list |
|
|
441
|
+
| | `bulk_add_contacts(list_id, ...)` | Add multiple contacts |
|
|
442
|
+
| | `list_contacts(list_id, ...)` | List contacts with filters |
|
|
443
|
+
| | `remove_contact(list_id, email)` | Remove a contact |
|
|
444
|
+
| **Inbound** | `list_inbound_emails(...)` | List received emails |
|
|
445
|
+
| | `get_inbound_email(id)` | Get inbound email details |
|
|
446
|
+
| | `delete_inbound_email(id)` | Delete an inbound email |
|
|
447
|
+
| **Inbound Routes** | `create_inbound_route(...)` | Create a routing rule |
|
|
448
|
+
| | `get_inbound_route(id)` | Get route details |
|
|
449
|
+
| | `update_inbound_route(id, ...)` | Update a route |
|
|
450
|
+
| | `delete_inbound_route(id)` | Delete a route |
|
|
451
|
+
| | `list_inbound_routes(...)` | List routes with pagination |
|
|
452
|
+
| **Analytics** | `get_analytics_overview(...)` | Aggregated delivery stats |
|
|
453
|
+
| | `get_analytics_timeseries(...)` | Daily metrics over time |
|
|
454
|
+
| | `get_analytics_domains(...)` | Per-domain breakdown |
|
|
455
|
+
| | `export_analytics_csv(...)` | Export stats as CSV |
|
|
456
|
+
| **Audit Logs** | `list_audit_logs(...)` | List account activity |
|
|
457
|
+
| **Dead Letters** | `list_dead_letters(...)` | List permanently failed emails |
|
|
458
|
+
| | `retry_dead_letter(id)` | Retry delivery |
|
|
459
|
+
| | `delete_dead_letter(id)` | Remove from dead letter queue |
|
|
460
|
+
| **Account** | `get_account()` | Get account info and quota |
|
|
461
|
+
| | `export_account()` | Export all account data |
|
|
462
|
+
| | `delete_account()` | Permanently delete account |
|
|
463
|
+
|
|
464
|
+
## Requirements
|
|
465
|
+
|
|
466
|
+
- Python 3.9+
|
|
467
|
+
- httpx >= 0.27
|
|
468
|
+
|
|
469
|
+
## License
|
|
470
|
+
|
|
471
|
+
MIT
|
|
472
|
+
|