Metadata-Version: 2.4
Name: anymessage-sdk
Version: 0.2.0
Summary: Python SDK for api.anymessage.shop — temporary and long-term email automation
License-Expression: MIT
Project-URL: Homepage, https://anymessage.shop
Project-URL: Documentation, https://anymessage.shop/en/docs
Keywords: anymessage,email,sdk,automation,temporary email
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: OS Independent
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Communications :: Email
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: requests<3.0,>=2.28

# AnyMessage SDK

A lightweight Python SDK for the [https://anymessage.shop](https://anymessage.shop) API.  
Supports **short-term** and **long-term** mailboxes, automatic message polling, and Activation Rate management.

---

## Installation

```bash
pip install anymessage
```

Requires Python 3.8+ and `requests`.

---

## Quick Start

```python
from anymessage import AnyMessageClient

with AnyMessageClient("YOUR_TOKEN") as client:
    order = client.order_email(site="instagram.com", domain="gmx,mailcom")
    msg = client.wait_for_message(id=order.id, timeout=120, poll_interval=3)
    client.cancel_email(id=order.id)
    print("Email:", order.email)
    print("HTML:", (msg.html or "")[:400])
```

Or use the one-liner combo that orders, waits, and extracts a value with regex:

```python
activation_id, email, html, code = client.order_wait_and_extract(
    site="instagram.com",
    domain="gmx,mailcom",
    regex=r"(\d{6})",   # extract 6-digit code from the email body
    timeout=120,
)
print(f"Code: {code}")  # e.g. "482910"
```

---

## Short-term Emails

| Method | Description |
|--------|-------------|
| `get_balance()` | Get account balance |
| `get_email_quantity(site)` | Available domains and counts |
| `order_email(site, domain, regex=None, subject=None)` | Order a temporary email |
| `reorder_email(id=None, email=None, site=None)` | Repeat a previous order |
| `get_message(id, preview=False)` | Fetch a message (raises `WaitMessageError` if not yet arrived) |
| `wait_for_message(id, timeout=120, poll_interval=2, preview=False, on_tick=None, stop_event=None)` | Poll until message arrives |
| `cancel_email(id)` | Cancel an activation |
| `order_wait_and_extract(site, domain, regex=None, subject=None, timeout=180, ...)` | Combo: order → wait → extract; returns `(id, email, html, match_or_None)` |

**Domain aggregators** — pass multiple domains as a comma-separated string or a list; the API returns whichever has stock:
```python
client.order_email(site="instagram.com", domain="gmx,mailcom,hotmail")
client.order_email(site="instagram.com", domain=["gmx", "mailcom"])
```

---

## Long-term Emails

| Method | Description |
|--------|-------------|
| `get_longlive_quantity(site)` | Available domains with counts and prices |
| `order_longlive_email(site, domain, count=1)` | Buy 1–1000 mailboxes; returns `LongliveOrderResponse` |
| `get_longlive_history(offset=1, limit=10)` | Order history with IMAP credentials |
| `get_longlive_last_messages(id, subject=None)` | Messages from the last 40 minutes |
| `get_longlive_messages(id, created_at=None, subject=None)` | All messages for an activation |
| `find_longlive_email(email)` | Look up a purchased mailbox by address |

```python
# Check what's available
qty = client.get_longlive_quantity(site="instagram.com")
print(qty.data)  # {"hotmail.com": {"count": 93, "price": 0.006}, ...}

# Buy 5 mailboxes at once
resp = client.order_longlive_email(site="instagram.com", domain="hotmail.com", count=5)
print(f"Bought {resp.count}, total ${resp.total_price}")
for mailbox in resp.emails:
    print(mailbox.email, mailbox.imap.password, mailbox.imap.link, mailbox.imap.port)

# Fetch recent messages for one of the mailboxes
msgs = client.get_longlive_last_messages(id=resp.emails[0].id)
for m in msgs:
    print(m.subject, m.from_, m.message[:200])

# Find a previously purchased mailbox
records = client.find_longlive_email(email="example@hotmail.com")
if records:
    print(records[0]["id"], records[0]["imap"])
```

---

## Activation Rate

| Method | Description |
|--------|-------------|
| `get_ratio(full=False)` | Cancel statistics per site+domain pair |
| `enable_block_ratio()` | Auto-block orders when ratio drops below threshold |
| `disable_block_ratio()` | Disable auto-blocking |

```python
# By default only shows pairs with cancel rate >= 60%
# Pass full=True to see all pairs including healthy ones
for entry in client.get_ratio(full=True):
    print(f"{entry.site} / {entry.domain}: ratio={entry.ratio:.2f}, cancel%={entry.cancel_percent}")
```

When blocking is enabled and the cancel rate reaches ≥ 60%, `order_email` raises `RatioBlockError`.

---

## Error Handling

```python
from anymessage import (
    AnyMessageClient, AnyMessageError,
    AuthError, NoBalanceError, NoEmailsError,
    RatioBlockError, ActivationCanceledError,
)

try:
    with AnyMessageClient("YOUR_TOKEN") as c:
        order = c.order_email(site="instagram.com", domain="gmx")
        msg = c.wait_for_message(id=order.id, timeout=120)
except AuthError:
    print("Invalid token")
except NoBalanceError:
    print("Insufficient balance")
except NoEmailsError:
    print("No emails available for this site/domain")
except RatioBlockError:
    print("Blocked due to low Activation Rate")
except ActivationCanceledError:
    print("Activation was canceled")
except AnyMessageError as e:
    print("API error:", e)
```

Full exception list: `AuthError`, `ValidationError`, `NotFoundError`, `NoBalanceError`, `NoEmailsError`, `ActivationCanceledError`, `ActivationAlreadyCanceledError`, `EmailBannedError`, `WaitMessageError`, `RatioBlockError`.

---

## Implementation Details

- Uses `requests.Session` with automatic retries (urllib3) and connection pooling.
- Thread-safe: create a separate `AnyMessageClient` per thread or task.
- No temporary files — everything runs in memory.
- `wait_for_message` supports `on_tick(n)` progress callback and `stop_event` (any object with `.is_set()`) for cancellation from another thread.

---

## License

MIT License © 2025 AnyMessage SDK contributors

---

**API Documentation:** https://anymessage.shop/en/docs  
**Official Website:** https://anymessage.shop/en
