Covers the 7 API operations in the email category.
| Method | Path | Description |
|---|---|---|
| POST | /v1/hooks/ses | SES bounce, complaint and delivery webhook (called by SNS, docs/email.md §6.2) |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/email | Email status (runlot email) |
| POST | /v1/orgs/{orgSlug}/projects/{projectName}/email | Turn on email (the deploy reads "email": true and calls this) |
| DELETE | /v1/orgs/{orgSlug}/projects/{projectName}/email | Turn off email (runlot email delete) |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/email/log | Mail log (runlot email log) |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/email/log/{mailId} | Metadata for one message |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/email/log/{mailId}/raw | Raw message (message/rfc822) |
POST /v1/hooks/ses
This is not a path you call. Amazon SNS delivers SES events here through an HTTPS subscription. Authentication is not a token but the SNS signature — it is accepted only when the certificate URL is https on sns.<region>.amazonaws.com and the topic matches the server's RUNLOT_SES_SNS_TOPIC_ARN (otherwise 403). A SubscriptionConfirmation is finished automatically by issuing a GET to SubscribeURL. If the server has no topic ARN, 501. Client libraries do not call it.
operationId sesHook
Request body: text/plain · string
| Status | Description | Response body |
|---|---|---|
| 200 | Received (an unknown event type or an unknown id also returns 200) | — |
| 400 | — | — |
| 403 | The SNS signature does not match | — |
| 501 | The webhook is off | — |
GET /v1/orgs/{orgSlug}/projects/{projectName}/email
Whether enabled, the address, the sender, the hourly limit, and recent send/receive counts (docs/email.md §5). address and from are filled in even when not enabled — they are the material for "this is the address you would get". granted is the real state.
Requires viewer or above.
operationId getEmail
| Status | Description | Response body |
|---|---|---|
| 200 | Email status | EmailStatus |
| 403 | — | — |
| 404 | — | — |
| 503 | no_core | Error |
POST /v1/orgs/{orgSlug}/projects/{projectName}/email
Idempotent. There is no request body — the address is ours to decide (<project>.<org>.<mail-domain>) and the limit comes from the plan. The address is fixed at the names in effect when it was granted.
Once enabled, the node wires env.email at the next convergence and mail sent to the address reaches the worker's email(). Sending and receiving are enabled together — one domain is the name for both directions.
member or above. Audit email.grant.
operationId grantEmail
| Status | Description | Response body |
|---|---|---|
| 200 | Grant status (the existing values if it already existed) | EmailStatus |
| 403 | — | — |
| 404 | — | — |
| 409 | email_unavailable — this deployment has no mail domain. email_address_taken — another project holds the same address | Error |
| 503 | no_core | Error |
DELETE /v1/orgs/{orgSlug}/projects/{projectName}/email
Mail to the address is now 550 — the sending MTA gets a bounce and does not retry. Idempotent.
admin or above. Audit email.revoke.
operationId revokeEmail
| Status | Description | Response body |
|---|---|---|
| 204 | Disabled | — |
| 403 | — | — |
| 404 | — | — |
| 503 | no_core | Error |
GET /v1/orgs/{orgSlug}/projects/{projectName}/email/log
One row per message sent and received, newest first (docs/email.md §6.1). Envelope, outcome, size and SPF result. The raw message is at …/log/{mailId}/raw.
Retention is the plan's current value — 30 days on free, 365 days on pro (keepDays).
Requires viewer or above.
operationId listMailLog
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
direction | query | No | string | Both when empty |
cursor | query | No | string | The cursor from the previous page |
limit | query | No | integer | — |
| Status | Description | Response body |
|---|---|---|
| 200 | One page | MailLogPage |
| 403 | — | — |
| 404 | — | — |
GET /v1/orgs/{orgSlug}/projects/{projectName}/email/log/{mailId}
An id outside the project is a 404 — you cannot feel around another project's log by id. Requires viewer or above.
operationId getMailLog
| Status | Description | Response body |
|---|---|---|
| 200 | One message | MailLogEntry |
| 403 | — | — |
| 404 | — | — |
GET /v1/orgs/{orgSlug}/projects/{projectName}/email/log/{mailId}/raw
The raw message as it is, headers included. Received mail includes the Received and Authentication-Results headers we added; sent mail is assembled from what was handed to the relay. It downloads as .eml. A row with no raw message (hasRaw: false) is a 404. Requires viewer or above.
operationId getMailLogRaw
| Status | Description | Response body |
|---|---|---|
| 200 | Raw message | string |
| 403 | — | — |
| 404 | — | — |