Skip to content

Send via API

POST /api/v1/emails/send

Terminal window
curl -X POST https://api.relaypost.dev/v1/emails/send \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"from": { "email": "hello@yourdomain.com", "name": "Your App" },
"to": [{ "email": "user@example.com" }],
"subject": "Your receipt",
"html": "<h1>Thanks for your purchase!</h1><p>Order #1234</p>"
}'
FieldTypeRequiredDescription
fromobjectYesSender — { "email": "...", "name": "..." }
toarrayYesRecipients — [{ "email": "...", "name": "..." }]
ccarrayNoCC recipients
bccarrayNoBCC recipients
subjectstringYesEmail subject line
htmlstringNoHTML body
textstringNoPlain text body
template_idstringNoUse a saved template instead of inline content
template_dataobjectNoKey-value pairs for template variables
headersobjectNoCustom email headers
scheduled_atstringNoISO 8601 datetime for scheduled delivery

You must provide either html, text, or template_id.

{
"data": {
"message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "queued",
"queued_at": "2025-01-15T10:30:00.000Z"
}
}
StatusCodeDescription
400VALIDATION_ERRORMissing or invalid fields
400DOMAIN_NOT_VERIFIEDFrom address uses an unverified domain
400RECIPIENTS_SUPPRESSEDOne or more recipients are on the suppression list
429LIMIT_EXCEEDEDOrganization email sending limit exceeded
{
"from": { "email": "orders@yourapp.com" },
"to": [{ "email": "customer@example.com" }],
"subject": "Your receipt",
"template_id": "tmpl_abc123",
"template_data": {
"order_number": "1234",
"total": "$49.99"
}
}

GET /api/v1/emails/:id

Retrieve a specific email by its ID or message ID, including delivery events.

Terminal window
curl https://api.relaypost.dev/v1/emails/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer YOUR_API_KEY"
{
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"from_address": "hello@yourdomain.com",
"to_addresses": ["user@example.com"],
"subject": "Your receipt",
"status": "delivered",
"priority": "normal",
"created_at": "2025-01-15T10:30:00.000Z",
"updated_at": "2025-01-15T10:30:05.000Z",
"scheduled_at": null,
"events": [
{
"id": "evt_001",
"type": "delivered",
"recipient": "user@example.com",
"smtp_code": 250,
"smtp_message": "OK",
"created_at": "2025-01-15T10:30:05.000Z"
}
]
}
}
StatusCodeDescription
404NOT_FOUNDEmail not found or belongs to another organization

GET /api/v1/emails

Retrieve a paginated list of emails for your organization.

Terminal window
curl "https://api.relaypost.dev/v1/emails?status=delivered&page=1&limit=10" \
-H "Authorization: Bearer YOUR_API_KEY"
ParameterTypeDefaultDescription
statusstringFilter by status: queued, delivered, bounced, failed, opened
from_datestringISO 8601 start date
to_datestringISO 8601 end date
pageinteger1Page number
limitinteger20Results per page (max 100)
{
"data": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"from_address": "hello@yourdomain.com",
"to_addresses": ["user@example.com"],
"subject": "Your receipt",
"status": "delivered",
"priority": "normal",
"created_at": "2025-01-15T10:30:00.000Z",
"updated_at": "2025-01-15T10:30:05.000Z"
}
],
"pagination": {
"page": 1,
"limit": 10,
"total_count": 42,
"total_pages": 5
}
}

POST /api/v1/emails/batch

Send the same template to multiple recipients with per-recipient variable data. Maximum 1000 recipients per batch.

Terminal window
curl -X POST https://api.relaypost.dev/v1/emails/batch \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"template_id": "tmpl_abc123",
"from": { "email": "orders@yourapp.com", "name": "Your Store" },
"recipients": [
{
"to": { "email": "alice@example.com" },
"data": { "customerName": "Alice", "orderNumber": "ORD-001" }
},
{
"to": { "email": "bob@example.com" },
"data": { "customerName": "Bob", "orderNumber": "ORD-002" }
}
]
}'
FieldTypeRequiredDescription
template_idstringYesTemplate ID to use for all recipients
fromobjectYesSender — { "email": "...", "name": "..." }
subjectstringNoOptional subject override (replaces template subject)
recipientsarrayYesArray of recipients (max 1000), each with to and data
{
"data": {
"batch_id": "550e8400-e29b-41d4-a716-446655440000",
"total": 2,
"accepted": 2,
"rejected": []
}
}
StatusCodeDescription
400BATCH_TOO_LARGEExceeds 1000 recipient limit
400TEMPLATE_INACTIVETemplate is not active
402BILLING_LIMIT_EXCEEDEDBatch would exceed your plan’s email limit
404TEMPLATE_NOT_FOUNDTemplate not found

Every email goes through these statuses:

queued → processing → delivered → opened
↘ bounced
↘ failed
↘ rejected
StatusMeaning
queuedAccepted and waiting in the delivery queue
scheduledQueued for future delivery at scheduled_at
processingCurrently being sent
deliveredSuccessfully delivered to the recipient’s mail server
openedRecipient opened the email (if tracking is enabled)
bouncedRecipient’s mail server rejected the email
rejectedRelayPost rejected the email (suppression list, validation failure)
failedDelivery failed after all retry attempts