Send transactional emails, batch messages, and check delivery status. All email endpoints support idempotency via the Idempotency-Key header.
Send Email
/email/sendSend a transactional email to one or more recipients
| Name | Type | Required | Description |
|---|---|---|---|
| to | string | string[] | Required | Recipient email address, or an array of up to 100 email addresses |
| subject | string | Required | Email subject line (max 998 characters) |
| html | string | Optional | HTML body content. Required if text and template_id are not provided. |
| text | string | Optional | Plain text body content. Required if html and template_id are not provided. |
| template_id | string (UUID) | Optional | ID of a saved template to use. Required if html and text are not provided. |
| template_data | Record<string, string> | Optional | Key-value pairs for template variable substitution using {{variable}} syntax |
| from_email | string | Optional | Sender email address. Falls back to workspace default if not provided. |
| from_name | string | Optional | Sender display name (max 100 characters). Defaults to workspace setting or "TopMail". |
| reply_to | string | Optional | Reply-to email address |
| track_opens | boolean | Optional | Enable open tracking. Defaults to true. |
| track_clicks | boolean | Optional | Enable click tracking. Defaults to true. |
| send_at | string (ISO 8601) | Optional | Schedule delivery for a future time. Must be within 72 hours. |
curl -X POST https://api.topmail.so/api/v1/email/send \-H "Authorization: Bearer tm_live_abc123" \-H "Content-Type: application/json" \-d '{"to": "user@example.com","subject": "Welcome to TopMail","html": "<h1>Hello {{first_name}}</h1><p>Thanks for signing up!</p>","from_email": "hello@yourdomain.com","from_name": "Your App","reply_to": "support@yourdomain.com","track_opens": true,"track_clicks": true}'
{"data": {"sent": 1,"failed": 0,"skipped": 0,"total": 1,"results": [{"to": "user@example.com","message_id": "ses-message-id-12345","success": true}]}}
Multiple Recipients
Pass an array of up to 100 email addresses in the to field. Each recipient is processed independently -- suppressed or invalid addresses are skipped without failing the entire request. The response includes per-recipient results.
Scheduled Sends
Include a send_at parameter with an ISO 8601 datetime to schedule an email for future delivery. The schedule must be within 72 hours from the current time.
curl -X POST https://api.topmail.so/api/v1/email/send \-H "Authorization: Bearer tm_live_abc123" \-H "Content-Type: application/json" \-d '{"to": "user@example.com","subject": "Your weekly digest","html": "<h1>Weekly Digest</h1><p>Here are your updates...</p>","send_at": "2025-01-15T09:00:00Z"}'
Sandbox Mode
When using a sandbox API key (prefixed with tm_test_), emails are not actually sent. The API returns mock success responses with simulated message IDs, allowing you to test your integration without sending real emails or consuming your email quota.
Batch Send
/email/batchSend up to 1,000 emails in a single request. Each message can have unique content, recipients, and settings.
Each item in the messages array accepts the same fields as the single send endpoint (except send_at), but with a single to address per message.
| Name | Type | Required | Description |
|---|---|---|---|
| messages | array | Required | Array of 1-1,000 message objects |
| messages[].to | string | Required | Recipient email address |
| messages[].subject | string | Required | Email subject line |
| messages[].html | string | Optional | HTML body content |
| messages[].text | string | Optional | Plain text body content |
| messages[].template_id | string (UUID) | Optional | Template ID to use |
| messages[].template_data | Record<string, string> | Optional | Template variable substitution |
| messages[].from_email | string | Optional | Sender email (defaults to workspace setting) |
| messages[].from_name | string | Optional | Sender display name |
| messages[].reply_to | string | Optional | Reply-to address |
| messages[].track_opens | boolean | Optional | Enable open tracking (default: true) |
| messages[].track_clicks | boolean | Optional | Enable click tracking (default: true) |
curl -X POST https://api.topmail.so/api/v1/email/batch \-H "Authorization: Bearer tm_live_abc123" \-H "Content-Type: application/json" \-d '{"messages": [{"to": "alice@example.com","subject": "Your order shipped!","html": "<p>Hi Alice, your order #1234 is on the way.</p>"},{"to": "bob@example.com","subject": "Your order shipped!","html": "<p>Hi Bob, your order #5678 is on the way.</p>"}]}'
{"data": {"batch_id": "batch-uuid-12345","status": "completed","total": 2,"sent": 2,"failed": 0}}
Batch Status
/email/batch/:batchIdCheck the status of a batch send
| Name | Type | Required | Description |
|---|---|---|---|
| batchId | string | Required | The batch ID returned from the batch send endpoint (URL parameter) |
curl https://api.topmail.so/api/v1/email/batch/batch-uuid-12345 \-H "Authorization: Bearer tm_live_abc123"
{"data": {"batch_id": "batch-uuid-12345","status": "completed","total": 100,"sent": 98,"failed": 2,"created_at": "2025-01-15T08:30:00.000Z","completed_at": "2025-01-15T08:30:45.000Z"}}
Message Status
/email/:messageId/statusLook up the delivery status of a sent message
| Name | Type | Required | Description |
|---|---|---|---|
| messageId | string | Required | The SES message ID returned from the send endpoint (URL parameter) |
curl https://api.topmail.so/api/v1/email/ses-message-id-12345/status \-H "Authorization: Bearer tm_live_abc123"
{"data": {"message_id": "ses-message-id-12345","status": "delivered","to": "user@example.com","sent_at": "2025-01-15T08:30:00.000Z","delivered_at": "2025-01-15T08:30:02.000Z","opened_at": "2025-01-15T09:15:30.000Z","clicked_at": "2025-01-15T09:16:00.000Z","bounced_at": null,"bounce_type": null}}
Idempotency
The send and batch endpoints support idempotent requests to prevent duplicate sends caused by network retries. Include an Idempotency-Key header with a unique value (e.g., a UUID). If a request with the same key has already been processed, the original response will be returned without resending the email.
curl -X POST https://api.topmail.so/api/v1/email/send \-H "Authorization: Bearer tm_live_abc123" \-H "Content-Type: application/json" \-H "Idempotency-Key: unique-request-id-12345" \-d '{"to": "user@example.com","subject": "Order confirmation","html": "<p>Your order has been confirmed.</p>"}'