Metadata-Version: 2.5
Name: poststack
Version: 0.9.0
Summary: Official Python SDK for the PostStack Email API
Project-URL: Homepage, https://poststack.dev
Project-URL: Documentation, https://poststack.dev/docs
Project-URL: Repository, https://github.com/getpoststack/python-sdk
Project-URL: Issues, https://github.com/getpoststack/python-sdk/issues
Author: PostStack
License: MIT
License-File: LICENSE
Keywords: api,email,poststack,smtp,transactional
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.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Email
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: httpx>=0.25.0
Requires-Dist: pydantic>=2.4.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: respx>=0.20.0; extra == 'dev'
Description-Content-Type: text/markdown

# PostStack Python SDK

Official Python SDK for the [PostStack](https://poststack.dev) Email API —
an [EU-hosted, GDPR-compliant](https://poststack.dev/security)
[email API for Python](https://poststack.dev) with sync and async clients,
full type hints, and drop-in compatibility with Django, FastAPI, Flask,
and Starlette. Up to 75% cheaper than Resend, SendGrid, and Postmark.

Docs: [poststack.dev/docs/sdk](https://poststack.dev/docs/sdk).

## Installation

```bash
pip install poststack
```

Requires Python 3.10+.

## Quick start

```python
from poststack import PostStack

client = PostStack(api_key="sk_live_...")

result = client.emails.send({
    "from": "hello@example.com",
    "to": ["user@example.com"],
    "subject": "Hello from PostStack",
    "html": "<p>Welcome!</p>",
})

print(result["id"])
```

## Async usage

```python
import asyncio
from poststack import AsyncPostStack

async def main():
    client = AsyncPostStack(api_key="sk_live_...")
    try:
        result = await client.emails.send({
            "from": "hello@example.com",
            "to": ["user@example.com"],
            "subject": "Hello from PostStack",
            "html": "<p>Welcome!</p>",
        })
        print(result["id"])
    finally:
        await client.aclose()

asyncio.run(main())
```

Or use it as an async context manager:

```python
async with AsyncPostStack(api_key="sk_live_...") as client:
    result = await client.emails.send({...})
```

## Error handling

Any non-2xx response raises `PostStackError`:

```python
from poststack import PostStack, PostStackError

client = PostStack(api_key="sk_live_...")

try:
    client.emails.send({"from": "x@y.com", "to": ["z@w.com"], "subject": "hi"})
except PostStackError as e:
    print(e.status_code, e.error, e.code, e.request_id)
    # e.headers holds the response headers; e.retry_after the Retry-After
    # delay in seconds, when the API sent one.
```

## Retries

Network errors, timeouts, 408, 429 and 5xx responses are retried up to
`max_retries` times (default 3) with full-jitter exponential backoff. A 429
that carries `Retry-After` waits exactly that long (up to 60 seconds; a longer
wait is raised instead). A 429 that is a quota rather than throttling — the
monthly plan limit or the daily send cap, which carry an error code and no
`Retry-After` — is raised immediately, since retrying cannot lift it.

## Configuration

```python
client = PostStack(
    api_key="sk_live_...",
    base_url="https://api.poststack.dev",  # default
    timeout=30.0,                           # default (seconds), per attempt
    max_retries=3,                          # default; 0 disables retrying
)
```

Override timeout per call:

```python
client.emails.send({...}, timeout=60.0)
```

## Resources

- `client.emails` — send, get, list, cancel, reschedule, batch, events, insights, preview, spam_preview
- `client.domains` — create, list, get, verify, update, delete, DMARC, DKIM rotation, inbox placement
- `client.contacts` — CRUD, import, export_csv (text; optional `segment_id`), unsubscribe
- `client.contact_properties` — custom properties, option_usage
- `client.segments` — create, list, get, update, delete, contacts, preview, members, growth, broadcasts
- `client.templates` — CRUD, publish, duplicate, render, presets
- `client.webhooks` — CRUD, test, deliveries, replay, batch_replay, rotate_secret
- `client.broadcasts` — CRUD, send, test, variants, resend, performance, non_openers, non_clickers, end_ab_test
- `client.suppressions` — list, add, remove
- `client.api_keys` — CRUD, rotate
- `client.mailboxes` — CRUD, aliases, password, filters, signature, shares, unread_summary
- `client.inbound_emails` — list, get, attachments, download, draft_reply, reply, forward
- `client.subscription_topics` — topics (get, update, list_subscribers) + contact subscriptions
- `client.workflows` — CRUD, graph (get_graph/put_graph/validate_graph), activate, pause, trigger, post_event
- `client.notification_channels` — Slack/Discord/Telegram alert channels: CRUD, test, deliveries, replay
- `client.signup_forms` — CRUD, submit
- `client.email_validations` — validate, validate_batch

## Links

- [PostStack — EU-hosted email API](https://poststack.dev)
- [API documentation](https://poststack.dev/docs)
- [Pricing](https://poststack.dev/pricing) · [Compare providers](https://poststack.dev/pricing/compare)
- [Migrate from Resend](https://poststack.dev/migrate/resend) · [from SendGrid](https://poststack.dev/migrate/sendgrid) · [from Postmark](https://poststack.dev/migrate/postmark)
- [Status](https://poststack.dev/status) · [Security](https://poststack.dev/security) · [DPA](https://poststack.dev/dpa)

## License

MIT — see [LICENSE](./LICENSE).
