Skip to content

Emails API ​

All endpoints require a bearer token (a login JWT or an API key) and a permission, listed with each endpoint.

INFO

Email hosting is offered on request - contact us before using these endpoints.

Mailboxes live on a domain you have already verified. If the domain's ownership is not verified yet, creating a mailbox returns 400 "Domain ownership is not verified. Publish the domain ownership TXT record (microapps-verify) and verify the domain before creating emails." See the Domains API.

Mailboxes are addressed by their id - a 24-character hex string - in every path: /api/emails/:domainName/:id.

The email object ​

json
{
  "id": "6a4d5b83b7006ccae6391b22",
  "email": "[email protected]",
  "domainName": "example.com",
  "storageSize": 5,
  "status": "ACTIVE",
  "alias": "",
  "catchAll": 0,
  "diskUsage": 20971520,
  "serverId": "6a4d5b83b7006ccae6391f88",
  "createdAt": "2026-09-01T12:00:00Z",
  "updatedAt": null
}
FieldMeaning
idThe mailbox id. Use it in every /api/emails/:domainName/:id path.
emailThe full address.
storageSizeMailbox quota in GB (1 to 50).
statusACTIVE or DISABLED (you set these). SUSPENDED is set by us and locks the mailbox.
aliasForwarding target. Empty string means no forwarding.
catchAll1 if this mailbox receives all mail sent to unknown addresses on the domain, else 0. A number, not a boolean, on the way out; a boolean on the way in.
diskUsageCurrent usage in bytes.
serverIdThe mail server the domain's mailboxes live on.
updatedAtnull until the mailbox is first changed.

List mailboxes ​

http
GET /api/emails?domain=example.com&page=1&limit=20&search=hello

Needs email:read. Paginated, newest first. The domain filter is optional; without it you get mailboxes across all your domains. search matches email, domainName, alias, and status.

bash
curl "https://cloud-api.microapps.io/api/emails?domain=example.com" \
  -H "Authorization: Bearer $MICROAPPS_API_KEY"
