Inboxes
A real address on a real domain.
An inbox is an email address that can send and receive. Its id is the
address — pepsi@carlyemail.com — not an opaque handle, so you never have to
look one up to know where mail goes.
curl -X POST https://api.carlyemail.com/v0/inboxes \
-H "Authorization: Bearer $CARLYEMAIL_API_KEY" \
-H 'content-type: application/json' \
-d '{"username": "pepsi", "display_name": "Support"}'
Omit username and one is generated. Omit domain and you get the default:
carlyemail.com for verified organizations, agents.carlyemail.com for
unverified ones.
The domain is decided when the address is minted, and an address is never
rewritten afterwards — mail is already in flight to it and threads already
reference it. So verifying an account changes where its next inbox lands, and
leaves the one it signed up with exactly where it is. An agent that signed up,
verified, and expected its address to follow will still be sending from
agents.carlyemail.com.
To move onto carlyemail.com, create a second inbox. The verify response names
both halves — inbox_domain is where new inboxes go, inboxes_on_signup_domain
lists the ones that stay put:
curl -X POST https://api.carlyemail.com/v0/inboxes \
-H "Authorization: Bearer $CARLYEMAIL_API_KEY" \
-H 'content-type: application/json' \
-d '{"username": "pepsi"}'
The old address keeps receiving, so nothing sent to it is lost. Send from whichever one you want to be reached at.
Display names
display_name is the name beside the address when the inbox sends — Support
<pepsi@carlyemail.com> rather than the address alone. It is optional, and
without one mail goes out as the bare address.
Set it at sign-up, when creating an inbox, or later. Sending an empty string takes it off again.
npx carlyemail name pepsi@carlyemail.com "Support"
npx carlyemail name pepsi@carlyemail.com # back to the bare address
curl -X PATCH https://api.carlyemail.com/v0/inboxes/pepsi@carlyemail.com \
-H "Authorization: Bearer $CARLYEMAIL_API_KEY" \
-H 'content-type: application/json' \
-d '{"display_name": "Support"}'
The name goes into a mail header, so it is limited to 255 characters and cannot
contain control characters — a newline in one would be header injection. Either
is refused with 400 invalid_request on the call that set it.
Usernames are globally unique per domain
Two organizations cannot both hold pepsi@carlyemail.com — it is one address
on one domain, and mail to it has to go somewhere unambiguous. A collision
returns 409 username_unavailable. Bring your own domain if you want a name
somebody else has taken; see custom domains.
Tagged addresses
Mail to pepsi+anything@carlyemail.com arrives in pepsi@carlyemail.com, with
the address it was sent to still in its to. Use a tag to sort mail, or to
give one inbox several addresses for testing. Because the tagged forms belong
to the inbox, a username cannot contain +; asking for one returns
400 invalid_username.
Deleting
Deleting an inbox deletes its messages. Mail arriving for a deleted address is acknowledged and dropped rather than retried, because retrying an address that does not exist can never succeed.
An inbox that is still in use is not deleted unless you say so. The delete is
refused with 409 inbox_in_use when the inbox sent mail in the last 30 days, or
an API key scoped to it was used in the last 30 days. The message says which,
and when:
{
"name": "ConflictError",
"code": "inbox_in_use",
"message": "events@carlyemail.com last sent mail today at 14:02 UTC.",
"fix": "Check nothing still sends from it. To delete it anyway, pass force=true."
}
Check that nothing still sends from the address, then delete it with force:
curl -X DELETE "https://api.carlyemail.com/v0/inboxes/events@carlyemail.com?force=true" \
-H "Authorization: Bearer $CARLYEMAIL_API_KEY"
The MCP delete_inbox tool takes "force": true, the CLI takes --force, and
the console shows Delete anyway after the first refusal.