Metadata-Version: 2.4
Name: minutemail-sdk
Version: 1.1.0
Summary: Official Python SDK for the MinuteMail API - 100% API coverage with full feature support.
Author-email: MinuteMail <engineering@minutemail.co>
License: MIT
Project-URL: Homepage, https://minutemail.co
Project-URL: Repository, https://github.com/minutemailco/minutemail-sdk
Keywords: email,api,sdk,minutemail
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.31.0
Dynamic: license-file

# MinuteMail Python SDK

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](pyproject.toml)
[![PyPI](https://img.shields.io/pypi/v/minutemail-sdk.svg)](https://pypi.org/project/minutemail-sdk/)

Official Python client for the MinuteMail public API (`/v1`). It handles auth headers, request wiring, and attachment encoding so you can focus on product logic.

## Installation

```bash
pip install minutemail-sdk
```

Or from source:

```bash
pip install git+https://github.com/minutemailco/minutemail-sdk.git
```

Requirements: Python 3.9+ and `requests>=2.31.0`.

## Authentication

Every authenticated call sends `Authorization: Bearer <api-key>`. Pass your tenant-scoped API key when constructing the client:

```python
from minutemail import MinuteMailClient

client = MinuteMailClient(
    api_key="your-api-key",
    base_url="https://api.minutemail.co",  # or http://localhost:8080 for local
)
```

## Usage examples

> **Domain note:** MinuteMail uses two domains.
> `minutemail.co` hosts the website and API (`base_url`, support mailboxes like
> `support@minutemail.co`). `minutemail.cc` is the domain temporary mailboxes
> are created on — pass it as the `domain` argument when creating mailboxes.

### Create and use a mailbox

```python
from minutemail import MinuteMailClient, APIError

client = MinuteMailClient(api_key="your-api-key")

try:
    mailbox = client.create_mailbox(
        domain="minutemail.cc",
        recoverable=True,
        tag="onboarding",
        expires_in=20,
    )
    print("Mailbox address:", mailbox["address"])

except APIError as exc:
    print("Request failed:", exc)
```

### Manage custom domains

```python
domain = client.create_domain("example.com")
print("TXT token:", domain["txt_token"])

result = client.verify_domain(domain["id"])
print("TXT verified:", result["txt_verified"])
print("MX verified:", result["mx_verified"])
```

### Team members and invitations

```python
# Invite by email
invitation = client.create_invitation("newuser@example.com")

# Add a member directly
member = client.create_member(
    user_id="user-123",
    username="alice",
    email="alice@example.com",
    status="ACTIVE",
)

# List all members
result = client.list_members()
for m in result["members"]:
    print(m["username"], m["email"])
```

### API key management

```python
# Create a scoped key
new_key = client.create_api_key(
    name="CI pipeline",
    scopes=[MinuteMailClient.SCOPE_MAILBOXES_READ, MinuteMailClient.SCOPE_MAILBOXES_WRITE],
)
print("Plaintext key (shown once):", new_key["api_key"])

# Update scopes later
client.update_api_key_scopes(new_key["id"], scopes=[MinuteMailClient.SCOPE_DOMAINS_READ])

# List all keys
keys = client.list_api_keys()
```

## Client classes

- `MinuteMailClient`: Production-safe surface for all gateway routes.

### Constructor parameters

- `api_key` (str, required): Tenant-scoped API key used for all authenticated calls.
- `base_url` (str, default `https://api.minutemail.co`): Gateway origin (no `/v1` suffix).
- `timeout` (float, default `10.0`): Per-request timeout in seconds.
- `session` (requests.Session, optional): Provide to reuse connections/custom adapters.

### Scope constants

Available as class attributes on `MinuteMailClient`:

| Constant | Value |
|---|---|
| `SCOPE_ALL` | `*` |
| `SCOPE_MAILBOXES_READ` / `SCOPE_MAILBOXES_WRITE` | `mailboxes:read` / `mailboxes:write` |
| `SCOPE_DOMAINS_READ` / `SCOPE_DOMAINS_WRITE` | `domains:read` / `domains:write` |
| `SCOPE_TEAM_READ` / `SCOPE_TEAM_WRITE` | `team:read` / `team:write` |
| `SCOPE_IDENTITIES_READ` / `SCOPE_IDENTITIES_WRITE` | `identities:read` / `identities:write` |

Empty scopes or `*` grants full access.

### MinuteMailClient methods

**Mailboxes**
- `list_mailboxes(address=None, owner=None)` → `{items:[...]}`. Active mailboxes, optionally filtered by exact address or owner user ID.
- `create_mailbox(domain, expires_in=None, recoverable=None, tag=None, owner=None, no_expiration=False)` → mailbox dict (201).
  - `expires_in` (int, optional): Lifetime in minutes (1–60).
  - `recoverable` (bool): Archive on expiry instead of deleting.
  - `tag` (str): Required when `recoverable=True`.
  - `owner` (str): Override the owner user ID.
  - `no_expiration` (bool): Create a permanent mailbox (never expires).
- `get_mailbox(mailbox_id)` → mailbox dict.
- `delete_mailbox(mailbox_id)` → `None` (204).
- `delete_mailboxes(ids)` → `None` (204). Bulk delete; recoverable mailboxes are archived.

**Archived mailboxes**
- `list_archived_mailboxes()` → `{items:[...]}`.
- `get_archived_mailbox(archived_mailbox_id)` → archived mailbox dict.
- `reactivate_archived_mailbox(archived_mailbox_id, expires_in=None)` → new mailbox dict (201).
- `delete_archived_mailbox(archived_mailbox_id)` → `None` (204).
- `delete_archived_mailboxes(ids)` → `None` (204). Bulk permanent delete.

**Mails**
- `list_mails(mailbox_id)` → `{items:[...]}` newest-first.
- `get_mail(mailbox_id, mail_id)` → mail dict with body, attachment summaries, headers.
- `create_mail(mailbox_id, sender, subject=None, body=None, expires_in=None, attachments=None)` → mail dict (201).
  - Uses `multipart/form-data`. `attachments` is a list of `(filename, bytes)` tuples.
- `delete_mail(mailbox_id, mail_id)` → `None` (204).
- `delete_mails(mailbox_id, ids)` → `None` (204). Bulk delete.

**Attachments**
- `list_attachments(mailbox_id, mail_id)` → `{items:[...]}` metadata only (no `data`).
- `get_attachment(mailbox_id, mail_id, attachment_id)` → metadata + base64 `data`.
- `create_attachment(mailbox_id, mail_id, filename, data, content_type=None, expires_in=None)` → attachment dict (201).
  - `data` accepts `bytes`, `bytearray`, `memoryview`, or `str` (UTF-8 encoded).
- `delete_attachment(mailbox_id, mail_id, attachment_id)` → `None` (204).
- `delete_attachments(mailbox_id, mail_id, ids)` → `None` (204). Bulk delete.

**Domains**
- `list_domains()` → `{domains:[...]}` newest-first.
- `create_domain(name)` → domain dict (201) with `txt_token` for DNS verification.
- `verify_domain(domain_id)` → `{txt_verified, mx_verified, txt_error?, mx_error?}`.
- `delete_domain(domain_id)` → `{status, id}` (202).

**Team members**
- `list_members()` → `{members:[...]}`.
- `create_member(user_id, username, email, status)` → member dict (201).
- `get_member(member_id)` → member dict.
- `delete_member(member_id)` → `{status, id}` (202).
- `delete_all_members()` → `{status, count}` (200).

**Invitations**
- `list_invitations()` → `{invitations:[...]}`.
- `create_invitation(email)` → invitation dict (201).
- `delete_invitation(invitation_id)` → `{status, invitation_id}`.

**OAuth clients**
- `list_oauth_clients()` → `{clients:[...]}`.
- `create_oauth_client(name, redirect_uris, provider_type="custom", provider_label=None)` → client dict (201).
  - `provider_type`: `google`, `github`, `apple`, `facebook`, or `custom`.
- `get_oauth_client(client_id)` → client dict.
- `delete_oauth_client(client_id)` → `None` (204).
- `rotate_oauth_client_secret(client_id)` → `{clientSecret}` — old secret invalidated.

**Identities**
- `list_identities(client_id=None, mailbox_address=None)` → `{identities:[...]}`.
- `create_identity(client_id, mailbox_address, username=None, name=None, avatar_url=None)` → identity dict (201).
- `get_identity(identity_id)` → identity dict.
- `delete_identity(identity_id)` → `None` (204).

**API keys**
- `list_api_keys()` → `{api_keys:[...]}`.
- `create_api_key(name, scopes=None, domains=None, expires_at=None)` → key dict with plaintext `api_key` (201).
  - `expires_at`: RFC 3339 timestamp.
- `delete_api_key(key_id)` → `{status, id}` (200).
- `delete_api_keys(owner)` → `{status, deleted}` (200). Bulk revoke by owner.
- `update_api_key_scopes(key_id, scopes)` → `{status, id, scopes}` (200).

**Health**
- `health()` → `{status: "ok"}`. No auth header sent.
- `ready()` → readiness payload. No auth header sent.

## Errors

- Network/timeouts raise `TransportError`.
- Non-2xx responses raise `APIError` with `status_code`, `error`, `message`, and a stringified response preview.

```python
from minutemail import APIError

try:
    client.delete_mailbox("missing-id")
except APIError as exc:
    print(exc.status_code, exc.error, exc.message)
```

## Configuration notes

- `base_url` should be the gateway origin (no `/v1` suffix). Default: `https://api.minutemail.co`.
- `expires_in` is an integer number of minutes (1–60). Omit to use the service default TTL.
- Attachments: `bytes`/`str` data is base64-encoded automatically by `create_attachment()`.

## Examples

See [examples/mailbox_roundtrip.py](examples/mailbox_roundtrip.py) for a
complete end-to-end flow: create a mailbox, poll for incoming mail, read an
attachment, clean up.

## Development

```bash
python3 -m venv venv && source venv/bin/activate
pip install -e .
```

Point `base_url` at your running gateway (`http://localhost:8080`) and use a
test API key. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines and
[CHANGELOG.md](CHANGELOG.md) for release history.
