Metadata-Version: 2.4
Name: carlyemail
Version: 0.4.0
Summary: Real email inboxes for AI agents — create one, then send, receive and reply.
Project-URL: Homepage, https://carlyemail.com
Project-URL: Documentation, https://docs.carlyemail.com
Author: SWH Labs LLC
License-Expression: MIT
Keywords: agent,ai,email,inbox,mcp
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Communications :: Email
Requires-Python: >=3.10
Requires-Dist: httpx>=0.24
Description-Content-Type: text/markdown

# carlyemail

Real email inboxes for AI agents. Create one with a call, then send, receive and
reply to real mail — from Gmail, Outlook, anywhere.

```bash
pip install carlyemail
```

## Getting a key

No dashboard step. Sign-up is one unauthenticated call, which is what lets an
agent create its own mailbox while it is running.

```python
from carlyemail import CarlyEmail

signup = CarlyEmail(api_key="none").agent.sign_up(
    {"human_email": "you@example.com", "username": "hello"}
)
print(signup["api_key"], signup["inbox_id"])
```

Confirm the six-digit code that arrives, and the account can send:

```python
carly = CarlyEmail(api_key=signup["api_key"])
carly.agent.verify({"otp_code": "123456"})
```

Or from a terminal: `npx carlyemail signup`.

## Using it

```python
from carlyemail import CarlyEmail

carly = CarlyEmail()          # reads CARLYEMAIL_API_KEY

inbox = carly.inboxes.create({"username": "hello"})

carly.messages.send(
    inbox["email"],
    {"to": ["you@example.com"], "subject": "Hello", "text": "From an agent."},
)

for message in carly.messages.list(inbox["email"])["messages"]:
    print(message["subject"], "from", message["from"])
```

Replying to a *message* keeps the conversation together — `In-Reply-To` and
`References` are set for you, so it threads in the recipient's client instead of
starting a second exchange.

```python
carly.messages.reply(inbox["email"], message["message_id"], {"text": "On it."})
```

## Errors

Every error carries the message, the thing that clears it, and a documentation
link. All three are on the exception.

```python
from carlyemail import CarlyEmailError

try:
    carly.inboxes.create({"username": "hello"})
except CarlyEmailError as error:
    print(error.status, error.code)   # 429 inbox_limit_reached
    print(error.fix)                  # Upgrade the plan, or delete an inbox…
    print(error.docs)
```

## Receiving

`carlyemail.inbound` is the other half — the bit that decides whether a
delivery should wake your agent at all.

```python
from carlyemail.inbound import create_email_router
from fastapi import FastAPI

app = FastAPI()


async def on_email(email):
    print(email.from_address, email.subject, email.text)


app.include_router(create_email_router(on_email, path="/hooks/carlyemail"))
```

Your handler runs only for mail worth answering. It verifies the signature over
the raw bytes, returns 401 for anything that does not verify — including a
signature header that is not valid base64, the case that otherwise 500s a public
endpoint — admits `message.received` and not the spam, blocked or
unauthenticated variants, drops mail the inbox sent itself, checks the sender
against `allow_from`, ignores redeliveries, and answers the request before your
agent starts thinking.

`InboundReceiver.decide(body, headers)` is the same logic with no framework in
it, for everything that is not FastAPI. Neither needs a dependency beyond the
standard library; FastAPI is imported only if you call `create_email_router`.

Full options: <https://docs.carlyemail.com/guides/receiving#the-receiver>

## Resources

`agent`, `auth`, `billing`, `inboxes`, `messages`, `threads`, `drafts`, `lists`,
`domains`, `api_keys`, `metrics`, `pods`, `organizations`, `inbox_events`,
`webhooks`.

Every method is generated from the [OpenAPI
spec](https://docs.carlyemail.com/openapi.json), so this client cannot describe
an endpoint the API does not serve.

## Also

- Docs — <https://docs.carlyemail.com>
- CLI — `npx carlyemail`
- MCP — `https://api.carlyemail.com/mcp`, for Claude and other clients

MIT.
