Metadata-Version: 2.4
Name: mailisk
Version: 0.9.3
Summary: Typed Python client for the Mailisk API
Author-email: Mailisk <support@mailisk.com>
License-Expression: MIT
Project-URL: Homepage, https://mailisk.com
Project-URL: Documentation, https://docs.mailisk.com
Keywords: mailisk,email,sms,testing,totp
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
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: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.31.0
Requires-Dist: typing-extensions>=4.8.0
Provides-Extra: dev
Requires-Dist: build>=1.2.0; extra == "dev"
Requires-Dist: mypy>=1.8.0; extra == "dev"
Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: twine>=6.0.0; extra == "dev"
Requires-Dist: types-requests>=2.31.0; extra == "dev"
Dynamic: license-file

# Mailisk Python Client

Typed Python client for the Mailisk REST API.

Mailisk is an email, SMS, outbound email, and TOTP testing platform. This
package mirrors the Mailisk Node client API surface in a Python-friendly shape:
methods use snake_case, response bodies stay as normal dictionaries, and the
package ships `TypedDict`/`Literal` types plus `py.typed`.

## Installation

```shell
pip install mailisk
```

## Create A Client

Get your API key from Mailisk and pass it directly when creating a client:

```python
from mailisk import MailiskClient

mailisk = MailiskClient(api_key="YOUR_API_KEY")
```

The library does not read `.env` files or environment variables by itself.
Applications should load configuration however they prefer, then pass values to
the client:

```python
from mailisk import MailiskClient

api_key = load_api_key_from_your_config()
mailisk = MailiskClient(api_key=api_key)
```

## Quick Start

```python
from mailisk import MailiskClient

mailisk = MailiskClient(api_key="YOUR_API_KEY")

result = mailisk.search_inbox("mynamespace")
print(result["data"])
```

## Defaults

`search_inbox` and `search_sms_messages` match the Node client defaults:

- wait for at least one matching message unless `wait` is `False`
- ignore messages older than 15 minutes unless a lower bound is provided
- use a 5 minute timeout while waiting
- allow a high redirect count for wait endpoints

Timeouts are in seconds because the client uses `requests`:

```python
mailisk.search_inbox(
    "mynamespace",
    {"to_addr_prefix": "john@mynamespace.mailisk.net"},
    {"timeout": 60},
)
```

## Email

Search inbox:

```python
response = mailisk.search_inbox(
    "mynamespace",
    {
        "to_addr_prefix": "john@mynamespace.mailisk.net",
        "subject_includes": "password",
    },
)

emails = response["data"]
```

List namespaces:

```python
namespaces = mailisk.list_namespaces()
print([item["namespace"] for item in namespaces["data"]])
```

Download an attachment:

```python
attachment_id = emails[0]["attachments"][0]["id"]
content = mailisk.download_attachment(attachment_id)
```

## Outbound Email

Send an outbound email:

```python
email = mailisk.send_email(
    "mynamespace",
    {
        "from": {"email": "support@mynamespace.mailisk.net", "name": "Support"},
        "to": ["verified@example.com"],
        "subject": "Hello from Mailisk",
        "text": "Plain text body",
        "html": "<p>HTML body</p>",
    },
)

print(email["id"], email["status"])
```

Send with an attachment:

```python
import base64
from pathlib import Path

content = Path("report.txt").read_bytes()

mailisk.send_email(
    "mynamespace",
    {
        "to": ["verified@example.com"],
        "subject": "Report",
        "text": "Attached.",
        "attachments": [
            {
                "filename": "report.txt",
                "content_type": "application/octet-stream",
                "content_base64": base64.b64encode(content).decode("ascii"),
            }
        ],
    },
)
```

Fetch delivery details:

```python
detail = mailisk.get_outbound_email(email["id"])
print(detail["delivery_summary"])
```

Reply to an inbound email:

```python
reply = mailisk.reply_to_email(
    emails[0]["id"],
    {
        "subject": "Re: Thanks",
        "text": "We received your message.",
    },
)
```

Forward an inbound email:

```python
forwarded = mailisk.forward_email(
    emails[0]["id"],
    {
        "to": ["verified@example.com"],
        "subject": "Fwd: Support request",
        "text": "Forwarding this along.",
    },
)
```

## SMS

Search SMS messages:

```python
messages = mailisk.search_sms_messages(
    "+15551234567",
    {"from_number": "+1800555", "body": "Your code"},
)
```

List SMS numbers:

```python
numbers = mailisk.list_sms_numbers()
```

Send a virtual SMS:

```python
mailisk.send_virtual_sms(
    {
        "from_number": "+15550000001",
        "to_number": "+15550000002",
        "body": "Test message",
    }
)
```

## TOTP

Create a saved TOTP device:

```python
device = mailisk.create_totp_device(
    {
        "name": "GitHub staging",
        "shared_secret": "JBSWY3DPEHPK3PXP",
    }
)
```

Generate a TOTP code from a shared secret:

```python
otp = mailisk.get_totp_otp_by_shared_secret(
    "JBSWY3DPEHPK3PXP",
    {"min_seconds_until_expire": 10},
)

print(otp["code"])
```

Generate a TOTP code for a saved device:

```python
otp = mailisk.get_totp_otp_by_device_id(device["id"])
```

Delete a saved TOTP device:

```python
mailisk.delete_totp_device(device["id"])
```

## Typing

The package includes `py.typed` and exports `TypedDict`/`Literal` types for API
parameters and responses:

```python
from mailisk import MailiskClient, SearchInboxResponse

client = MailiskClient(api_key="YOUR_API_KEY")
response: SearchInboxResponse = client.search_inbox("mynamespace")
```

You can import request and response types from `mailisk` directly, for example
`SendEmailParams`, `SearchInboxResponse`, `OutboundEmailResponse`,
`OutboundEmailDetailResponse`, and `TotpOtpResponse`.
