carlyemail
Real email inboxes for AI agents. Create one with a call, then send, receive and reply to real mail — from Gmail, Outlook, anywhere.
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.
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:
carly = CarlyEmail(api_key=signup["api_key"])
carly.agent.verify({"otp_code": "123456"})
Or from a terminal: npx carlyemail signup.
Using it
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.
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.
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.
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, 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.
Release files for carlyemail 0.4.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| carlyemail-0.4.2.tar.gz | 15.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| carlyemail-0.4.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.2 kB
Release files / carlyemail-0.4.2.tar.gz
| Download URL | carlyemail-0.4.2.tar.gz |
|---|---|
| Size | 15.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
23e96d28bf1504233379f16fc5b5cdaa7a23c3f14921ed61baa1728c1e1ee98a
|
|
BLAKE2b-256 checksum How to use checksums |
03378d691ab80196948e24dba316ddb0c714dc58b76873b435f98c599b30f319
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.3
|
Release files / carlyemail-0.4.2-py3-none-any.whl
| Download URL | carlyemail-0.4.2-py3-none-any.whl |
|---|---|
| Size | 16.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
09a6b06cc0352de2a93c5aa2202cef66ffc041257f7918f9ce966e155344853e
|
|
BLAKE2b-256 checksum How to use checksums |
bdbb7169777a3791d6e50bc008114845130a126ce5d84cf8f2213a5dfd948f0b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.3
|