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.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file carlyemail-0.4.0.tar.gz.
File metadata
- Download URL: carlyemail-0.4.0.tar.gz
- Upload date:
- Size: 14.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ca3cd07e1b9caf3a5ce02e658406bb8b64a852cc3c541d6d0db348c5f04df5a1
|
|
| MD5 |
eff5447565171107a543f7371e1a5797
|
|
| BLAKE2b-256 |
bf8c8a83d89e8def578d9c16845e86f273cd946ae0f35eb3e3e5d1423e08248c
|
File details
Details for the file carlyemail-0.4.0-py3-none-any.whl.
File metadata
- Download URL: carlyemail-0.4.0-py3-none-any.whl
- Upload date:
- Size: 15.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
baeb8eeb058525eed6cb2c96e072e1639261858024240d102815293394f8ab0e
|
|
| MD5 |
be386bcec02e84cff225b7c27c50b43a
|
|
| BLAKE2b-256 |
810295e15a84979fb9ec8d99d5771f6dc83c96fb1a8c8ea573a13e5aa79a6976
|