Metadata-Version: 2.4
Name: mailnation
Version: 0.1.0
Summary: Official Python SDK for the Mailnation Email API
Author: Mailnation
License: MIT
Project-URL: Homepage, https://docs.mailnation.id
Project-URL: Repository, https://github.com/mailnation-id/mailnation-python
Keywords: mailnation,email,smtp,transactional
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Dynamic: license-file

# mailnation

Official Python SDK for the [Mailnation Email API](https://docs.mailnation.id).

- `POST /emails` — send (html/text, attachments, headers, tags)
- `GET /emails/{id}` — status + recipients
- HTTP Basic (SMTP credentials) or Bearer JWT
- Automatic `Idempotency-Key` when unset
- Typed API errors (`insufficient_credits`, idempotency conflicts, …)
- `wait()` helper for polling delivery

OpenAPI: [openapi.yaml](./openapi.yaml) · Live: https://api.mailnation.id/openapi.yaml

## Install

```bash
pip install mailnation
```

Requires Python 3.9+. No third-party runtime dependencies.

## Quickstart

```python
import os
from mailnation import Client

client = Client(
    username=os.environ["MAILNATION_SMTP_USER"],
    password=os.environ["MAILNATION_SMTP_PASSWORD"],
)

res = client.emails.send(
    from_="noreply@your-domain.id",
    to="user@gmail.com",
    subject="OTP",
    html="<p>847291</p>",
    text="847291",
)
print(res["id"], res["status"])
```

`from` is a Python keyword, so the client accepts `from_`.

## Attachment

```python
from mailnation import attachment_from_file

att = attachment_from_file("invoice.pdf", "application/pdf")
res = client.emails.send(from_="billing@x.id", to="a@b.com", subject="Invoice", html="<p>ok</p>", attachments=[att])
```

## Wait for delivery

```python
email = client.emails.wait(res["id"])
```

## Errors

```python
from mailnation import is_insufficient_credits, is_idempotency_conflict, is_retryable

if is_insufficient_credits(err):
    ...
if is_idempotency_conflict(err):
    ...
if is_retryable(err):
    ...
```

## Auth

```python
Client(username=smtp_user, password=smtp_password)  # recommended for apps
Client(bearer=jwt)  # dashboard customer JWT
```

## License

MIT
