Metadata-Version: 2.4
Name: inbox-api
Version: 0.1.4
Summary: Python SDK for the Inbox API — email management for developers
Project-URL: Homepage, https://inboxapi.com
Project-URL: Documentation, https://inboxapi.com/docs/python-sdk
Project-URL: Repository, https://github.com/cloudworks-pt/inbox-api
Author-email: CloudWorks <dev@cloudworks.pt>
License-Expression: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: anyio>=4.0
Requires-Dist: httpx<1,>=0.28
Requires-Dist: pydantic<3,>=2.0
Description-Content-Type: text/markdown

# inbox-api

[![PyPI version](https://img.shields.io/pypi/v/inbox-api)](https://pypi.org/project/inbox-api/)
[![Python](https://img.shields.io/pypi/pyversions/inbox-api)](https://pypi.org/project/inbox-api/)

Python SDK for the Inbox API — email management for developers.

## Installation

```bash
pip install inbox-api
```

## Quick Start

### Sync

```python
from inbox_api import InboxApiClient

with InboxApiClient("https://api.example.com", "cw_your_token") as client:
    result = client.messages.list("account_id", page_size=5)
    for msg in result.items:
        print(f"{msg.subject} — from {msg.from_email}")
```

### Async

```python
import asyncio
from inbox_api import AsyncInboxApiClient

async def main():
    async with AsyncInboxApiClient("https://api.example.com", "cw_your_token") as client:
        result = await client.messages.list("account_id", page_size=5)
        for msg in result.items:
            print(f"{msg.subject} — from {msg.from_email}")

asyncio.run(main())
```

## Authentication

The SDK authenticates using API tokens prefixed with `cw_`. Pass your token as the second argument to the client constructor.

```python
client = InboxApiClient("https://api.example.com", "cw_your_token")
```

## Resources

| Resource | Access | Operations |
|----------|--------|------------|
| Messages | `client.messages` | list, get, get_body, batch_mark_read, batch_archive, batch_move, iter_all |
| Threads | `client.threads` | list, get, iter_all |
| Send | `client.send` | send, reply, forward |
| Search | `client.search` | search, iter_all |
| Drafts | `client.drafts` | list, create, update, delete, send |
| Contacts | `client.contacts` | list, iter_all |
| Webhooks | `client.webhooks` | list, create, get, update, delete, templates |
| Accounts | `client.accounts` | list, get, health, digest |

## Send an Email

```python
from inbox_api import InboxApiClient
from inbox_api.models.send import SendEmailRequest

with InboxApiClient("https://api.example.com", "cw_your_token") as client:
    client.send.send(SendEmailRequest(
        account_id="account_id",
        to=[{"email": "recipient@example.com"}],
        subject="Hello from Inbox API",
        body_text="Sent via the Python SDK.",
    ))
```

## Search Messages

```python
from inbox_api import InboxApiClient

with InboxApiClient("https://api.example.com", "cw_your_token") as client:
    results = client.search.search("account_id", "invoice")
    for msg in results.items:
        print(f"{msg.subject} — {msg.snippet}")
```

## Pagination

Use `iter_all()` to automatically paginate through all results:

```python
from inbox_api import InboxApiClient

# Sync — iterate all messages
with InboxApiClient("https://api.example.com", "cw_your_token") as client:
    for msg in client.messages.iter_all("account_id"):
        print(msg.subject)
```

```python
from inbox_api import AsyncInboxApiClient

# Async — iterate all messages
async with AsyncInboxApiClient("https://api.example.com", "cw_your_token") as client:
    async for msg in client.messages.iter_all("account_id"):
        print(msg.subject)
```

```python
# Limit to first 5 pages for safety
with InboxApiClient("https://api.example.com", "cw_your_token") as client:
    for msg in client.messages.iter_all("account_id", max_pages=5):
        print(msg.subject)
```

Available on: `client.messages.iter_all()`, `client.threads.iter_all()`, `client.contacts.iter_all()`, `client.search.iter_all()`.

## Error Handling

```python
from inbox_api import InboxApiClient, ApiError, RateLimitError, NotFoundError

with InboxApiClient("https://api.example.com", "cw_your_token") as client:
    try:
        msg = client.messages.get("nonexistent_id")
    except NotFoundError:
        print("Message not found")
    except RateLimitError as e:
        print(f"Rate limited — retry after {e.retry_after}s")
    except ApiError as e:
        print(f"API error {e.status_code}: {e.message}")
```

## Retry Configuration

The SDK automatically retries on 429 (rate limit) and 5xx (server error) responses with exponential backoff.

```python
from inbox_api import InboxApiClient

# Default: 2 retries with exponential backoff
client = InboxApiClient("https://api.example.com", "cw_your_token")

# Disable retries
client = InboxApiClient("https://api.example.com", "cw_your_token", max_retries=0)

# More retries for batch operations
client = InboxApiClient("https://api.example.com", "cw_your_token", max_retries=5)
```

When a 429 response includes a `Retry-After` header, the SDK respects it instead of using calculated backoff.

## Timeout Configuration

```python
import httpx
from inbox_api import InboxApiClient

# Default: 30s request timeout, 5s connect timeout
client = InboxApiClient("https://api.example.com", "cw_your_token")

# Custom timeout
client = InboxApiClient(
    "https://api.example.com",
    "cw_your_token",
    timeout=httpx.Timeout(60.0, connect=10.0),
)
```

## Advanced

### Custom httpx Client

Inject a pre-configured httpx client for full control over transport settings:

```python
import httpx
from inbox_api import InboxApiClient

custom_client = httpx.Client(
    proxy="http://proxy.example.com:8080",
)
client = InboxApiClient(
    "https://api.example.com",
    "cw_your_token",
    http_client=custom_client,
)
```

When you provide a custom client, the SDK will not close it on context manager exit.

## License

MIT
