lumbox 0.3.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.
- lumbox-0.3.0/PKG-INFO +134 -0
- lumbox-0.3.0/README.md +109 -0
- lumbox-0.3.0/lumbox/__init__.py +4 -0
- lumbox-0.3.0/lumbox/client.py +389 -0
- lumbox-0.3.0/lumbox/tools.py +255 -0
- lumbox-0.3.0/lumbox.egg-info/PKG-INFO +134 -0
- lumbox-0.3.0/lumbox.egg-info/SOURCES.txt +10 -0
- lumbox-0.3.0/lumbox.egg-info/dependency_links.txt +1 -0
- lumbox-0.3.0/lumbox.egg-info/requires.txt +7 -0
- lumbox-0.3.0/lumbox.egg-info/top_level.txt +1 -0
- lumbox-0.3.0/pyproject.toml +32 -0
- lumbox-0.3.0/setup.cfg +4 -0
lumbox-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lumbox
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Lumbox SDK — Email for AI agents. Create inboxes, receive OTPs, send replies.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://lumbox.co
|
|
7
|
+
Project-URL: Repository, https://github.com/kumard3/agentinbox
|
|
8
|
+
Project-URL: Documentation, https://docs.lumbox.co
|
|
9
|
+
Keywords: email,ai,agents,otp,mcp,lumbox,verification
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
Requires-Dist: httpx>=0.27.0
|
|
21
|
+
Provides-Extra: langchain
|
|
22
|
+
Requires-Dist: langchain-core>=0.3.0; extra == "langchain"
|
|
23
|
+
Provides-Extra: crewai
|
|
24
|
+
Requires-Dist: crewai>=0.80.0; extra == "crewai"
|
|
25
|
+
|
|
26
|
+
# lumbox
|
|
27
|
+
|
|
28
|
+
Email for AI agents. Create inboxes, receive OTPs, extract verification codes — all via API.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install lumbox
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from lumbox import Lumbox
|
|
40
|
+
|
|
41
|
+
client = Lumbox(api_key="ak_...")
|
|
42
|
+
|
|
43
|
+
# Create an inbox
|
|
44
|
+
inbox = client.create_inbox(name="github-bot")
|
|
45
|
+
# → github-bot@lumbox.co
|
|
46
|
+
|
|
47
|
+
# Sign up on any service with inbox.address...
|
|
48
|
+
|
|
49
|
+
# Wait for the OTP (blocks until it arrives)
|
|
50
|
+
otp = inbox.wait_for_otp(timeout=60)
|
|
51
|
+
print(otp["code"]) # "847291"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Auth header
|
|
55
|
+
|
|
56
|
+
The SDK sends `Authorization: Bearer ak_...` by default. The legacy
|
|
57
|
+
`X-API-Key` header still works server-side. Raw HTTP example:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
curl https://api.lumbox.co/v1/inboxes \
|
|
61
|
+
-H "Authorization: Bearer ak_your_key_here"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Inbox-scoped API keys
|
|
65
|
+
|
|
66
|
+
Mint a key that can only ever touch one inbox:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
created = client.inboxes.api_keys.create(inbox.id, name="ci-bot")
|
|
70
|
+
print(created["api_key"]) # shown once
|
|
71
|
+
|
|
72
|
+
client.inboxes.api_keys.list(inbox.id)
|
|
73
|
+
client.inboxes.api_keys.delete(inbox.id, created["id"])
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Features
|
|
77
|
+
|
|
78
|
+
- **OTP extraction** — verification codes parsed automatically
|
|
79
|
+
- **Long-poll** — `wait_for_email()` and `wait_for_otp()` block until arrival
|
|
80
|
+
- **Send/reply/forward** — full outbound email support
|
|
81
|
+
- **Custom domains** — DKIM, SPF, DMARC verification
|
|
82
|
+
- **LangChain & CrewAI** — pre-built tool wrappers
|
|
83
|
+
|
|
84
|
+
## Framework Integration
|
|
85
|
+
|
|
86
|
+
### LangChain
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pip install lumbox[langchain]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from lumbox import create_langchain_tools
|
|
94
|
+
|
|
95
|
+
tools = create_langchain_tools(api_key="ak_...")
|
|
96
|
+
# Use tools directly with LangChain agents
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Any Framework
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from lumbox import lumbox_tools
|
|
103
|
+
|
|
104
|
+
tools = lumbox_tools(api_key="ak_...")
|
|
105
|
+
# Dict of plain functions with proper type hints
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## API
|
|
109
|
+
|
|
110
|
+
### `Lumbox(api_key, base_url?)`
|
|
111
|
+
|
|
112
|
+
Create a client. `base_url` defaults to `https://api.lumbox.co`.
|
|
113
|
+
|
|
114
|
+
### `client.create_inbox(name?, domain?)`
|
|
115
|
+
|
|
116
|
+
Returns an `Inbox` object with `.address`, `.id`, and convenience methods.
|
|
117
|
+
|
|
118
|
+
### `inbox.wait_for_otp(timeout?, sender?)`
|
|
119
|
+
|
|
120
|
+
Blocks until an email with an OTP arrives.
|
|
121
|
+
|
|
122
|
+
### `inbox.wait_for_email(timeout?, sender?, subject?)`
|
|
123
|
+
|
|
124
|
+
Blocks until any email arrives.
|
|
125
|
+
|
|
126
|
+
### `inbox.list_emails()`
|
|
127
|
+
|
|
128
|
+
List all emails in the inbox.
|
|
129
|
+
|
|
130
|
+
Full API docs: [docs.lumbox.co](https://docs.lumbox.co)
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT
|
lumbox-0.3.0/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# lumbox
|
|
2
|
+
|
|
3
|
+
Email for AI agents. Create inboxes, receive OTPs, extract verification codes — all via API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install lumbox
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from lumbox import Lumbox
|
|
15
|
+
|
|
16
|
+
client = Lumbox(api_key="ak_...")
|
|
17
|
+
|
|
18
|
+
# Create an inbox
|
|
19
|
+
inbox = client.create_inbox(name="github-bot")
|
|
20
|
+
# → github-bot@lumbox.co
|
|
21
|
+
|
|
22
|
+
# Sign up on any service with inbox.address...
|
|
23
|
+
|
|
24
|
+
# Wait for the OTP (blocks until it arrives)
|
|
25
|
+
otp = inbox.wait_for_otp(timeout=60)
|
|
26
|
+
print(otp["code"]) # "847291"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Auth header
|
|
30
|
+
|
|
31
|
+
The SDK sends `Authorization: Bearer ak_...` by default. The legacy
|
|
32
|
+
`X-API-Key` header still works server-side. Raw HTTP example:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
curl https://api.lumbox.co/v1/inboxes \
|
|
36
|
+
-H "Authorization: Bearer ak_your_key_here"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Inbox-scoped API keys
|
|
40
|
+
|
|
41
|
+
Mint a key that can only ever touch one inbox:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
created = client.inboxes.api_keys.create(inbox.id, name="ci-bot")
|
|
45
|
+
print(created["api_key"]) # shown once
|
|
46
|
+
|
|
47
|
+
client.inboxes.api_keys.list(inbox.id)
|
|
48
|
+
client.inboxes.api_keys.delete(inbox.id, created["id"])
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- **OTP extraction** — verification codes parsed automatically
|
|
54
|
+
- **Long-poll** — `wait_for_email()` and `wait_for_otp()` block until arrival
|
|
55
|
+
- **Send/reply/forward** — full outbound email support
|
|
56
|
+
- **Custom domains** — DKIM, SPF, DMARC verification
|
|
57
|
+
- **LangChain & CrewAI** — pre-built tool wrappers
|
|
58
|
+
|
|
59
|
+
## Framework Integration
|
|
60
|
+
|
|
61
|
+
### LangChain
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install lumbox[langchain]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from lumbox import create_langchain_tools
|
|
69
|
+
|
|
70
|
+
tools = create_langchain_tools(api_key="ak_...")
|
|
71
|
+
# Use tools directly with LangChain agents
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Any Framework
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from lumbox import lumbox_tools
|
|
78
|
+
|
|
79
|
+
tools = lumbox_tools(api_key="ak_...")
|
|
80
|
+
# Dict of plain functions with proper type hints
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## API
|
|
84
|
+
|
|
85
|
+
### `Lumbox(api_key, base_url?)`
|
|
86
|
+
|
|
87
|
+
Create a client. `base_url` defaults to `https://api.lumbox.co`.
|
|
88
|
+
|
|
89
|
+
### `client.create_inbox(name?, domain?)`
|
|
90
|
+
|
|
91
|
+
Returns an `Inbox` object with `.address`, `.id`, and convenience methods.
|
|
92
|
+
|
|
93
|
+
### `inbox.wait_for_otp(timeout?, sender?)`
|
|
94
|
+
|
|
95
|
+
Blocks until an email with an OTP arrives.
|
|
96
|
+
|
|
97
|
+
### `inbox.wait_for_email(timeout?, sender?, subject?)`
|
|
98
|
+
|
|
99
|
+
Blocks until any email arrives.
|
|
100
|
+
|
|
101
|
+
### `inbox.list_emails()`
|
|
102
|
+
|
|
103
|
+
List all emails in the inbox.
|
|
104
|
+
|
|
105
|
+
Full API docs: [docs.lumbox.co](https://docs.lumbox.co)
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
MIT
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lumbox Python SDK — Email for AI agents.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
from lumbox import Lumbox
|
|
6
|
+
|
|
7
|
+
client = Lumbox(api_key="ak_...")
|
|
8
|
+
inbox = client.create_inbox(name="my-bot")
|
|
9
|
+
otp = inbox.wait_for_otp(sender="github.com", timeout=60)
|
|
10
|
+
print(otp["code"]) # "847291"
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from typing import Any, Optional
|
|
16
|
+
import httpx
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class LumboxError(Exception):
|
|
20
|
+
def __init__(self, status: int, body: Any):
|
|
21
|
+
self.status = status
|
|
22
|
+
self.body = body
|
|
23
|
+
super().__init__(f"API error {status}: {body}")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class Inbox:
|
|
28
|
+
"""Handle to a single agent inbox. Use methods to read emails, wait for OTPs, etc."""
|
|
29
|
+
|
|
30
|
+
id: str
|
|
31
|
+
address: str
|
|
32
|
+
name: Optional[str]
|
|
33
|
+
status: str
|
|
34
|
+
created_at: str
|
|
35
|
+
_client: "Lumbox" = field(repr=False)
|
|
36
|
+
|
|
37
|
+
def list_emails(
|
|
38
|
+
self,
|
|
39
|
+
*,
|
|
40
|
+
sender: Optional[str] = None,
|
|
41
|
+
category: Optional[str] = None,
|
|
42
|
+
since: Optional[str] = None,
|
|
43
|
+
unread: bool = False,
|
|
44
|
+
limit: int = 20,
|
|
45
|
+
) -> dict:
|
|
46
|
+
"""List emails in this inbox."""
|
|
47
|
+
params: dict[str, Any] = {"limit": limit}
|
|
48
|
+
if sender:
|
|
49
|
+
params["from"] = sender
|
|
50
|
+
if category:
|
|
51
|
+
params["category"] = category
|
|
52
|
+
if since:
|
|
53
|
+
params["since"] = since
|
|
54
|
+
if unread:
|
|
55
|
+
params["unread"] = "true"
|
|
56
|
+
return self._client._get(f"/v1/inboxes/{self.id}/emails", params=params)
|
|
57
|
+
|
|
58
|
+
def get_email(self, email_id: str) -> dict:
|
|
59
|
+
"""Get full email content including parsed data."""
|
|
60
|
+
return self._client._get(f"/v1/inboxes/{self.id}/emails/{email_id}")
|
|
61
|
+
|
|
62
|
+
def wait_for_email(
|
|
63
|
+
self,
|
|
64
|
+
*,
|
|
65
|
+
sender: Optional[str] = None,
|
|
66
|
+
subject: Optional[str] = None,
|
|
67
|
+
category: Optional[str] = None,
|
|
68
|
+
has_otp: bool = False,
|
|
69
|
+
timeout: int = 30,
|
|
70
|
+
) -> dict:
|
|
71
|
+
"""
|
|
72
|
+
Block until a matching email arrives. Returns the full parsed email.
|
|
73
|
+
|
|
74
|
+
This is the primary method for AI agents. After signing up on a platform:
|
|
75
|
+
email = inbox.wait_for_email(sender="github.com", timeout=60)
|
|
76
|
+
otp = email["parsed"]["otp_codes"][0]
|
|
77
|
+
"""
|
|
78
|
+
params: dict[str, Any] = {"timeout": timeout}
|
|
79
|
+
if sender:
|
|
80
|
+
params["from"] = sender
|
|
81
|
+
if subject:
|
|
82
|
+
params["subject"] = subject
|
|
83
|
+
if category:
|
|
84
|
+
params["category"] = category
|
|
85
|
+
if has_otp:
|
|
86
|
+
params["has_otp"] = "true"
|
|
87
|
+
return self._client._get(f"/v1/inboxes/{self.id}/wait", params=params)
|
|
88
|
+
|
|
89
|
+
def wait_for_otp(
|
|
90
|
+
self,
|
|
91
|
+
*,
|
|
92
|
+
sender: Optional[str] = None,
|
|
93
|
+
timeout: int = 30,
|
|
94
|
+
) -> dict:
|
|
95
|
+
"""
|
|
96
|
+
Wait for an OTP/verification code. Returns just the code.
|
|
97
|
+
|
|
98
|
+
The simplest way for an agent to get a verification code:
|
|
99
|
+
result = inbox.wait_for_otp(sender="github.com", timeout=60)
|
|
100
|
+
code = result["code"] # "847291"
|
|
101
|
+
"""
|
|
102
|
+
params: dict[str, Any] = {"timeout": timeout}
|
|
103
|
+
if sender:
|
|
104
|
+
params["from"] = sender
|
|
105
|
+
return self._client._get(f"/v1/inboxes/{self.id}/otp", params=params)
|
|
106
|
+
|
|
107
|
+
def delete(self) -> dict:
|
|
108
|
+
"""Delete this inbox and all its emails."""
|
|
109
|
+
return self._client._delete(f"/v1/inboxes/{self.id}")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class Lumbox:
|
|
113
|
+
"""
|
|
114
|
+
Lumbox client — create email inboxes for AI agents.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
api_key: Your Lumbox API key (starts with 'ak_')
|
|
118
|
+
base_url: API base URL (default: https://api.lumbox.co)
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
def __init__(
|
|
122
|
+
self,
|
|
123
|
+
api_key: str,
|
|
124
|
+
base_url: str = "https://api.lumbox.co",
|
|
125
|
+
):
|
|
126
|
+
self._api_key = api_key
|
|
127
|
+
self._base_url = base_url.rstrip("/")
|
|
128
|
+
self._http = httpx.Client(
|
|
129
|
+
base_url=self._base_url,
|
|
130
|
+
headers={
|
|
131
|
+
"Content-Type": "application/json",
|
|
132
|
+
"Authorization": f"Bearer {api_key}",
|
|
133
|
+
},
|
|
134
|
+
timeout=httpx.Timeout(130), # long timeout for /wait endpoints
|
|
135
|
+
)
|
|
136
|
+
self.inboxes = _InboxesNamespace(self)
|
|
137
|
+
|
|
138
|
+
def _get(self, path: str, params: Optional[dict] = None) -> dict:
|
|
139
|
+
resp = self._http.get(path, params=params)
|
|
140
|
+
data = resp.json()
|
|
141
|
+
if not resp.is_success:
|
|
142
|
+
raise LumboxError(resp.status_code, data)
|
|
143
|
+
return data
|
|
144
|
+
|
|
145
|
+
def _post(
|
|
146
|
+
self, path: str, json: Optional[dict] = None, idempotency_key: Optional[str] = None
|
|
147
|
+
) -> dict:
|
|
148
|
+
headers = {"Idempotency-Key": idempotency_key} if idempotency_key else None
|
|
149
|
+
resp = self._http.post(path, json=json or {}, headers=headers)
|
|
150
|
+
data = resp.json()
|
|
151
|
+
if not resp.is_success:
|
|
152
|
+
raise LumboxError(resp.status_code, data)
|
|
153
|
+
return data
|
|
154
|
+
|
|
155
|
+
def _delete(self, path: str) -> dict:
|
|
156
|
+
resp = self._http.delete(path)
|
|
157
|
+
data = resp.json()
|
|
158
|
+
if not resp.is_success:
|
|
159
|
+
raise LumboxError(resp.status_code, data)
|
|
160
|
+
return data
|
|
161
|
+
|
|
162
|
+
def _to_inbox(self, data: dict) -> Inbox:
|
|
163
|
+
return Inbox(
|
|
164
|
+
id=data["id"],
|
|
165
|
+
address=data["address"],
|
|
166
|
+
name=data.get("name"),
|
|
167
|
+
status=data["status"],
|
|
168
|
+
created_at=data["created_at"],
|
|
169
|
+
_client=self,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# --- Inboxes ---
|
|
173
|
+
|
|
174
|
+
def create_inbox(
|
|
175
|
+
self,
|
|
176
|
+
*,
|
|
177
|
+
name: Optional[str] = None,
|
|
178
|
+
domain: Optional[str] = None,
|
|
179
|
+
local_part: Optional[str] = None,
|
|
180
|
+
) -> Inbox:
|
|
181
|
+
"""Create a new email inbox for an AI agent."""
|
|
182
|
+
body: dict[str, Any] = {}
|
|
183
|
+
if name:
|
|
184
|
+
body["name"] = name
|
|
185
|
+
if domain:
|
|
186
|
+
body["domain"] = domain
|
|
187
|
+
if local_part:
|
|
188
|
+
body["local_part"] = local_part
|
|
189
|
+
data = self._post("/v1/inboxes", json=body)
|
|
190
|
+
return self._to_inbox(data)
|
|
191
|
+
|
|
192
|
+
def list_inboxes(self) -> list[Inbox]:
|
|
193
|
+
"""List all inboxes."""
|
|
194
|
+
res = self._get("/v1/inboxes")
|
|
195
|
+
return [self._to_inbox(d) for d in res["data"]]
|
|
196
|
+
|
|
197
|
+
def get_inbox(self, inbox_id: str) -> Inbox:
|
|
198
|
+
"""Get an inbox by ID."""
|
|
199
|
+
data = self._get(f"/v1/inboxes/{inbox_id}")
|
|
200
|
+
return self._to_inbox(data)
|
|
201
|
+
|
|
202
|
+
# --- Domains ---
|
|
203
|
+
|
|
204
|
+
def add_domain(self, domain: str) -> dict:
|
|
205
|
+
"""Add a custom domain. Returns DNS records to configure."""
|
|
206
|
+
return self._post("/v1/domains", json={"domain": domain})
|
|
207
|
+
|
|
208
|
+
def verify_domain(self, domain_id: str) -> dict:
|
|
209
|
+
"""Verify DNS records and activate a domain."""
|
|
210
|
+
return self._post(f"/v1/domains/{domain_id}/verify")
|
|
211
|
+
|
|
212
|
+
def list_domains(self) -> dict:
|
|
213
|
+
"""List all custom domains."""
|
|
214
|
+
return self._get("/v1/domains")
|
|
215
|
+
|
|
216
|
+
# --- Search ---
|
|
217
|
+
|
|
218
|
+
def search_emails(
|
|
219
|
+
self,
|
|
220
|
+
*,
|
|
221
|
+
query: Optional[str] = None,
|
|
222
|
+
sender: Optional[str] = None,
|
|
223
|
+
category: Optional[str] = None,
|
|
224
|
+
inbox_id: Optional[str] = None,
|
|
225
|
+
) -> dict:
|
|
226
|
+
"""Search emails across all inboxes."""
|
|
227
|
+
params: dict[str, Any] = {}
|
|
228
|
+
if query:
|
|
229
|
+
params["q"] = query
|
|
230
|
+
if sender:
|
|
231
|
+
params["from"] = sender
|
|
232
|
+
if category:
|
|
233
|
+
params["category"] = category
|
|
234
|
+
if inbox_id:
|
|
235
|
+
params["inbox_id"] = inbox_id
|
|
236
|
+
return self._get("/v1/emails", params=params)
|
|
237
|
+
|
|
238
|
+
def _patch(self, path: str, json: Optional[dict] = None) -> dict:
|
|
239
|
+
resp = self._http.patch(path, json=json or {})
|
|
240
|
+
data = resp.json()
|
|
241
|
+
if not resp.is_success:
|
|
242
|
+
raise LumboxError(resp.status_code, data)
|
|
243
|
+
return data
|
|
244
|
+
|
|
245
|
+
# --- SMTP Configuration (BYOS) ---
|
|
246
|
+
|
|
247
|
+
def configure_smtp(
|
|
248
|
+
self,
|
|
249
|
+
*,
|
|
250
|
+
provider: str,
|
|
251
|
+
name: Optional[str] = None,
|
|
252
|
+
host: Optional[str] = None,
|
|
253
|
+
port: Optional[int] = None,
|
|
254
|
+
username: Optional[str] = None,
|
|
255
|
+
password: Optional[str] = None,
|
|
256
|
+
api_key: Optional[str] = None,
|
|
257
|
+
region: Optional[str] = None,
|
|
258
|
+
from_email: Optional[str] = None,
|
|
259
|
+
is_default: bool = False,
|
|
260
|
+
) -> dict:
|
|
261
|
+
"""Configure a custom SMTP provider (BYOS)."""
|
|
262
|
+
body: dict[str, Any] = {"provider": provider, "is_default": is_default}
|
|
263
|
+
if name:
|
|
264
|
+
body["name"] = name
|
|
265
|
+
if host:
|
|
266
|
+
body["host"] = host
|
|
267
|
+
if port:
|
|
268
|
+
body["port"] = port
|
|
269
|
+
if username:
|
|
270
|
+
body["username"] = username
|
|
271
|
+
if password:
|
|
272
|
+
body["password"] = password
|
|
273
|
+
if api_key:
|
|
274
|
+
body["api_key"] = api_key
|
|
275
|
+
if region:
|
|
276
|
+
body["region"] = region
|
|
277
|
+
if from_email:
|
|
278
|
+
body["from_email"] = from_email
|
|
279
|
+
return self._post("/v1/smtp-configs", json=body)
|
|
280
|
+
|
|
281
|
+
def list_smtp_configs(self) -> dict:
|
|
282
|
+
"""List all SMTP configurations."""
|
|
283
|
+
return self._get("/v1/smtp-configs")
|
|
284
|
+
|
|
285
|
+
def test_smtp_config(self, config_id: str, to: str) -> dict:
|
|
286
|
+
"""Send a test email through an SMTP config."""
|
|
287
|
+
return self._post(f"/v1/smtp-configs/{config_id}/test", json={"to": to})
|
|
288
|
+
|
|
289
|
+
# --- Thread Routing ---
|
|
290
|
+
|
|
291
|
+
def assign_thread(
|
|
292
|
+
self,
|
|
293
|
+
thread_id: str,
|
|
294
|
+
agent_id: str,
|
|
295
|
+
*,
|
|
296
|
+
role: Optional[str] = None,
|
|
297
|
+
) -> dict:
|
|
298
|
+
"""Assign an agent to a thread."""
|
|
299
|
+
body: dict[str, Any] = {"agent_id": agent_id}
|
|
300
|
+
if role:
|
|
301
|
+
body["role"] = role
|
|
302
|
+
return self._post(f"/v1/threads/{thread_id}/assign", json=body)
|
|
303
|
+
|
|
304
|
+
def unassign_thread(self, thread_id: str, agent_id: str) -> dict:
|
|
305
|
+
"""Unassign an agent from a thread."""
|
|
306
|
+
return self._post(f"/v1/threads/{thread_id}/unassign", json={"agent_id": agent_id})
|
|
307
|
+
|
|
308
|
+
def list_thread_agents(self, thread_id: str) -> dict:
|
|
309
|
+
"""List agents assigned to a thread."""
|
|
310
|
+
return self._get(f"/v1/threads/{thread_id}/agents")
|
|
311
|
+
|
|
312
|
+
def create_routing_rule(
|
|
313
|
+
self,
|
|
314
|
+
*,
|
|
315
|
+
name: str,
|
|
316
|
+
conditions: dict,
|
|
317
|
+
target_agent_id: Optional[str] = None,
|
|
318
|
+
target_inbox_id: Optional[str] = None,
|
|
319
|
+
priority: int = 0,
|
|
320
|
+
) -> dict:
|
|
321
|
+
"""Create an auto-routing rule for thread assignment."""
|
|
322
|
+
body: dict[str, Any] = {
|
|
323
|
+
"name": name,
|
|
324
|
+
"conditions": conditions,
|
|
325
|
+
"priority": priority,
|
|
326
|
+
}
|
|
327
|
+
if target_agent_id:
|
|
328
|
+
body["target_agent_id"] = target_agent_id
|
|
329
|
+
if target_inbox_id:
|
|
330
|
+
body["target_inbox_id"] = target_inbox_id
|
|
331
|
+
return self._post("/v1/routing-rules", json=body)
|
|
332
|
+
|
|
333
|
+
def list_routing_rules(self) -> dict:
|
|
334
|
+
"""List all routing rules."""
|
|
335
|
+
return self._get("/v1/routing-rules")
|
|
336
|
+
|
|
337
|
+
def delete_routing_rule(self, rule_id: str) -> dict:
|
|
338
|
+
"""Delete a routing rule."""
|
|
339
|
+
return self._delete(f"/v1/routing-rules/{rule_id}")
|
|
340
|
+
|
|
341
|
+
# --- Webhooks ---
|
|
342
|
+
|
|
343
|
+
def create_webhook(self, url: str, *, events: Optional[list[str]] = None) -> dict:
|
|
344
|
+
"""Register a webhook URL for real-time notifications."""
|
|
345
|
+
body: dict[str, Any] = {"url": url}
|
|
346
|
+
if events:
|
|
347
|
+
body["events"] = events
|
|
348
|
+
return self._post("/v1/webhooks", json=body)
|
|
349
|
+
|
|
350
|
+
def list_webhooks(self) -> dict:
|
|
351
|
+
"""List all webhooks."""
|
|
352
|
+
return self._get("/v1/webhooks")
|
|
353
|
+
|
|
354
|
+
def test_webhook(self, webhook_id: str) -> dict:
|
|
355
|
+
"""Send a test payload to a webhook."""
|
|
356
|
+
return self._post(f"/v1/webhooks/{webhook_id}/test")
|
|
357
|
+
|
|
358
|
+
def delete_webhook(self, webhook_id: str) -> dict:
|
|
359
|
+
"""Delete a webhook."""
|
|
360
|
+
return self._delete(f"/v1/webhooks/{webhook_id}")
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
class _InboxApiKeys:
|
|
364
|
+
"""Manage API keys scoped to a single inbox."""
|
|
365
|
+
|
|
366
|
+
def __init__(self, client: "Lumbox"):
|
|
367
|
+
self._client = client
|
|
368
|
+
|
|
369
|
+
def create(self, inbox_id: str, *, name: str) -> dict:
|
|
370
|
+
"""Mint a new key locked to this inbox. The plaintext key is returned only once."""
|
|
371
|
+
return self._client._post(
|
|
372
|
+
f"/v1/inboxes/{inbox_id}/api-keys",
|
|
373
|
+
json={"name": name},
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
def list(self, inbox_id: str) -> dict:
|
|
377
|
+
"""List keys scoped to this inbox."""
|
|
378
|
+
return self._client._get(f"/v1/inboxes/{inbox_id}/api-keys")
|
|
379
|
+
|
|
380
|
+
def delete(self, inbox_id: str, key_id: str) -> dict:
|
|
381
|
+
"""Revoke an inbox-scoped key."""
|
|
382
|
+
return self._client._delete(f"/v1/inboxes/{inbox_id}/api-keys/{key_id}")
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
class _InboxesNamespace:
|
|
386
|
+
"""Namespace accessor: ``client.inboxes.api_keys.create(...)``."""
|
|
387
|
+
|
|
388
|
+
def __init__(self, client: "Lumbox"):
|
|
389
|
+
self.api_keys = _InboxApiKeys(client)
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pre-built tool wrappers for popular AI agent frameworks.
|
|
3
|
+
|
|
4
|
+
Works with: LangChain, CrewAI, OpenAI Agents SDK, Vercel AI SDK, LlamaIndex, AutoGen
|
|
5
|
+
|
|
6
|
+
Usage (LangChain):
|
|
7
|
+
from lumbox import create_langchain_tools
|
|
8
|
+
tools = create_langchain_tools(api_key="ak_...")
|
|
9
|
+
|
|
10
|
+
Usage (any framework — raw function tools):
|
|
11
|
+
from lumbox import lumbox_tools
|
|
12
|
+
tools = lumbox_tools(api_key="ak_...")
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
from typing import Optional
|
|
17
|
+
from lumbox.client import Lumbox
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def lumbox_tools(
|
|
21
|
+
api_key: str,
|
|
22
|
+
base_url: str = "https://api.lumbox.co",
|
|
23
|
+
) -> dict:
|
|
24
|
+
"""
|
|
25
|
+
Returns a dict of plain functions that any framework can use as tools.
|
|
26
|
+
Each function has proper type hints and docstrings for schema generation.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
{
|
|
30
|
+
"create_inbox": <function>,
|
|
31
|
+
"wait_for_email": <function>,
|
|
32
|
+
"get_otp": <function>,
|
|
33
|
+
"list_emails": <function>,
|
|
34
|
+
"read_email": <function>,
|
|
35
|
+
"search_emails": <function>,
|
|
36
|
+
"add_domain": <function>,
|
|
37
|
+
"verify_domain": <function>,
|
|
38
|
+
}
|
|
39
|
+
"""
|
|
40
|
+
client = Lumbox(api_key=api_key, base_url=base_url)
|
|
41
|
+
|
|
42
|
+
def create_inbox(name: str = "", domain: str = "") -> str:
|
|
43
|
+
"""Create a new email inbox for an AI agent.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
name: Human-readable name like 'github-signup-bot'. Used as the email local part.
|
|
47
|
+
domain: Custom domain if configured. Leave empty for default domain.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
JSON with inbox id, email address, and status.
|
|
51
|
+
"""
|
|
52
|
+
inbox = client.create_inbox(
|
|
53
|
+
name=name or None,
|
|
54
|
+
domain=domain or None,
|
|
55
|
+
)
|
|
56
|
+
return f'{{"id": "{inbox.id}", "address": "{inbox.address}", "name": "{inbox.name}", "status": "{inbox.status}"}}'
|
|
57
|
+
|
|
58
|
+
def wait_for_email(
|
|
59
|
+
inbox_id: str,
|
|
60
|
+
sender: str = "",
|
|
61
|
+
subject: str = "",
|
|
62
|
+
category: str = "",
|
|
63
|
+
timeout: int = 30,
|
|
64
|
+
) -> str:
|
|
65
|
+
"""Wait for an email to arrive in an inbox. Blocks until received or timeout.
|
|
66
|
+
|
|
67
|
+
Use this after signing up on a platform to get the verification email.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
inbox_id: The inbox ID to watch (e.g., inb_abc123).
|
|
71
|
+
sender: Filter by sender address or domain (e.g., 'github.com').
|
|
72
|
+
subject: Filter by subject keyword.
|
|
73
|
+
category: Filter by category: verification, security, notification, transactional, newsletter.
|
|
74
|
+
timeout: Max seconds to wait (default 30, max 120).
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
JSON with full email data including parsed OTP codes and verification links.
|
|
78
|
+
"""
|
|
79
|
+
import json
|
|
80
|
+
|
|
81
|
+
inbox = client.get_inbox(inbox_id)
|
|
82
|
+
result = inbox.wait_for_email(
|
|
83
|
+
sender=sender or None,
|
|
84
|
+
subject=subject or None,
|
|
85
|
+
category=category or None,
|
|
86
|
+
timeout=timeout,
|
|
87
|
+
)
|
|
88
|
+
return json.dumps(result, indent=2)
|
|
89
|
+
|
|
90
|
+
def get_otp(
|
|
91
|
+
inbox_id: str,
|
|
92
|
+
sender: str = "",
|
|
93
|
+
timeout: int = 30,
|
|
94
|
+
) -> str:
|
|
95
|
+
"""Get the latest OTP/verification code from an inbox. Blocks until one arrives.
|
|
96
|
+
|
|
97
|
+
The simplest way for an agent to get a verification code.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
inbox_id: The inbox ID.
|
|
101
|
+
sender: Filter by sender (e.g., 'github.com').
|
|
102
|
+
timeout: Max seconds to wait (default 30, max 120).
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
JSON with code, sender, subject, and expiry time.
|
|
106
|
+
"""
|
|
107
|
+
import json
|
|
108
|
+
|
|
109
|
+
inbox = client.get_inbox(inbox_id)
|
|
110
|
+
result = inbox.wait_for_otp(sender=sender or None, timeout=timeout)
|
|
111
|
+
return json.dumps(result, indent=2)
|
|
112
|
+
|
|
113
|
+
def list_emails(
|
|
114
|
+
inbox_id: str,
|
|
115
|
+
sender: str = "",
|
|
116
|
+
category: str = "",
|
|
117
|
+
unread: bool = False,
|
|
118
|
+
limit: int = 10,
|
|
119
|
+
) -> str:
|
|
120
|
+
"""List emails in an inbox.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
inbox_id: The inbox ID.
|
|
124
|
+
sender: Filter by sender.
|
|
125
|
+
category: Filter by category.
|
|
126
|
+
unread: Only show unread emails.
|
|
127
|
+
limit: Max emails to return (default 10).
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
JSON array of emails with parsed data.
|
|
131
|
+
"""
|
|
132
|
+
import json
|
|
133
|
+
|
|
134
|
+
inbox = client.get_inbox(inbox_id)
|
|
135
|
+
result = inbox.list_emails(
|
|
136
|
+
sender=sender or None,
|
|
137
|
+
category=category or None,
|
|
138
|
+
unread=unread,
|
|
139
|
+
limit=limit,
|
|
140
|
+
)
|
|
141
|
+
return json.dumps(result, indent=2)
|
|
142
|
+
|
|
143
|
+
def read_email(inbox_id: str, email_id: str) -> str:
|
|
144
|
+
"""Read the full content of a specific email.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
inbox_id: The inbox ID.
|
|
148
|
+
email_id: The email ID.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
JSON with full email content, parsed OTP codes, verification links, and AI summary.
|
|
152
|
+
"""
|
|
153
|
+
import json
|
|
154
|
+
|
|
155
|
+
inbox = client.get_inbox(inbox_id)
|
|
156
|
+
result = inbox.get_email(email_id)
|
|
157
|
+
return json.dumps(result, indent=2)
|
|
158
|
+
|
|
159
|
+
def search_emails(
|
|
160
|
+
query: str = "",
|
|
161
|
+
sender: str = "",
|
|
162
|
+
category: str = "",
|
|
163
|
+
inbox_id: str = "",
|
|
164
|
+
) -> str:
|
|
165
|
+
"""Search emails across all inboxes.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
query: Search query (searches subject, body, summary).
|
|
169
|
+
sender: Filter by sender.
|
|
170
|
+
category: Filter by category.
|
|
171
|
+
inbox_id: Limit to a specific inbox.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
JSON array of matching emails.
|
|
175
|
+
"""
|
|
176
|
+
import json
|
|
177
|
+
|
|
178
|
+
result = client.search_emails(
|
|
179
|
+
query=query or None,
|
|
180
|
+
sender=sender or None,
|
|
181
|
+
category=category or None,
|
|
182
|
+
inbox_id=inbox_id or None,
|
|
183
|
+
)
|
|
184
|
+
return json.dumps(result, indent=2)
|
|
185
|
+
|
|
186
|
+
def add_domain(domain: str) -> str:
|
|
187
|
+
"""Add a custom domain for agent email addresses.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
domain: The domain to add (e.g., 'mycompany.com').
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
JSON with domain ID and DNS records to configure.
|
|
194
|
+
"""
|
|
195
|
+
import json
|
|
196
|
+
|
|
197
|
+
result = client.add_domain(domain)
|
|
198
|
+
return json.dumps(result, indent=2)
|
|
199
|
+
|
|
200
|
+
def verify_domain(domain_id: str) -> str:
|
|
201
|
+
"""Verify DNS records and activate a custom domain.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
domain_id: The domain ID to verify.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
JSON with verification status for each DNS record.
|
|
208
|
+
"""
|
|
209
|
+
import json
|
|
210
|
+
|
|
211
|
+
result = client.verify_domain(domain_id)
|
|
212
|
+
return json.dumps(result, indent=2)
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
"create_inbox": create_inbox,
|
|
216
|
+
"wait_for_email": wait_for_email,
|
|
217
|
+
"get_otp": get_otp,
|
|
218
|
+
"list_emails": list_emails,
|
|
219
|
+
"read_email": read_email,
|
|
220
|
+
"search_emails": search_emails,
|
|
221
|
+
"add_domain": add_domain,
|
|
222
|
+
"verify_domain": verify_domain,
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def create_langchain_tools(
|
|
227
|
+
api_key: str,
|
|
228
|
+
base_url: str = "https://api.lumbox.co",
|
|
229
|
+
):
|
|
230
|
+
"""
|
|
231
|
+
Create LangChain-compatible tools for Lumbox.
|
|
232
|
+
|
|
233
|
+
Usage:
|
|
234
|
+
from lumbox import create_langchain_tools
|
|
235
|
+
from langchain_openai import ChatOpenAI
|
|
236
|
+
from langchain.agents import create_tool_calling_agent, AgentExecutor
|
|
237
|
+
|
|
238
|
+
tools = create_langchain_tools(api_key="ak_...")
|
|
239
|
+
llm = ChatOpenAI(model="gpt-4o")
|
|
240
|
+
agent = create_tool_calling_agent(llm, tools, prompt)
|
|
241
|
+
executor = AgentExecutor(agent=agent, tools=tools)
|
|
242
|
+
"""
|
|
243
|
+
try:
|
|
244
|
+
from langchain_core.tools import StructuredTool
|
|
245
|
+
except ImportError:
|
|
246
|
+
raise ImportError(
|
|
247
|
+
"langchain-core is required. Install with: pip install lumbox[langchain]"
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
raw_tools = lumbox_tools(api_key=api_key, base_url=base_url)
|
|
251
|
+
|
|
252
|
+
return [
|
|
253
|
+
StructuredTool.from_function(func, name=name)
|
|
254
|
+
for name, func in raw_tools.items()
|
|
255
|
+
]
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lumbox
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Lumbox SDK — Email for AI agents. Create inboxes, receive OTPs, send replies.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://lumbox.co
|
|
7
|
+
Project-URL: Repository, https://github.com/kumard3/agentinbox
|
|
8
|
+
Project-URL: Documentation, https://docs.lumbox.co
|
|
9
|
+
Keywords: email,ai,agents,otp,mcp,lumbox,verification
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
Requires-Dist: httpx>=0.27.0
|
|
21
|
+
Provides-Extra: langchain
|
|
22
|
+
Requires-Dist: langchain-core>=0.3.0; extra == "langchain"
|
|
23
|
+
Provides-Extra: crewai
|
|
24
|
+
Requires-Dist: crewai>=0.80.0; extra == "crewai"
|
|
25
|
+
|
|
26
|
+
# lumbox
|
|
27
|
+
|
|
28
|
+
Email for AI agents. Create inboxes, receive OTPs, extract verification codes — all via API.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install lumbox
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from lumbox import Lumbox
|
|
40
|
+
|
|
41
|
+
client = Lumbox(api_key="ak_...")
|
|
42
|
+
|
|
43
|
+
# Create an inbox
|
|
44
|
+
inbox = client.create_inbox(name="github-bot")
|
|
45
|
+
# → github-bot@lumbox.co
|
|
46
|
+
|
|
47
|
+
# Sign up on any service with inbox.address...
|
|
48
|
+
|
|
49
|
+
# Wait for the OTP (blocks until it arrives)
|
|
50
|
+
otp = inbox.wait_for_otp(timeout=60)
|
|
51
|
+
print(otp["code"]) # "847291"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Auth header
|
|
55
|
+
|
|
56
|
+
The SDK sends `Authorization: Bearer ak_...` by default. The legacy
|
|
57
|
+
`X-API-Key` header still works server-side. Raw HTTP example:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
curl https://api.lumbox.co/v1/inboxes \
|
|
61
|
+
-H "Authorization: Bearer ak_your_key_here"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Inbox-scoped API keys
|
|
65
|
+
|
|
66
|
+
Mint a key that can only ever touch one inbox:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
created = client.inboxes.api_keys.create(inbox.id, name="ci-bot")
|
|
70
|
+
print(created["api_key"]) # shown once
|
|
71
|
+
|
|
72
|
+
client.inboxes.api_keys.list(inbox.id)
|
|
73
|
+
client.inboxes.api_keys.delete(inbox.id, created["id"])
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Features
|
|
77
|
+
|
|
78
|
+
- **OTP extraction** — verification codes parsed automatically
|
|
79
|
+
- **Long-poll** — `wait_for_email()` and `wait_for_otp()` block until arrival
|
|
80
|
+
- **Send/reply/forward** — full outbound email support
|
|
81
|
+
- **Custom domains** — DKIM, SPF, DMARC verification
|
|
82
|
+
- **LangChain & CrewAI** — pre-built tool wrappers
|
|
83
|
+
|
|
84
|
+
## Framework Integration
|
|
85
|
+
|
|
86
|
+
### LangChain
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pip install lumbox[langchain]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from lumbox import create_langchain_tools
|
|
94
|
+
|
|
95
|
+
tools = create_langchain_tools(api_key="ak_...")
|
|
96
|
+
# Use tools directly with LangChain agents
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Any Framework
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from lumbox import lumbox_tools
|
|
103
|
+
|
|
104
|
+
tools = lumbox_tools(api_key="ak_...")
|
|
105
|
+
# Dict of plain functions with proper type hints
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## API
|
|
109
|
+
|
|
110
|
+
### `Lumbox(api_key, base_url?)`
|
|
111
|
+
|
|
112
|
+
Create a client. `base_url` defaults to `https://api.lumbox.co`.
|
|
113
|
+
|
|
114
|
+
### `client.create_inbox(name?, domain?)`
|
|
115
|
+
|
|
116
|
+
Returns an `Inbox` object with `.address`, `.id`, and convenience methods.
|
|
117
|
+
|
|
118
|
+
### `inbox.wait_for_otp(timeout?, sender?)`
|
|
119
|
+
|
|
120
|
+
Blocks until an email with an OTP arrives.
|
|
121
|
+
|
|
122
|
+
### `inbox.wait_for_email(timeout?, sender?, subject?)`
|
|
123
|
+
|
|
124
|
+
Blocks until any email arrives.
|
|
125
|
+
|
|
126
|
+
### `inbox.list_emails()`
|
|
127
|
+
|
|
128
|
+
List all emails in the inbox.
|
|
129
|
+
|
|
130
|
+
Full API docs: [docs.lumbox.co](https://docs.lumbox.co)
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
lumbox
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "lumbox"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "Lumbox SDK — Email for AI agents. Create inboxes, receive OTPs, send replies."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
dependencies = ["httpx>=0.27.0"]
|
|
13
|
+
keywords = ["email", "ai", "agents", "otp", "mcp", "lumbox", "verification"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://lumbox.co"
|
|
27
|
+
Repository = "https://github.com/kumard3/agentinbox"
|
|
28
|
+
Documentation = "https://docs.lumbox.co"
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
langchain = ["langchain-core>=0.3.0"]
|
|
32
|
+
crewai = ["crewai>=0.80.0"]
|
lumbox-0.3.0/setup.cfg
ADDED