emailit 2.0.1__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.
- emailit-2.0.1/LICENSE +21 -0
- emailit-2.0.1/PKG-INFO +574 -0
- emailit-2.0.1/README.md +541 -0
- emailit-2.0.1/pyproject.toml +50 -0
- emailit-2.0.1/setup.cfg +4 -0
- emailit-2.0.1/src/emailit/__init__.py +65 -0
- emailit-2.0.1/src/emailit/_api_resource.py +27 -0
- emailit-2.0.1/src/emailit/_api_response.py +23 -0
- emailit-2.0.1/src/emailit/_base_client.py +125 -0
- emailit-2.0.1/src/emailit/_client.py +77 -0
- emailit-2.0.1/src/emailit/_collection.py +20 -0
- emailit-2.0.1/src/emailit/_emailit_object.py +84 -0
- emailit-2.0.1/src/emailit/_util.py +55 -0
- emailit-2.0.1/src/emailit/_webhook_signature.py +67 -0
- emailit-2.0.1/src/emailit/events/__init__.py +77 -0
- emailit-2.0.1/src/emailit/events/audience_created.py +5 -0
- emailit-2.0.1/src/emailit/events/audience_deleted.py +5 -0
- emailit-2.0.1/src/emailit/events/audience_updated.py +5 -0
- emailit-2.0.1/src/emailit/events/contact_created.py +5 -0
- emailit-2.0.1/src/emailit/events/contact_deleted.py +5 -0
- emailit-2.0.1/src/emailit/events/contact_updated.py +5 -0
- emailit-2.0.1/src/emailit/events/domain_created.py +5 -0
- emailit-2.0.1/src/emailit/events/domain_deleted.py +5 -0
- emailit-2.0.1/src/emailit/events/domain_updated.py +5 -0
- emailit-2.0.1/src/emailit/events/email_accepted.py +5 -0
- emailit-2.0.1/src/emailit/events/email_attempted.py +5 -0
- emailit-2.0.1/src/emailit/events/email_bounced.py +5 -0
- emailit-2.0.1/src/emailit/events/email_clicked.py +5 -0
- emailit-2.0.1/src/emailit/events/email_complained.py +5 -0
- emailit-2.0.1/src/emailit/events/email_delivered.py +5 -0
- emailit-2.0.1/src/emailit/events/email_failed.py +5 -0
- emailit-2.0.1/src/emailit/events/email_loaded.py +5 -0
- emailit-2.0.1/src/emailit/events/email_received.py +5 -0
- emailit-2.0.1/src/emailit/events/email_rejected.py +5 -0
- emailit-2.0.1/src/emailit/events/email_scheduled.py +5 -0
- emailit-2.0.1/src/emailit/events/email_suppressed.py +5 -0
- emailit-2.0.1/src/emailit/events/email_verification_created.py +5 -0
- emailit-2.0.1/src/emailit/events/email_verification_deleted.py +5 -0
- emailit-2.0.1/src/emailit/events/email_verification_list_created.py +5 -0
- emailit-2.0.1/src/emailit/events/email_verification_list_deleted.py +5 -0
- emailit-2.0.1/src/emailit/events/email_verification_list_updated.py +5 -0
- emailit-2.0.1/src/emailit/events/email_verification_updated.py +5 -0
- emailit-2.0.1/src/emailit/events/subscriber_created.py +5 -0
- emailit-2.0.1/src/emailit/events/subscriber_deleted.py +5 -0
- emailit-2.0.1/src/emailit/events/subscriber_updated.py +5 -0
- emailit-2.0.1/src/emailit/events/suppression_created.py +5 -0
- emailit-2.0.1/src/emailit/events/suppression_deleted.py +5 -0
- emailit-2.0.1/src/emailit/events/suppression_updated.py +5 -0
- emailit-2.0.1/src/emailit/events/template_created.py +5 -0
- emailit-2.0.1/src/emailit/events/template_deleted.py +5 -0
- emailit-2.0.1/src/emailit/events/template_updated.py +5 -0
- emailit-2.0.1/src/emailit/events/webhook_event.py +109 -0
- emailit-2.0.1/src/emailit/exceptions/__init__.py +15 -0
- emailit-2.0.1/src/emailit/exceptions/api_connection.py +5 -0
- emailit-2.0.1/src/emailit/exceptions/api_error.py +44 -0
- emailit-2.0.1/src/emailit/exceptions/authentication.py +5 -0
- emailit-2.0.1/src/emailit/exceptions/invalid_request.py +5 -0
- emailit-2.0.1/src/emailit/exceptions/rate_limit.py +5 -0
- emailit-2.0.1/src/emailit/exceptions/unprocessable_entity.py +5 -0
- emailit-2.0.1/src/emailit/resources/__init__.py +27 -0
- emailit-2.0.1/src/emailit/resources/api_key.py +5 -0
- emailit-2.0.1/src/emailit/resources/audience.py +5 -0
- emailit-2.0.1/src/emailit/resources/contact.py +5 -0
- emailit-2.0.1/src/emailit/resources/domain.py +5 -0
- emailit-2.0.1/src/emailit/resources/email.py +5 -0
- emailit-2.0.1/src/emailit/resources/email_verification.py +5 -0
- emailit-2.0.1/src/emailit/resources/email_verification_list.py +5 -0
- emailit-2.0.1/src/emailit/resources/event.py +5 -0
- emailit-2.0.1/src/emailit/resources/subscriber.py +5 -0
- emailit-2.0.1/src/emailit/resources/suppression.py +5 -0
- emailit-2.0.1/src/emailit/resources/template.py +5 -0
- emailit-2.0.1/src/emailit/resources/webhook.py +5 -0
- emailit-2.0.1/src/emailit/services/__init__.py +27 -0
- emailit-2.0.1/src/emailit/services/_abstract_service.py +63 -0
- emailit-2.0.1/src/emailit/services/api_key_service.py +25 -0
- emailit-2.0.1/src/emailit/services/audience_service.py +25 -0
- emailit-2.0.1/src/emailit/services/contact_service.py +25 -0
- emailit-2.0.1/src/emailit/services/domain_service.py +28 -0
- emailit-2.0.1/src/emailit/services/email_service.py +40 -0
- emailit-2.0.1/src/emailit/services/email_verification_list_service.py +33 -0
- emailit-2.0.1/src/emailit/services/email_verification_service.py +12 -0
- emailit-2.0.1/src/emailit/services/event_service.py +16 -0
- emailit-2.0.1/src/emailit/services/subscriber_service.py +43 -0
- emailit-2.0.1/src/emailit/services/suppression_service.py +25 -0
- emailit-2.0.1/src/emailit/services/template_service.py +28 -0
- emailit-2.0.1/src/emailit/services/webhook_service.py +25 -0
- emailit-2.0.1/src/emailit.egg-info/PKG-INFO +574 -0
- emailit-2.0.1/src/emailit.egg-info/SOURCES.txt +107 -0
- emailit-2.0.1/src/emailit.egg-info/dependency_links.txt +1 -0
- emailit-2.0.1/src/emailit.egg-info/requires.txt +5 -0
- emailit-2.0.1/src/emailit.egg-info/top_level.txt +1 -0
- emailit-2.0.1/tests/test_api_key_service.py +83 -0
- emailit-2.0.1/tests/test_api_response.py +29 -0
- emailit-2.0.1/tests/test_audience_service.py +85 -0
- emailit-2.0.1/tests/test_client.py +60 -0
- emailit-2.0.1/tests/test_contact_service.py +84 -0
- emailit-2.0.1/tests/test_domain_service.py +119 -0
- emailit-2.0.1/tests/test_email_service.py +555 -0
- emailit-2.0.1/tests/test_email_verification_list_service.py +129 -0
- emailit-2.0.1/tests/test_email_verification_service.py +47 -0
- emailit-2.0.1/tests/test_event_service.py +60 -0
- emailit-2.0.1/tests/test_exceptions.py +83 -0
- emailit-2.0.1/tests/test_resource.py +210 -0
- emailit-2.0.1/tests/test_subscriber_service.py +109 -0
- emailit-2.0.1/tests/test_suppression_service.py +74 -0
- emailit-2.0.1/tests/test_template_service.py +85 -0
- emailit-2.0.1/tests/test_webhook_event.py +139 -0
- emailit-2.0.1/tests/test_webhook_service.py +80 -0
- emailit-2.0.1/tests/test_webhook_signature.py +118 -0
emailit-2.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Emailit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
emailit-2.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: emailit
|
|
3
|
+
Version: 2.0.1
|
|
4
|
+
Summary: Official Python SDK for the Emailit Email API
|
|
5
|
+
Author-email: Emailit <support@emailit.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://emailit.com
|
|
8
|
+
Project-URL: Documentation, https://emailit.com/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/emailit/emailit-python
|
|
10
|
+
Project-URL: Changelog, https://github.com/emailit/emailit-python/releases
|
|
11
|
+
Keywords: emailit,email,api,sdk
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Communications :: Email
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.7
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: requests>=2.20
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
31
|
+
Requires-Dist: responses>=0.20; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# Emailit Python
|
|
35
|
+
|
|
36
|
+
[](https://github.com/emailit/emailit-python/actions)
|
|
37
|
+
[](https://pypi.org/project/emailit/)
|
|
38
|
+
[](https://github.com/emailit/emailit-python/blob/main/LICENSE)
|
|
39
|
+
|
|
40
|
+
The official Python SDK for the [Emailit](https://emailit.com) Email API.
|
|
41
|
+
|
|
42
|
+
## Requirements
|
|
43
|
+
|
|
44
|
+
- Python 3.7+
|
|
45
|
+
- [Requests](https://requests.readthedocs.io/) 2.20+
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install emailit
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Getting Started
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from emailit import EmailitClient
|
|
57
|
+
|
|
58
|
+
client = EmailitClient("your_api_key")
|
|
59
|
+
|
|
60
|
+
email = client.emails.send({
|
|
61
|
+
"from": "hello@yourdomain.com",
|
|
62
|
+
"to": ["user@example.com"],
|
|
63
|
+
"subject": "Hello from Emailit",
|
|
64
|
+
"html": "<h1>Welcome!</h1><p>Thanks for signing up.</p>",
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
print(email.id) # em_abc123...
|
|
68
|
+
print(email.status) # pending
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
All service methods return typed resource objects (`Email`, `Domain`, `Contact`, etc.) with direct attribute access -- just like the Stripe SDK.
|
|
72
|
+
|
|
73
|
+
## Available Services
|
|
74
|
+
|
|
75
|
+
| Service | Property | Description |
|
|
76
|
+
|---------|----------|-------------|
|
|
77
|
+
| Emails | `client.emails` | Send, list, get, cancel, retry emails |
|
|
78
|
+
| Domains | `client.domains` | Create, verify, list, manage sending domains |
|
|
79
|
+
| API Keys | `client.api_keys` | Create, list, manage API keys |
|
|
80
|
+
| Audiences | `client.audiences` | Create, list, manage audiences |
|
|
81
|
+
| Subscribers | `client.subscribers` | Add, list, manage subscribers in audiences |
|
|
82
|
+
| Templates | `client.templates` | Create, list, publish email templates |
|
|
83
|
+
| Suppressions | `client.suppressions` | Create, list, manage suppressed addresses |
|
|
84
|
+
| Email Verifications | `client.email_verifications` | Verify email addresses |
|
|
85
|
+
| Email Verification Lists | `client.email_verification_lists` | Create, list, get results, export |
|
|
86
|
+
| Webhooks | `client.webhooks` | Create, list, manage webhooks |
|
|
87
|
+
| Contacts | `client.contacts` | Create, list, manage contacts |
|
|
88
|
+
| Events | `client.events` | List and retrieve events |
|
|
89
|
+
|
|
90
|
+
## Usage
|
|
91
|
+
|
|
92
|
+
### Emails
|
|
93
|
+
|
|
94
|
+
#### Send an email
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
email = client.emails.send({
|
|
98
|
+
"from": "hello@yourdomain.com",
|
|
99
|
+
"to": ["user@example.com"],
|
|
100
|
+
"subject": "Hello from Emailit",
|
|
101
|
+
"html": "<h1>Welcome!</h1>",
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
print(email.id)
|
|
105
|
+
print(email.status)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### Send with a template
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
email = client.emails.send({
|
|
112
|
+
"from": "hello@yourdomain.com",
|
|
113
|
+
"to": "user@example.com",
|
|
114
|
+
"template": "welcome_email",
|
|
115
|
+
"variables": {
|
|
116
|
+
"name": "John Doe",
|
|
117
|
+
"company": "Acme Inc",
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Send with attachments
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
import base64
|
|
126
|
+
|
|
127
|
+
email = client.emails.send({
|
|
128
|
+
"from": "invoices@yourdomain.com",
|
|
129
|
+
"to": "customer@example.com",
|
|
130
|
+
"subject": "Your Invoice #12345",
|
|
131
|
+
"html": "<p>Please find your invoice attached.</p>",
|
|
132
|
+
"attachments": [
|
|
133
|
+
{
|
|
134
|
+
"filename": "invoice.pdf",
|
|
135
|
+
"content": base64.b64encode(open("invoice.pdf", "rb").read()).decode(),
|
|
136
|
+
"content_type": "application/pdf",
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### Schedule an email
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
email = client.emails.send({
|
|
146
|
+
"from": "reminders@yourdomain.com",
|
|
147
|
+
"to": "user@example.com",
|
|
148
|
+
"subject": "Appointment Reminder",
|
|
149
|
+
"html": "<p>Your appointment is tomorrow at 2 PM.</p>",
|
|
150
|
+
"scheduled_at": "2026-01-10T09:00:00Z",
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
print(email.status) # scheduled
|
|
154
|
+
print(email.scheduled_at) # 2026-01-10T09:00:00Z
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### List emails
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
emails = client.emails.list({"page": 1, "limit": 10})
|
|
161
|
+
|
|
162
|
+
for email in emails:
|
|
163
|
+
print(f"{email.id} — {email.status}")
|
|
164
|
+
|
|
165
|
+
if emails.has_more():
|
|
166
|
+
# fetch next page
|
|
167
|
+
pass
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### Cancel / Retry
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
client.emails.cancel("em_abc123")
|
|
174
|
+
client.emails.retry("em_abc123")
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
### Domains
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
# Create a domain
|
|
183
|
+
domain = client.domains.create({
|
|
184
|
+
"name": "example.com",
|
|
185
|
+
"track_loads": True,
|
|
186
|
+
"track_clicks": True,
|
|
187
|
+
})
|
|
188
|
+
print(domain.id)
|
|
189
|
+
|
|
190
|
+
# Verify DNS
|
|
191
|
+
domain = client.domains.verify("sd_123")
|
|
192
|
+
|
|
193
|
+
# List all domains
|
|
194
|
+
domains = client.domains.list()
|
|
195
|
+
|
|
196
|
+
# Get a domain
|
|
197
|
+
domain = client.domains.get("sd_123")
|
|
198
|
+
|
|
199
|
+
# Update a domain
|
|
200
|
+
domain = client.domains.update("sd_123", {"track_clicks": False})
|
|
201
|
+
|
|
202
|
+
# Delete a domain
|
|
203
|
+
client.domains.delete("sd_123")
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
### API Keys
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
# Create an API key
|
|
212
|
+
key = client.api_keys.create({
|
|
213
|
+
"name": "Production Key",
|
|
214
|
+
"scope": "full",
|
|
215
|
+
})
|
|
216
|
+
print(key.key) # only available on create
|
|
217
|
+
|
|
218
|
+
# List all API keys
|
|
219
|
+
keys = client.api_keys.list()
|
|
220
|
+
|
|
221
|
+
# Get an API key
|
|
222
|
+
key = client.api_keys.get("ak_123")
|
|
223
|
+
|
|
224
|
+
# Update an API key
|
|
225
|
+
client.api_keys.update("ak_123", {"name": "Renamed Key"})
|
|
226
|
+
|
|
227
|
+
# Delete an API key
|
|
228
|
+
client.api_keys.delete("ak_123")
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
### Audiences
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
# Create an audience
|
|
237
|
+
audience = client.audiences.create({"name": "Newsletter"})
|
|
238
|
+
print(audience.id)
|
|
239
|
+
print(audience.token)
|
|
240
|
+
|
|
241
|
+
# List audiences
|
|
242
|
+
audiences = client.audiences.list()
|
|
243
|
+
|
|
244
|
+
# Get an audience
|
|
245
|
+
audience = client.audiences.get("aud_123")
|
|
246
|
+
|
|
247
|
+
# Update an audience
|
|
248
|
+
client.audiences.update("aud_123", {"name": "Updated Newsletter"})
|
|
249
|
+
|
|
250
|
+
# Delete an audience
|
|
251
|
+
client.audiences.delete("aud_123")
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
### Subscribers
|
|
257
|
+
|
|
258
|
+
Subscribers belong to an audience, so the audience ID is always the first argument.
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
# Add a subscriber
|
|
262
|
+
subscriber = client.subscribers.create("aud_123", {
|
|
263
|
+
"email": "user@example.com",
|
|
264
|
+
"first_name": "John",
|
|
265
|
+
"last_name": "Doe",
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
# List subscribers in an audience
|
|
269
|
+
subscribers = client.subscribers.list("aud_123")
|
|
270
|
+
|
|
271
|
+
# Get a subscriber
|
|
272
|
+
subscriber = client.subscribers.get("aud_123", "sub_456")
|
|
273
|
+
|
|
274
|
+
# Update a subscriber
|
|
275
|
+
client.subscribers.update("aud_123", "sub_456", {
|
|
276
|
+
"first_name": "Jane",
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
# Delete a subscriber
|
|
280
|
+
client.subscribers.delete("aud_123", "sub_456")
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
### Templates
|
|
286
|
+
|
|
287
|
+
```python
|
|
288
|
+
# Create a template
|
|
289
|
+
result = client.templates.create({
|
|
290
|
+
"name": "Welcome",
|
|
291
|
+
"subject": "Welcome!",
|
|
292
|
+
"html": "<h1>Hi {{name}}</h1>",
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
# List templates
|
|
296
|
+
templates = client.templates.list()
|
|
297
|
+
|
|
298
|
+
# Get a template
|
|
299
|
+
template = client.templates.get("tem_123")
|
|
300
|
+
|
|
301
|
+
# Update a template
|
|
302
|
+
client.templates.update("tem_123", {"subject": "New Subject"})
|
|
303
|
+
|
|
304
|
+
# Publish a template
|
|
305
|
+
client.templates.publish("tem_123")
|
|
306
|
+
|
|
307
|
+
# Delete a template
|
|
308
|
+
client.templates.delete("tem_123")
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
### Suppressions
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
# Create a suppression
|
|
317
|
+
suppression = client.suppressions.create({
|
|
318
|
+
"email": "spam@example.com",
|
|
319
|
+
"type": "hard_bounce",
|
|
320
|
+
"reason": "Manual suppression",
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
# List suppressions
|
|
324
|
+
suppressions = client.suppressions.list()
|
|
325
|
+
|
|
326
|
+
# Get a suppression
|
|
327
|
+
suppression = client.suppressions.get("sup_123")
|
|
328
|
+
|
|
329
|
+
# Update a suppression
|
|
330
|
+
client.suppressions.update("sup_123", {"reason": "Updated"})
|
|
331
|
+
|
|
332
|
+
# Delete a suppression
|
|
333
|
+
client.suppressions.delete("sup_123")
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
### Email Verifications
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
result = client.email_verifications.verify({
|
|
342
|
+
"email": "test@example.com",
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
print(result.status) # valid
|
|
346
|
+
print(result.score) # 0.95
|
|
347
|
+
print(result.risk) # low
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
### Email Verification Lists
|
|
353
|
+
|
|
354
|
+
```python
|
|
355
|
+
# Create a verification list
|
|
356
|
+
vlist = client.email_verification_lists.create({
|
|
357
|
+
"name": "Marketing List Q1",
|
|
358
|
+
"emails": [
|
|
359
|
+
"user1@example.com",
|
|
360
|
+
"user2@example.com",
|
|
361
|
+
"user3@example.com",
|
|
362
|
+
],
|
|
363
|
+
})
|
|
364
|
+
print(vlist.id) # evl_abc123...
|
|
365
|
+
print(vlist.status) # pending
|
|
366
|
+
|
|
367
|
+
# List all verification lists
|
|
368
|
+
vlists = client.email_verification_lists.list()
|
|
369
|
+
|
|
370
|
+
# Get a verification list
|
|
371
|
+
vlist = client.email_verification_lists.get("evl_abc123")
|
|
372
|
+
print(vlist.stats["successful_verifications"])
|
|
373
|
+
|
|
374
|
+
# Get verification results
|
|
375
|
+
results = client.email_verification_lists.results("evl_abc123", {"page": 1, "limit": 50})
|
|
376
|
+
|
|
377
|
+
for result in results:
|
|
378
|
+
print(f"{result.email} — {result.result}")
|
|
379
|
+
|
|
380
|
+
# Export results as XLSX
|
|
381
|
+
response = client.email_verification_lists.export("evl_abc123")
|
|
382
|
+
with open("results.xlsx", "wb") as f:
|
|
383
|
+
f.write(response.body.encode())
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
### Webhooks
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
# Create a webhook
|
|
392
|
+
webhook = client.webhooks.create({
|
|
393
|
+
"name": "My Webhook",
|
|
394
|
+
"url": "https://example.com/hook",
|
|
395
|
+
"all_events": True,
|
|
396
|
+
"enabled": True,
|
|
397
|
+
})
|
|
398
|
+
print(webhook.id)
|
|
399
|
+
|
|
400
|
+
# List webhooks
|
|
401
|
+
webhooks = client.webhooks.list()
|
|
402
|
+
|
|
403
|
+
# Get a webhook
|
|
404
|
+
webhook = client.webhooks.get("wh_123")
|
|
405
|
+
|
|
406
|
+
# Update a webhook
|
|
407
|
+
client.webhooks.update("wh_123", {"enabled": False})
|
|
408
|
+
|
|
409
|
+
# Delete a webhook
|
|
410
|
+
client.webhooks.delete("wh_123")
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
### Contacts
|
|
416
|
+
|
|
417
|
+
```python
|
|
418
|
+
# Create a contact
|
|
419
|
+
contact = client.contacts.create({
|
|
420
|
+
"email": "user@example.com",
|
|
421
|
+
"first_name": "John",
|
|
422
|
+
"last_name": "Doe",
|
|
423
|
+
})
|
|
424
|
+
print(contact.id)
|
|
425
|
+
|
|
426
|
+
# List contacts
|
|
427
|
+
contacts = client.contacts.list()
|
|
428
|
+
|
|
429
|
+
# Get a contact
|
|
430
|
+
contact = client.contacts.get("con_123")
|
|
431
|
+
|
|
432
|
+
# Update a contact
|
|
433
|
+
client.contacts.update("con_123", {"first_name": "Jane"})
|
|
434
|
+
|
|
435
|
+
# Delete a contact
|
|
436
|
+
client.contacts.delete("con_123")
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
### Events
|
|
442
|
+
|
|
443
|
+
```python
|
|
444
|
+
# List events
|
|
445
|
+
events = client.events.list({"type": "email.delivered"})
|
|
446
|
+
|
|
447
|
+
for event in events:
|
|
448
|
+
print(event.type)
|
|
449
|
+
|
|
450
|
+
# Get an event
|
|
451
|
+
event = client.events.get("evt_123")
|
|
452
|
+
print(event.type)
|
|
453
|
+
print(event.data["email_id"])
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## Webhook Events
|
|
457
|
+
|
|
458
|
+
The SDK provides typed event classes for all Emailit webhook event types under the `emailit.events` module, plus a `WebhookSignature` class for verifying webhook request signatures.
|
|
459
|
+
|
|
460
|
+
### Verifying Webhook Signatures
|
|
461
|
+
|
|
462
|
+
```python
|
|
463
|
+
from emailit import WebhookSignature, ApiErrorException
|
|
464
|
+
from emailit.events import EmailDelivered
|
|
465
|
+
|
|
466
|
+
raw_body = request.body # raw request body string
|
|
467
|
+
signature = request.headers["x-emailit-signature"]
|
|
468
|
+
timestamp = request.headers["x-emailit-timestamp"]
|
|
469
|
+
secret = "your_webhook_signing_secret"
|
|
470
|
+
|
|
471
|
+
try:
|
|
472
|
+
event = WebhookSignature.verify(raw_body, signature, timestamp, secret)
|
|
473
|
+
|
|
474
|
+
# event is automatically typed based on the event type
|
|
475
|
+
print(event.type) # e.g. "email.delivered"
|
|
476
|
+
print(event.event_id) # e.g. "evt_abc123"
|
|
477
|
+
|
|
478
|
+
# Access the event data
|
|
479
|
+
data = event.get_event_data()
|
|
480
|
+
|
|
481
|
+
if isinstance(event, EmailDelivered):
|
|
482
|
+
# Handle delivered email
|
|
483
|
+
pass
|
|
484
|
+
|
|
485
|
+
except ApiErrorException as e:
|
|
486
|
+
return Response(e.args[0], status=401)
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
You can disable replay protection by passing `tolerance=None`, or set a custom tolerance in seconds:
|
|
490
|
+
|
|
491
|
+
```python
|
|
492
|
+
# Skip replay check
|
|
493
|
+
event = WebhookSignature.verify(raw_body, signature, timestamp, secret, tolerance=None)
|
|
494
|
+
|
|
495
|
+
# Custom 10-minute tolerance
|
|
496
|
+
event = WebhookSignature.verify(raw_body, signature, timestamp, secret, tolerance=600)
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Available Event Types
|
|
500
|
+
|
|
501
|
+
**Emails:** `email.accepted`, `email.scheduled`, `email.delivered`, `email.bounced`, `email.attempted`, `email.failed`, `email.rejected`, `email.suppressed`, `email.received`, `email.complained`, `email.clicked`, `email.loaded`
|
|
502
|
+
|
|
503
|
+
**Domains:** `domain.created`, `domain.updated`, `domain.deleted`
|
|
504
|
+
|
|
505
|
+
**Audiences:** `audience.created`, `audience.updated`, `audience.deleted`
|
|
506
|
+
|
|
507
|
+
**Subscribers:** `subscriber.created`, `subscriber.updated`, `subscriber.deleted`
|
|
508
|
+
|
|
509
|
+
**Contacts:** `contact.created`, `contact.updated`, `contact.deleted`
|
|
510
|
+
|
|
511
|
+
**Templates:** `template.created`, `template.updated`, `template.deleted`
|
|
512
|
+
|
|
513
|
+
**Suppressions:** `suppression.created`, `suppression.updated`, `suppression.deleted`
|
|
514
|
+
|
|
515
|
+
**Email Verifications:** `email_verification.created`, `email_verification.updated`, `email_verification.deleted`
|
|
516
|
+
|
|
517
|
+
**Email Verification Lists:** `email_verification_list.created`, `email_verification_list.updated`, `email_verification_list.deleted`
|
|
518
|
+
|
|
519
|
+
Each event type has a corresponding class under `emailit.events` (e.g. `EmailDelivered`, `DomainCreated`). You can use `isinstance` checks or the `EVENT_TYPE` constant for routing:
|
|
520
|
+
|
|
521
|
+
```python
|
|
522
|
+
from emailit.events import EmailDelivered, EmailBounced, ContactCreated
|
|
523
|
+
|
|
524
|
+
if isinstance(event, EmailDelivered):
|
|
525
|
+
handle_delivered(event)
|
|
526
|
+
elif isinstance(event, EmailBounced):
|
|
527
|
+
handle_bounce(event)
|
|
528
|
+
elif isinstance(event, ContactCreated):
|
|
529
|
+
handle_new_contact(event)
|
|
530
|
+
else:
|
|
531
|
+
print(f"Unhandled: {event.type}")
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
## Error Handling
|
|
535
|
+
|
|
536
|
+
The SDK raises typed exceptions for API errors:
|
|
537
|
+
|
|
538
|
+
```python
|
|
539
|
+
from emailit import (
|
|
540
|
+
ApiErrorException,
|
|
541
|
+
AuthenticationException,
|
|
542
|
+
InvalidRequestException,
|
|
543
|
+
RateLimitException,
|
|
544
|
+
UnprocessableEntityException,
|
|
545
|
+
ApiConnectionException,
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
try:
|
|
549
|
+
client.emails.send({...})
|
|
550
|
+
except AuthenticationException:
|
|
551
|
+
# Invalid API key (401)
|
|
552
|
+
pass
|
|
553
|
+
except InvalidRequestException:
|
|
554
|
+
# Bad request or not found (400, 404)
|
|
555
|
+
pass
|
|
556
|
+
except RateLimitException:
|
|
557
|
+
# Too many requests (429)
|
|
558
|
+
pass
|
|
559
|
+
except UnprocessableEntityException:
|
|
560
|
+
# Validation failed (422)
|
|
561
|
+
pass
|
|
562
|
+
except ApiConnectionException:
|
|
563
|
+
# Network error
|
|
564
|
+
pass
|
|
565
|
+
except ApiErrorException as e:
|
|
566
|
+
# Any other API error
|
|
567
|
+
print(e.http_status)
|
|
568
|
+
print(e.http_body)
|
|
569
|
+
print(e.json_body)
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
## License
|
|
573
|
+
|
|
574
|
+
MIT -- see [LICENSE](LICENSE) for details.
|