Skip to content

Email addresses

An email address (an “inbox” in the API, with ids starting ibx_) belongs to the account. It can be assigned to a device or held unassigned; either way it counts toward the plan.

GET /domains lists the domains this account can create addresses on: shared domains its plan reaches, and any domains it brought itself.

{ "domains": [{ "domain": "example-pool.email", "reserved": false, "tier": "free" }] }

reserved is true for a domain that belongs to your account alone. tier is the plan group a shared domain belongs to, and null for one of your own.

Shared domains are grouped by plan, so an account only gets addresses on its own plan’s group and those below it.

POST /inboxes with a client-generated id and a domain:

Terminal window
curl https://api.mailcycle.email/inboxes \
-H "Authorization: Bearer $MAILCYCLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "id": "ibx_k3v9x2mq7a", "domain": "example-pool.email", "prefix": "receipts" }'
FieldNotes
idRequired. ibx_ followed by 4 to 48 letters and digits. You choose it, so sealed data can be bound to it before the address exists.
domainRequired, unless emailAddress is given. One of the domains from GET /domains.
prefixOptional. The server adds a random ending: receipts-x7k2@….
styleOptional. With no prefix or localPart, the server rolls a name in this style: person (maya.holt), business (harbor-supply), team (orders_desk) or neutral (quiet.falcon42, the default).
localPartThe exact name before the @. Any name from Scale up. On every plan, a rolled name from GET /inboxes/names.
emailAddressThe whole address, as shorthand for domain plus localPart. Same rules as localPart.
retentionDaysOptional. 1 to 90, default 7.
metaOptional. The sealed label.
publicKeyThe address’s X25519 public key, base64url. Without it the address refuses mail.

The response is the new address as inbox. Past the plan’s limit the request returns 402 allocation_exhausted.

GET /inboxes/names?style=person&domain=example-pool.email returns up to eight names in that style that are free on the domain:

{ "style": "person", "domain": "example-pool.email", "names": ["maya.holt", "theo.brandt", "…"] }

Pass one as localPart to take it. The names are free when listed, not held, so another account can take one first; creating it then returns 409 address_taken. A name is two words from one style’s word lists joined by ., - or _, sometimes with a number of up to three digits on the end: maya.holt, harbor-supply42, orders_desk_7.

PATCH /inboxes/:id updates the sealed label (meta) or retentionDays, or adds a missing publicKey. A shorter retention applies to mail already stored, and deletes what is past it.

The sealed meta holds the label and the address’s sender name, like “Support at Acme”, which the device or agent holding the address puts on the From line. Set both in the app under Edit address; a sender name needs a plan that sends, Personal and up. Writing meta replaces both, so carry the sender name over when you change the label.

POST /workers/:id/inboxes with { "inboxId": "ibx_…" } puts an address on a device, which then receives its mail. DELETE /workers/:id/inboxes/:inboxId takes it off. On Free a device holds one address. Both need a signed-in session, since they decide where an address’s mail goes; an API key gets 403 session_required.

DELETE /inboxes/:id deletes the address with its mail and attachments and frees its place on the plan. The address is retired and never issued to anyone again, so password resets sent to it cannot reach a stranger.

© Northlab Studios Ltd, trading as Mailcycle. Registered in England and Wales, company no. 17462734. Registered office: 167-169 Great Portland Street, London W1W 5PF.