json
{
  "data": [
    {
      "id": "6a4d5b83b7006ccae6391b22",
      "email": "[email protected]",
      "domainName": "example.com",
      "storageSize": 5,
      "status": "ACTIVE",
      "alias": "",
      "catchAll": 0,
      "diskUsage": 20971520,
      "serverId": "6a4d5b83b7006ccae6391f88",
      "createdAt": "2026-09-01T12:00:00Z",
      "updatedAt": null
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 20,
  "totalPages": 1
}

Mailbox counts per domain ​

http
GET /api/emails/domains

Needs email:read. One entry per domain that has at least one mailbox, sorted by name:

json
[
  { "domainName": "example.com", "count": 3 }
]

Create a mailbox ​

http
POST /api/emails/:domainName

Needs email:create, $3 of credit, and a free slot under your mailbox limit.

bash
curl -X POST https://cloud-api.microapps.io/api/emails/example.com \
  -H "Authorization: Bearer $MICROAPPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "Sup3rSecret",
    "storageSize": 5,
    "serverId": "6a4d5b83b7006ccae6391f88"
  }'
FieldTypeNotes
emailstringThe full address. Its domain part must equal :domainName, or you get 400 "Email domain does not match the domain name: ... vs ...". The part before the @ must be 1 to 64 characters of lowercase letters, digits, ., _ and -, none of them at the start or end.
passwordstring8+ characters with an uppercase letter, a lowercase letter, and a digit.
storageSizenumberQuota in GB, 1 to 50. Required.
serverIdstringOnly required the first time you create a mailbox on the domain (it picks the mail server, and must be one that offers email hosting). Omit it afterwards; the domain's existing server is reused.

Response 201 with the email object, status already ACTIVE. Email addresses are globally unique, so a duplicate returns 400 "Email is already taken.".

New mailboxes go live within a few seconds rather than instantly.

Describe a mailbox ​

http
GET /api/emails/:domainName/:id

Needs email:read.

bash
curl https://cloud-api.microapps.io/api/emails/example.com/6a4d5b83b7006ccae6391b22 \
  -H "Authorization: Bearer $MICROAPPS_API_KEY"

Update a mailbox ​

http
PUT /api/emails/:domainName/:id

Needs email:update. Every field is optional - send only what you want to change:

bash
curl -X PUT https://cloud-api.microapps.io/api/emails/example.com/6a4d5b83b7006ccae6391b22 \
  -H "Authorization: Bearer $MICROAPPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "alias": "[email protected]", "storageSize": 10 }'
FieldTypeNotes
passwordstringNew password (same rules as create).
aliasstringForward a copy of incoming mail here. Send "" to clear it. Cannot equal the mailbox's own address (400 "Alias cannot be the same as the email").
catchAllbooleanMake this the catch-all for the domain. Sent as true/false; read back as 1/0. Only one mailbox per domain can hold it: enabling it while another already does returns 400 naming that mailbox.
statusstringACTIVE or DISABLED only, otherwise 400 "Status can either be ACTIVE or DISABLED".
storageSizenumberNew quota in GB, 1 to 50.

Response 200 with the updated mailbox. Sending nothing that differs from the current values is a no-op that still returns 200.

Suspended mailboxes

A SUSPENDED mailbox rejects all edits (400 "Cannot update a suspended email"), and you cannot set SUSPENDED yourself - it is an account-level state we manage.

Delete a mailbox ​

http
DELETE /api/emails/:domainName/:id

Needs email:delete. Returns 204. The mailbox and its mail are gone; this is irreversible.

Mailbox stats ​

http
GET /api/emails/:domainName/:id/mailbox-stats

Needs email:read. A live count plus the last activity timestamps:

json
{
  "messageCount": 214,
  "lastSent": "2026-09-15T09:12:00Z",
  "lastReceived": "2026-09-16T06:44:00Z"
}

lastSent and lastReceived are null until the mailbox has sent or received something. messageCount is best effort: if the count cannot be taken, it comes back 0 rather than failing the call.

Set up email on a domain ​

http
POST /api/emails/:domainName/email-setup

Needs email:update and $3 of credit.

bash
curl -X POST https://cloud-api.microapps.io/api/emails/example.com/email-setup \
  -H "Authorization: Bearer $MICROAPPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "emailServerId": "6a4d5b83b7006ccae6391f88" }'

Response 201 with no body. Turns on email for the domain and adds the records you need to publish to the domain's dnsRecords (all with TTL 300):

RecordrecordTypeNamePurposeRequired
MXMX@Where mail is deliveredYes
SPFTXT@Authorises our servers to send for youYes
DKIMTXT<domain-id>._domainkeySigns your outbound mailYes
DMARCTXT_dmarcReporting and policyOptional
SRVSRV_imaps._tcpIMAP autodiscovery (993)Optional
SRVSRV_submission._tcpSMTP submission autodiscovery (587)Optional

Read the exact values back from GET /api/domains/:id. A domain that already has email returns 400 "Domain already has an email server assigned" - use regenerate instead.

Revalidate DNS ​

http
POST /api/emails/:domainName/revalidate-dns

Needs email:update. Re-checks every published record on the domain right now - ownership, pointing and SSL records included, not just the email ones - and updates each record's status and the domain's dnsStatus. Response 200 with no body; read the results back from GET /api/domains/:id. This is what the console's Recheck DNS button calls.

Regenerate DNS ​

http
POST /api/emails/:domainName/regenerate-dns

Needs email:update. Wipes the domain's record list and rebuilds it from a fresh identity. Response 200 with no body. This is what the console's Regenerate Records button calls.

Regenerating invalidates three records you have already published

It rotates all of these at once, and every record starts unverified again:

  • the ownership TXT gets a new verification token,
  • the DKIM key rotates, so the _domainkey TXT value changes,
  • the SSL delegation label rotates, so the _acme-challenge CNAME target changes.

Update all three at your DNS provider afterwards. Certificates already issued keep serving until they expire, but the next renewal fails if the _acme-challenge CNAME is stale.

Remove email setup ​

http
DELETE /api/emails/:domainName/email-setup

Needs email:update. Strips the email records and unassigns the mail server. Ownership, pointing and SSL records are left alone. Returns 204.

Delete the domain's mailboxes first: while any remain, this returns 400 "Cannot delete domain with active emails".

Metrics ​

Sent / received / bounced counts at three scopes, all needing email:read. Add ?from= and ?to= (RFC3339 or YYYY-MM-DD, where to counts to end of day) to pick a window - the default is the last 7 days and the range is capped at 90 days.

EndpointScope
GET /api/emails/:domainName/:id/metricsMailbox total
GET /api/emails/:domainName/:id/metrics/dailyMailbox, daily
GET /api/emails/:domainName/metricsDomain total
GET /api/emails/:domainName/metrics/dailyDomain, daily
GET /api/emails/metrics/accountAccount total
GET /api/emails/metrics/account/dailyAccount, daily

Totals:

bash
curl "https://cloud-api.microapps.io/api/emails/example.com/metrics?from=2026-09-09&to=2026-09-16" \
  -H "Authorization: Bearer $MICROAPPS_API_KEY"
json
{ "sent": 1842, "received": 5310, "bounced": 7 }

Daily variants return an array, one row per day that had activity:

json
[
  { "date": "2026-09-15", "sent": 264, "received": 771, "bounced": 1 },
  { "date": "2026-09-16", "sent": 301, "received": 688, "bounced": 0 }
]

The two account-level endpoints are the only ones that take no domain in the path.

Unsubscribes ​

Every message you send carries a one-click unsubscribe link. When a recipient uses it, their address is added to your domain's suppression list and you stop sending to it.

http
GET /api/unsubscribes/:domainId?page=1&limit=20

Needs email:read. Note this one takes the domain's id, not its name. Paginated list of unsubscribed addresses:

bash
curl https://cloud-api.microapps.io/api/unsubscribes/6a4d5b83b7006ccae6391c41 \
  -H "Authorization: Bearer $MICROAPPS_API_KEY"
json
{
  "data": [
    {
      "id": "6a4d5b83b7006ccae6392055",
      "email": "[email protected]",
      "domain": "example.com",
      "accountId": "6a4d5b83b7006ccae639100a",
      "domainId": "6a4d5b83b7006ccae6391c41",
      "createdAt": "2026-09-14T18:22:41Z"
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 20,
  "totalPages": 1
}
http
DELETE /api/unsubscribes/:domainId/:email

Needs email:update. Removes an address from the list, which re-enables sending to it. Returns 204. A malformed domain id returns 400 "Invalid domain ID".

bash
curl -X DELETE https://cloud-api.microapps.io/api/unsubscribes/6a4d5b83b7006ccae6391c41/[email protected] \
  -H "Authorization: Bearer $MICROAPPS_API_KEY"

Built for the long tail.