Public exception
GET /api/domains is public so clients can discover available receiving domains before creating an inbox.
API REFERENCE
Built for developers and enterprises receiving email at scale.
https://api.mail.tdJSON over HTTPSOpenAPI 3.0.3Use an API token from the Pro dashboard. The domain in the example is a placeholder—select one returned by GET /api/domains.
# Base URL: https://api.mail.td
TOKEN=td_xxxxxxxxxxxxxxxxxxxx
# 1. Choose an available receiving domain
curl https://api.mail.td/api/domains
# 2. Create an inbox
curl -X POST https://api.mail.td/api/accounts \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"address":"build-42@example.com","password":"use-a-long-password"}'
# 3. Read its messages (UUID or full email address both work)
curl "https://api.mail.td/api/accounts/build-42@example.com/messages?page=1" \
-H "Authorization: Bearer $TOKEN"{account_id} accepts either the mailbox UUID or its full email address. URL-encode addresses when required by your HTTP client.
External integrations use one credential: a Pro API token. Send it in every protected request. Tokens start with td_, do not expire automatically and can be revoked from the dashboard or API.
Authorization: Bearer td_xxxxxxxxxxxxxxxxxxxx Content-Type: application/json
GET /api/domains is public so clients can discover available receiving domains before creating an inbox.
Every other endpoint on this page uses a long-lived td_ token scoped to its registered user and owned resources.
Create and manage receive-only addresses. Passwords are never returned; save them when created.
/api/domainsPublicList system domains available for new inboxes.
200 · { domains: [{ id, domain, is_active, pro_only }] }/api/accountsAPI tokenCreate an inbox on an available system domain or a verified custom domain. The returned mailbox token is separate from your API token.
{ address, password }201 · { id, address, token }/api/accounts/{account_id}API tokenGet address, role, storage quota and usage.
200 · { id, address, role, quota, used, created_at }/api/accounts/{account_id}API tokenPermanently delete an inbox and all of its messages.
204 · No Content/api/accounts/{account_id}/reset-passwordAPI tokenReplace mailbox credentials and invalidate its existing mailbox tokens.
{ password } or { auth_key }200 · { message: "password_reset" }Lists are paginated at 30 messages. A page with fewer than 30 items is the final page. Message detail contains sanitized display fields plus attachment metadata.
/api/accounts/{account_id}/messages?page=1API tokenList messages newest first, 30 per page.
200 · { messages: MessageSummary[], page }/api/accounts/{account_id}/messagesAPI tokenDelete all messages currently visible in the inbox.
200 · { deleted, reclaimed_bytes }/api/accounts/{account_id}/messages/readAPI tokenMark up to 200 message IDs, or every message, as read.
{ ids: ["..."] } or { all: true }200 · { updated }/api/accounts/{account_id}/messages/{id}API tokenRead bodies, headers and attachment metadata.
200 · Message/api/accounts/{account_id}/messages/{id}API tokenDelete one message and reclaim its storage.
204 · No Content/api/accounts/{account_id}/messages/{id}/sourceAPI tokenDownload the original RFC 822 message.
200 · message/rfc822 (.eml)/api/accounts/{account_id}/messages/{id}/readAPI tokenMark one message as read. Idempotent.
204 · No Content/api/accounts/{account_id}/messages/{id}/attachments/{index}API tokenDownload an attachment using its zero-based index from message detail.
200 · Binary body with Content-Type and Content-Disposition{
"id": "f5e6d7c8-...",
"sender": "noreply@example.com",
"from": "Example <noreply@example.com>",
"subject": "Verify your email",
"address": "build-42@example.com",
"text_body": "Click the link below to verify...",
"html_body": "<html>...</html>",
"size": 4523,
"is_read": false,
"attachments": [
{ "index": 0, "filename": "result.pdf", "content_type": "application/pdf", "size": 12345 }
],
"created_at": "2026-08-03T10:30:00Z"
}These endpoints operate across resources owned by the registered user.
/api/user/meAPI tokenGet user, plan, status, limits and monthly operation usage.
200 · ProUser/api/user/accounts?cursor=&q=API tokenList owned inboxes. Use cursor for the next page and q to search.
200 · { accounts, next_cursor }/api/user/accounts/{id}API tokenDelete an owned inbox and its messages.
204 · No Content/api/user/accounts/{id}/reset-passwordAPI tokenReset an owned inbox password.
{ password } or { auth_key }200 · { message: "password_reset" }/api/user/accounts/{id}/messages?page=1API tokenList messages for an owned inbox.
200 · { messages, page }Add the DNS record returned by the create call, then request verification. Only verified domains can receive mail.
/api/user/domainsAPI tokenList custom domains and their verification state.
200 · { domains: CustomDomain[] }/api/user/domainsAPI tokenAdd a receiving domain and receive the required DNS records.
{ domain: "mail.example.com" }201 · { id, domain, verify_token, dns_records }/api/user/domains/{id}/verifyAPI tokenCheck the required TXT and MX records and activate a correctly configured domain.
200 · { verify_status, txt_record?, mx_record?, dns_records?, message? }/api/user/domains/{id}API tokenRemove a custom domain. Delete every inbox on the domain first or the API returns 409 domain_has_accounts.
204 · No Content/api/user/tokensAPI tokenList active token metadata. Secret token values are never returned again.
200 · { tokens: [{ id, name, last_used_at, created_at, revoked_at }] }/api/user/tokensAPI tokenCreate a long-lived API token. Store the returned td_ token immediately.
{ name: "CI inboxes" }201 · { id, name, token }/api/user/tokens/{id}API tokenRevoke a token immediately.
204 · No Content/api/user/webhooksAPI tokenList webhook endpoints and delivery health.
200 · { webhooks: Webhook[] }/api/user/webhooksAPI tokenRegister an HTTPS endpoint for email.received. The signing secret is returned once.
{ url, events: ["email.received"] }201 · { id, url, events, secret, status, created_at }/api/user/webhooks/{id}API tokenDelete a webhook.
204 · No Content/api/user/webhooks/{id}/rotateAPI tokenRotate the signing secret; the previous secret stops working immediately.
200 · { id, secret }/api/user/webhooks/{id}/deliveriesAPI tokenInspect recent attempts, status codes, latency and errors.
200 · { deliveries: WebhookDelivery[] }All three clients use the same td_ API token and cover accounts, messages, custom domains, webhooks, tokens and user management with typed errors.
npm install mailtdZero dependencies, native fetch and full TypeScript definitions.
pip install mailtdhttpx-based, dataclass models and context-manager support.
go get github.com/mailtd/mailtd-goStandard net/http, context support and typed structs.
import { MailTD } from "mailtd";
const client = new MailTD("td_...");
const account = await client.accounts.create("test@example.com", {
password: "use-a-long-password"
});
const { messages } = await client.messages.list(account.id);
const message = await client.messages.get(account.id, messages[0].id);
console.log(message.subject, message.text_body);from mailtd import MailTD
client = MailTD("td_...")
account = client.accounts.create(
"test@example.com", password="use-a-long-password"
)
messages, page = client.messages.list(account.id)
message = client.messages.get(account.id, messages[0].id)
print(message.subject, message.text_body)client := mailtd.NewClient("td_...")
ctx := context.Background()
password := "use-a-long-password"
account, err := client.Accounts.Create(ctx, "test@example.com", &mailtd.CreateOptions{
Password: &password,
})
if err != nil { log.Fatal(err) }
result, err := client.Messages.List(ctx, account.ID, nil)
if err != nil { log.Fatal(err) }
message, err := client.Messages.Get(ctx, account.ID, result.Data[0].ID)External API integrations receive new-message events through webhooks. Register an HTTPS URL, respond with a 2xx within 5 seconds, and verify every signature against the raw request body. Failed deliveries are retried after 15 seconds, 1 minute, 5 minutes, 10 minutes and 20 minutes. A webhook is marked failing after five consecutive events each exhaust all delivery attempts; it then stops receiving new events.
X-Webhook-ID: evt_... X-Webhook-Timestamp: 1785740000 X-Webhook-Signature: sha256=<hex> signed_payload = timestamp + "." + raw_request_body expected = HMAC-SHA256(webhook_secret, signed_payload)
The flat data object includes complete text and HTML bodies for normal-size messages when content_status is ready. A status of failed or pending_timeout is an explicit metadata-only fallback. Attachments contain metadata and authenticated download paths, never attachment bytes or internal storage IDs. Events are capped at 1,000,000 bytes; check content_truncated and attachments_omitted. Delivery is at least once, so deduplicate with the stable event id.
{
"id": "evt_f5e6d7c8-...", "type": "email.received", "created_at": "...",
"data": { "email_id": "f5e6d7c8-...", "account_id": "a1b2c3d4-...",
"address": "build-42@example.com", "from": "Example <noreply@example.com>",
"to": "build-42@example.com", "sender": "noreply@example.com",
"subject": "Verify your email", "preview_text": "Click the link...",
"text_body": "Click the link below...", "html_body": "<p>Click the link below...</p>",
"attachments": [{ "index": 0, "filename": "result.pdf",
"content_type": "application/pdf", "size": 12345,
"download_url": "/api/accounts/a1b2c3d4-.../messages/f5e6d7c8-.../attachments/0" }],
"content_status": "ready", "content_truncated": false,
"attachments_omitted": 0, "size": 4523, "created_at": "..." }
}GET /api/user/me.429; use webhooks instead of aggressive polling.td_ token or webhook secret in browser code.{ "error": "invalid_or_expired_token", "message": "Optional human-readable detail" }