deadsimple-email 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.
- deadsimple_email-0.1.0/PKG-INFO +246 -0
- deadsimple_email-0.1.0/README.md +201 -0
- deadsimple_email-0.1.0/pyproject.toml +70 -0
- deadsimple_email-0.1.0/setup.cfg +4 -0
- deadsimple_email-0.1.0/src/deadsimple/__init__.py +45 -0
- deadsimple_email-0.1.0/src/deadsimple/__main__.py +5 -0
- deadsimple_email-0.1.0/src/deadsimple/cli.py +287 -0
- deadsimple_email-0.1.0/src/deadsimple/client.py +952 -0
- deadsimple_email-0.1.0/src/deadsimple/exceptions.py +37 -0
- deadsimple_email-0.1.0/src/deadsimple/integrations/__init__.py +1 -0
- deadsimple_email-0.1.0/src/deadsimple/integrations/autogen.py +141 -0
- deadsimple_email-0.1.0/src/deadsimple/integrations/crewai.py +121 -0
- deadsimple_email-0.1.0/src/deadsimple/integrations/langchain.py +177 -0
- deadsimple_email-0.1.0/src/deadsimple/integrations/llamaindex.py +166 -0
- deadsimple_email-0.1.0/src/deadsimple/integrations/openai_agents.py +254 -0
- deadsimple_email-0.1.0/src/deadsimple/mcp.py +283 -0
- deadsimple_email-0.1.0/src/deadsimple/py.typed +0 -0
- deadsimple_email-0.1.0/src/deadsimple/types.py +427 -0
- deadsimple_email-0.1.0/src/deadsimple/webhooks.py +84 -0
- deadsimple_email-0.1.0/src/deadsimple_email.egg-info/PKG-INFO +246 -0
- deadsimple_email-0.1.0/src/deadsimple_email.egg-info/SOURCES.txt +24 -0
- deadsimple_email-0.1.0/src/deadsimple_email.egg-info/dependency_links.txt +1 -0
- deadsimple_email-0.1.0/src/deadsimple_email.egg-info/entry_points.txt +3 -0
- deadsimple_email-0.1.0/src/deadsimple_email.egg-info/requires.txt +29 -0
- deadsimple_email-0.1.0/src/deadsimple_email.egg-info/top_level.txt +1 -0
- deadsimple_email-0.1.0/tests/test_client.py +301 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: deadsimple-email
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Dead Simple Email — Python SDK for the email API for AI agents
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://deadsimple.email
|
|
7
|
+
Project-URL: Documentation, https://deadsimple.email/docs
|
|
8
|
+
Project-URL: Repository, https://github.com/deadsimple/deadsimple-python
|
|
9
|
+
Project-URL: Changelog, https://github.com/deadsimple/deadsimple-python/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: email,api,ai,agents,sdk,langchain,crewai,mcp
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Communications :: Email
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
Requires-Dist: httpx>=0.25
|
|
25
|
+
Provides-Extra: mcp
|
|
26
|
+
Requires-Dist: mcp>=1.0; extra == "mcp"
|
|
27
|
+
Provides-Extra: langchain
|
|
28
|
+
Requires-Dist: langchain-core>=0.2; extra == "langchain"
|
|
29
|
+
Provides-Extra: crewai
|
|
30
|
+
Requires-Dist: crewai>=0.60; extra == "crewai"
|
|
31
|
+
Provides-Extra: openai-agents
|
|
32
|
+
Requires-Dist: openai-agents>=0.1; extra == "openai-agents"
|
|
33
|
+
Provides-Extra: autogen
|
|
34
|
+
Requires-Dist: pyautogen>=0.2; extra == "autogen"
|
|
35
|
+
Provides-Extra: llamaindex
|
|
36
|
+
Requires-Dist: llama-index-core>=0.10; extra == "llamaindex"
|
|
37
|
+
Provides-Extra: all
|
|
38
|
+
Requires-Dist: deadsimple-email[autogen,crewai,langchain,llamaindex,mcp,openai-agents]; extra == "all"
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
|
|
42
|
+
Requires-Dist: anyio[trio]>=4.0; extra == "dev"
|
|
43
|
+
Requires-Dist: respx>=0.21; extra == "dev"
|
|
44
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
45
|
+
|
|
46
|
+
# Dead Simple Email — Python SDK
|
|
47
|
+
|
|
48
|
+
The official Python SDK for [Dead Simple Email](https://deadsimple.email), the email API for AI agents.
|
|
49
|
+
|
|
50
|
+
- **Typed responses** — dataclass models with IDE autocompletion, not raw dicts
|
|
51
|
+
- **Sync + async** — `DeadSimple` for synchronous code, `AsyncDeadSimple` for async/await
|
|
52
|
+
- **Idempotency** — pass `idempotency_key` to any create/send method for safe retries
|
|
53
|
+
- **Webhook verification** — HMAC-SHA256 signature validation built in
|
|
54
|
+
- **Full API coverage** — inboxes, messages, threads, webhooks, domains, API keys, pods, usage, attachments
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install deadsimple-email
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from deadsimple import DeadSimple
|
|
66
|
+
|
|
67
|
+
client = DeadSimple("dse_your_api_key")
|
|
68
|
+
|
|
69
|
+
# Create an inbox
|
|
70
|
+
inbox = client.inboxes.create(display_name="Support Bot")
|
|
71
|
+
print(f"Inbox: {inbox.email}")
|
|
72
|
+
|
|
73
|
+
# Send an email
|
|
74
|
+
result = client.messages.send(
|
|
75
|
+
inbox_id=inbox.inbox_id,
|
|
76
|
+
to="user@example.com",
|
|
77
|
+
subject="Hello from my AI agent",
|
|
78
|
+
text_body="This email was sent by an AI agent using Dead Simple Email.",
|
|
79
|
+
)
|
|
80
|
+
print(f"Sent: {result.message_id}")
|
|
81
|
+
|
|
82
|
+
# Read received messages
|
|
83
|
+
messages = client.messages.list(inbox_id=inbox.inbox_id)
|
|
84
|
+
for msg in messages.messages:
|
|
85
|
+
print(f" {msg.from_email}: {msg.subject}")
|
|
86
|
+
|
|
87
|
+
# Reply to a message
|
|
88
|
+
client.messages.reply(
|
|
89
|
+
inbox_id=inbox.inbox_id,
|
|
90
|
+
message_id=messages.messages[0].message_id,
|
|
91
|
+
text_body="Thanks for your email!",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# List conversation threads
|
|
95
|
+
threads = client.threads.list(inbox_id=inbox.inbox_id)
|
|
96
|
+
for t in threads.threads:
|
|
97
|
+
print(f" Thread: {t.subject} ({t.message_count} messages)")
|
|
98
|
+
|
|
99
|
+
# Register a webhook for real-time notifications
|
|
100
|
+
webhook = client.webhooks.create(
|
|
101
|
+
url="https://your-app.com/webhook",
|
|
102
|
+
events=["message.received"],
|
|
103
|
+
)
|
|
104
|
+
print(f"Webhook secret: {webhook.signing_secret}")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Async Usage
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from deadsimple import AsyncDeadSimple
|
|
111
|
+
|
|
112
|
+
async with AsyncDeadSimple("dse_your_api_key") as client:
|
|
113
|
+
inbox = await client.inboxes.create(display_name="Async Bot")
|
|
114
|
+
await client.messages.send(
|
|
115
|
+
inbox_id=inbox.inbox_id,
|
|
116
|
+
to="user@example.com",
|
|
117
|
+
subject="Hello from async",
|
|
118
|
+
text_body="Sent asynchronously.",
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Bulk Operations
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
# Create 50 inboxes at once
|
|
126
|
+
result = client.inboxes.bulk_create([
|
|
127
|
+
{"display_name": f"Agent {i}", "tags": ["batch-1"]}
|
|
128
|
+
for i in range(50)
|
|
129
|
+
])
|
|
130
|
+
print(f"Created {result.created}, failed {result.failed}")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Custom Domains
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
# Add your domain
|
|
137
|
+
domain = client.domains.add("mail.yourcompany.com")
|
|
138
|
+
|
|
139
|
+
# Shows DNS records to configure
|
|
140
|
+
for record in domain.dns_records:
|
|
141
|
+
print(f" {record['type']} {record['name']} -> {record['value']}")
|
|
142
|
+
|
|
143
|
+
# Check verification
|
|
144
|
+
status = client.domains.verify(domain.domain_id)
|
|
145
|
+
print(f"Status: {status.status}")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Multi-Tenant Pods
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
# Create an isolated namespace for a customer
|
|
152
|
+
pod = client.pods.create(name="customer-acme", description="Acme Corp")
|
|
153
|
+
print(f"Pod API key: {pod.api_key['key']}")
|
|
154
|
+
|
|
155
|
+
# Use the pod's scoped API key for isolated access
|
|
156
|
+
acme_client = DeadSimple(pod.api_key["key"])
|
|
157
|
+
acme_inbox = acme_client.inboxes.create(display_name="Acme Support")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Idempotent Requests
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
import uuid
|
|
164
|
+
|
|
165
|
+
# Safe to retry — same key = same result, no duplicates
|
|
166
|
+
key = str(uuid.uuid4())
|
|
167
|
+
inbox = client.inboxes.create(display_name="Bot", idempotency_key=key)
|
|
168
|
+
inbox_again = client.inboxes.create(display_name="Bot", idempotency_key=key) # Returns same inbox
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Webhook Signature Verification
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from deadsimple.webhooks import verify_signature
|
|
175
|
+
|
|
176
|
+
# In your webhook handler (e.g., Flask, FastAPI):
|
|
177
|
+
try:
|
|
178
|
+
verify_signature(
|
|
179
|
+
payload=request.body,
|
|
180
|
+
signature=request.headers["X-DSE-Signature"],
|
|
181
|
+
secret="whsec_your_signing_secret",
|
|
182
|
+
)
|
|
183
|
+
# Signature valid — process the event
|
|
184
|
+
except Exception:
|
|
185
|
+
# Signature invalid — reject the request
|
|
186
|
+
return Response(status_code=401)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Usage Metrics
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
usage = client.usage.get()
|
|
193
|
+
print(f"Plan: {usage.plan_name}")
|
|
194
|
+
print(f"Inboxes: {usage.inboxes['used']} / {usage.inboxes['limit']}")
|
|
195
|
+
print(f"Emails this month: {usage.emails['sent_this_month']}")
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Error Handling
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
from deadsimple import DeadSimple, RateLimitError, NotFoundError, ValidationError
|
|
202
|
+
import time
|
|
203
|
+
|
|
204
|
+
client = DeadSimple("dse_your_api_key")
|
|
205
|
+
|
|
206
|
+
try:
|
|
207
|
+
inbox = client.inboxes.get("nonexistent")
|
|
208
|
+
except NotFoundError:
|
|
209
|
+
print("Inbox not found")
|
|
210
|
+
except RateLimitError as e:
|
|
211
|
+
print(f"Rate limited, retry in {e.retry_after}s")
|
|
212
|
+
time.sleep(e.retry_after)
|
|
213
|
+
except ValidationError as e:
|
|
214
|
+
print(f"Bad request: {e.message}")
|
|
215
|
+
for detail in e.details:
|
|
216
|
+
print(f" {detail['field']}: {detail['message']}")
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## All Resources
|
|
220
|
+
|
|
221
|
+
| Resource | Methods |
|
|
222
|
+
|----------|---------|
|
|
223
|
+
| `client.inboxes` | `create`, `bulk_create`, `list`, `get`, `update`, `delete` |
|
|
224
|
+
| `client.messages` | `send`, `list`, `get`, `reply`, `reply_all`, `forward` |
|
|
225
|
+
| `client.threads` | `list`, `get` |
|
|
226
|
+
| `client.webhooks` | `create`, `list`, `delete` |
|
|
227
|
+
| `client.domains` | `add`, `list`, `verify`, `delete` |
|
|
228
|
+
| `client.api_keys` | `create`, `list`, `delete` |
|
|
229
|
+
| `client.pods` | `create`, `list`, `get`, `delete` |
|
|
230
|
+
| `client.usage` | `get` |
|
|
231
|
+
| `client.attachments` | `get_url` |
|
|
232
|
+
|
|
233
|
+
## Pricing
|
|
234
|
+
|
|
235
|
+
| Plan | Price | Inboxes | Emails/mo |
|
|
236
|
+
|------|-------|---------|-----------|
|
|
237
|
+
| Free | $0 | 5 | 5,000 |
|
|
238
|
+
| Hobby | $5/mo | 15 | 15,000 |
|
|
239
|
+
| Pro | $29/mo | 100 | 100,000 |
|
|
240
|
+
| Scale | $99/mo | 500 | 500,000 |
|
|
241
|
+
|
|
242
|
+
Webhook signing included on **all plans** (competitors charge $200/mo).
|
|
243
|
+
|
|
244
|
+
## License
|
|
245
|
+
|
|
246
|
+
MIT
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Dead Simple Email — Python SDK
|
|
2
|
+
|
|
3
|
+
The official Python SDK for [Dead Simple Email](https://deadsimple.email), the email API for AI agents.
|
|
4
|
+
|
|
5
|
+
- **Typed responses** — dataclass models with IDE autocompletion, not raw dicts
|
|
6
|
+
- **Sync + async** — `DeadSimple` for synchronous code, `AsyncDeadSimple` for async/await
|
|
7
|
+
- **Idempotency** — pass `idempotency_key` to any create/send method for safe retries
|
|
8
|
+
- **Webhook verification** — HMAC-SHA256 signature validation built in
|
|
9
|
+
- **Full API coverage** — inboxes, messages, threads, webhooks, domains, API keys, pods, usage, attachments
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install deadsimple-email
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from deadsimple import DeadSimple
|
|
21
|
+
|
|
22
|
+
client = DeadSimple("dse_your_api_key")
|
|
23
|
+
|
|
24
|
+
# Create an inbox
|
|
25
|
+
inbox = client.inboxes.create(display_name="Support Bot")
|
|
26
|
+
print(f"Inbox: {inbox.email}")
|
|
27
|
+
|
|
28
|
+
# Send an email
|
|
29
|
+
result = client.messages.send(
|
|
30
|
+
inbox_id=inbox.inbox_id,
|
|
31
|
+
to="user@example.com",
|
|
32
|
+
subject="Hello from my AI agent",
|
|
33
|
+
text_body="This email was sent by an AI agent using Dead Simple Email.",
|
|
34
|
+
)
|
|
35
|
+
print(f"Sent: {result.message_id}")
|
|
36
|
+
|
|
37
|
+
# Read received messages
|
|
38
|
+
messages = client.messages.list(inbox_id=inbox.inbox_id)
|
|
39
|
+
for msg in messages.messages:
|
|
40
|
+
print(f" {msg.from_email}: {msg.subject}")
|
|
41
|
+
|
|
42
|
+
# Reply to a message
|
|
43
|
+
client.messages.reply(
|
|
44
|
+
inbox_id=inbox.inbox_id,
|
|
45
|
+
message_id=messages.messages[0].message_id,
|
|
46
|
+
text_body="Thanks for your email!",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# List conversation threads
|
|
50
|
+
threads = client.threads.list(inbox_id=inbox.inbox_id)
|
|
51
|
+
for t in threads.threads:
|
|
52
|
+
print(f" Thread: {t.subject} ({t.message_count} messages)")
|
|
53
|
+
|
|
54
|
+
# Register a webhook for real-time notifications
|
|
55
|
+
webhook = client.webhooks.create(
|
|
56
|
+
url="https://your-app.com/webhook",
|
|
57
|
+
events=["message.received"],
|
|
58
|
+
)
|
|
59
|
+
print(f"Webhook secret: {webhook.signing_secret}")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Async Usage
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from deadsimple import AsyncDeadSimple
|
|
66
|
+
|
|
67
|
+
async with AsyncDeadSimple("dse_your_api_key") as client:
|
|
68
|
+
inbox = await client.inboxes.create(display_name="Async Bot")
|
|
69
|
+
await client.messages.send(
|
|
70
|
+
inbox_id=inbox.inbox_id,
|
|
71
|
+
to="user@example.com",
|
|
72
|
+
subject="Hello from async",
|
|
73
|
+
text_body="Sent asynchronously.",
|
|
74
|
+
)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Bulk Operations
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# Create 50 inboxes at once
|
|
81
|
+
result = client.inboxes.bulk_create([
|
|
82
|
+
{"display_name": f"Agent {i}", "tags": ["batch-1"]}
|
|
83
|
+
for i in range(50)
|
|
84
|
+
])
|
|
85
|
+
print(f"Created {result.created}, failed {result.failed}")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Custom Domains
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# Add your domain
|
|
92
|
+
domain = client.domains.add("mail.yourcompany.com")
|
|
93
|
+
|
|
94
|
+
# Shows DNS records to configure
|
|
95
|
+
for record in domain.dns_records:
|
|
96
|
+
print(f" {record['type']} {record['name']} -> {record['value']}")
|
|
97
|
+
|
|
98
|
+
# Check verification
|
|
99
|
+
status = client.domains.verify(domain.domain_id)
|
|
100
|
+
print(f"Status: {status.status}")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Multi-Tenant Pods
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
# Create an isolated namespace for a customer
|
|
107
|
+
pod = client.pods.create(name="customer-acme", description="Acme Corp")
|
|
108
|
+
print(f"Pod API key: {pod.api_key['key']}")
|
|
109
|
+
|
|
110
|
+
# Use the pod's scoped API key for isolated access
|
|
111
|
+
acme_client = DeadSimple(pod.api_key["key"])
|
|
112
|
+
acme_inbox = acme_client.inboxes.create(display_name="Acme Support")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Idempotent Requests
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
import uuid
|
|
119
|
+
|
|
120
|
+
# Safe to retry — same key = same result, no duplicates
|
|
121
|
+
key = str(uuid.uuid4())
|
|
122
|
+
inbox = client.inboxes.create(display_name="Bot", idempotency_key=key)
|
|
123
|
+
inbox_again = client.inboxes.create(display_name="Bot", idempotency_key=key) # Returns same inbox
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Webhook Signature Verification
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from deadsimple.webhooks import verify_signature
|
|
130
|
+
|
|
131
|
+
# In your webhook handler (e.g., Flask, FastAPI):
|
|
132
|
+
try:
|
|
133
|
+
verify_signature(
|
|
134
|
+
payload=request.body,
|
|
135
|
+
signature=request.headers["X-DSE-Signature"],
|
|
136
|
+
secret="whsec_your_signing_secret",
|
|
137
|
+
)
|
|
138
|
+
# Signature valid — process the event
|
|
139
|
+
except Exception:
|
|
140
|
+
# Signature invalid — reject the request
|
|
141
|
+
return Response(status_code=401)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Usage Metrics
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
usage = client.usage.get()
|
|
148
|
+
print(f"Plan: {usage.plan_name}")
|
|
149
|
+
print(f"Inboxes: {usage.inboxes['used']} / {usage.inboxes['limit']}")
|
|
150
|
+
print(f"Emails this month: {usage.emails['sent_this_month']}")
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Error Handling
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from deadsimple import DeadSimple, RateLimitError, NotFoundError, ValidationError
|
|
157
|
+
import time
|
|
158
|
+
|
|
159
|
+
client = DeadSimple("dse_your_api_key")
|
|
160
|
+
|
|
161
|
+
try:
|
|
162
|
+
inbox = client.inboxes.get("nonexistent")
|
|
163
|
+
except NotFoundError:
|
|
164
|
+
print("Inbox not found")
|
|
165
|
+
except RateLimitError as e:
|
|
166
|
+
print(f"Rate limited, retry in {e.retry_after}s")
|
|
167
|
+
time.sleep(e.retry_after)
|
|
168
|
+
except ValidationError as e:
|
|
169
|
+
print(f"Bad request: {e.message}")
|
|
170
|
+
for detail in e.details:
|
|
171
|
+
print(f" {detail['field']}: {detail['message']}")
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## All Resources
|
|
175
|
+
|
|
176
|
+
| Resource | Methods |
|
|
177
|
+
|----------|---------|
|
|
178
|
+
| `client.inboxes` | `create`, `bulk_create`, `list`, `get`, `update`, `delete` |
|
|
179
|
+
| `client.messages` | `send`, `list`, `get`, `reply`, `reply_all`, `forward` |
|
|
180
|
+
| `client.threads` | `list`, `get` |
|
|
181
|
+
| `client.webhooks` | `create`, `list`, `delete` |
|
|
182
|
+
| `client.domains` | `add`, `list`, `verify`, `delete` |
|
|
183
|
+
| `client.api_keys` | `create`, `list`, `delete` |
|
|
184
|
+
| `client.pods` | `create`, `list`, `get`, `delete` |
|
|
185
|
+
| `client.usage` | `get` |
|
|
186
|
+
| `client.attachments` | `get_url` |
|
|
187
|
+
|
|
188
|
+
## Pricing
|
|
189
|
+
|
|
190
|
+
| Plan | Price | Inboxes | Emails/mo |
|
|
191
|
+
|------|-------|---------|-----------|
|
|
192
|
+
| Free | $0 | 5 | 5,000 |
|
|
193
|
+
| Hobby | $5/mo | 15 | 15,000 |
|
|
194
|
+
| Pro | $29/mo | 100 | 100,000 |
|
|
195
|
+
| Scale | $99/mo | 500 | 500,000 |
|
|
196
|
+
|
|
197
|
+
Webhook signing included on **all plans** (competitors charge $200/mo).
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
MIT
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "deadsimple-email"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Dead Simple Email — Python SDK for the email API for AI agents"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.9"
|
|
7
|
+
license = {text = "MIT"}
|
|
8
|
+
keywords = ["email", "api", "ai", "agents", "sdk", "langchain", "crewai", "mcp"]
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 3 - Alpha",
|
|
11
|
+
"Intended Audience :: Developers",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.9",
|
|
15
|
+
"Programming Language :: Python :: 3.10",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Topic :: Communications :: Email",
|
|
20
|
+
"Typing :: Typed",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"httpx>=0.25",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
mcp = ["mcp>=1.0"]
|
|
28
|
+
langchain = ["langchain-core>=0.2"]
|
|
29
|
+
crewai = ["crewai>=0.60"]
|
|
30
|
+
openai-agents = ["openai-agents>=0.1"]
|
|
31
|
+
autogen = ["pyautogen>=0.2"]
|
|
32
|
+
llamaindex = ["llama-index-core>=0.10"]
|
|
33
|
+
all = ["deadsimple-email[mcp,langchain,crewai,openai-agents,autogen,llamaindex]"]
|
|
34
|
+
dev = [
|
|
35
|
+
"pytest>=8.0",
|
|
36
|
+
"pytest-asyncio>=0.24",
|
|
37
|
+
"anyio[trio]>=4.0",
|
|
38
|
+
"respx>=0.21",
|
|
39
|
+
"ruff>=0.5",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Homepage = "https://deadsimple.email"
|
|
44
|
+
Documentation = "https://deadsimple.email/docs"
|
|
45
|
+
Repository = "https://github.com/deadsimple/deadsimple-python"
|
|
46
|
+
Changelog = "https://github.com/deadsimple/deadsimple-python/blob/main/CHANGELOG.md"
|
|
47
|
+
|
|
48
|
+
[project.scripts]
|
|
49
|
+
dse = "deadsimple.cli:main"
|
|
50
|
+
deadsimple-mcp = "deadsimple.mcp:main"
|
|
51
|
+
|
|
52
|
+
[build-system]
|
|
53
|
+
requires = ["setuptools>=68"]
|
|
54
|
+
build-backend = "setuptools.build_meta"
|
|
55
|
+
|
|
56
|
+
[tool.setuptools.packages.find]
|
|
57
|
+
where = ["src"]
|
|
58
|
+
|
|
59
|
+
[tool.setuptools.package-data]
|
|
60
|
+
deadsimple = ["py.typed"]
|
|
61
|
+
|
|
62
|
+
[tool.pytest.ini_options]
|
|
63
|
+
asyncio_mode = "auto"
|
|
64
|
+
|
|
65
|
+
[tool.ruff]
|
|
66
|
+
target-version = "py39"
|
|
67
|
+
line-length = 120
|
|
68
|
+
|
|
69
|
+
[tool.ruff.lint]
|
|
70
|
+
select = ["E", "F", "I", "UP"]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Dead Simple Email — Python SDK for AI agents.
|
|
2
|
+
|
|
3
|
+
Usage::
|
|
4
|
+
|
|
5
|
+
from deadsimple import DeadSimple
|
|
6
|
+
|
|
7
|
+
client = DeadSimple("dse_your_api_key")
|
|
8
|
+
inbox = client.inboxes.create(display_name="My Agent")
|
|
9
|
+
client.messages.send(
|
|
10
|
+
inbox_id=inbox.inbox_id,
|
|
11
|
+
to="user@example.com",
|
|
12
|
+
subject="Hello",
|
|
13
|
+
text_body="Sent by an AI agent.",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
Async usage::
|
|
17
|
+
|
|
18
|
+
from deadsimple import AsyncDeadSimple
|
|
19
|
+
|
|
20
|
+
async with AsyncDeadSimple("dse_your_api_key") as client:
|
|
21
|
+
inbox = await client.inboxes.create(display_name="My Agent")
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from deadsimple.client import AsyncDeadSimple, DeadSimple, WebSocketStream
|
|
25
|
+
from deadsimple.exceptions import (
|
|
26
|
+
AuthenticationError,
|
|
27
|
+
DeadSimpleError,
|
|
28
|
+
NotFoundError,
|
|
29
|
+
RateLimitError,
|
|
30
|
+
ValidationError,
|
|
31
|
+
)
|
|
32
|
+
from deadsimple.types import WebhookEvent
|
|
33
|
+
|
|
34
|
+
__version__ = "0.1.0"
|
|
35
|
+
__all__ = [
|
|
36
|
+
"DeadSimple",
|
|
37
|
+
"AsyncDeadSimple",
|
|
38
|
+
"WebSocketStream",
|
|
39
|
+
"DeadSimpleError",
|
|
40
|
+
"AuthenticationError",
|
|
41
|
+
"NotFoundError",
|
|
42
|
+
"RateLimitError",
|
|
43
|
+
"ValidationError",
|
|
44
|
+
"WebhookEvent",
|
|
45
|
+
]
|