Messages API
6 min read
The Messages API lets you send transactional emails, track delivery status, and manage scheduled messages.
Send email
Send a single email message.
POST /v1/messages/send
Request body
| Field | Type | Required | Description |
|---|---|---|---|
from |
string | Yes | Sender address (must match verified domain) |
to |
string/array | Yes | Recipient address(es) |
subject |
string | Yes | Email subject line |
html |
string | * | HTML body (* at least one of html/text required) |
text |
string | * | Plain text body |
cc |
array | No | CC recipients |
bcc |
array | No | BCC recipients |
headers |
object | No | Custom email headers |
attachments |
array | No | File attachments |
template_id |
string | No | Template ID to use |
template_data |
object | No | Template variables |
tags |
array | No | Tags for analytics |
metadata |
object | No | Custom metadata |
tracking |
object | boolean | No |
Tracking settings (false disables both) |
transactional |
boolean | No | Declares transactional mail — same effect as disabling both trackings |
scheduled_at |
string | No | ISO 8601 datetime for scheduled send |
optimize_send_time |
boolean | No | Optimize delivery timing |
Example request
curl -X POST https://api.mailingapi.com/v1/messages/send \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Your Company <hello@yourdomain.com>",
"to": "John Doe <john@example.com>",
"subject": "Your order has shipped",
"html": "<h1>Order Shipped</h1><p>Hi {{name}}, your order #{{order_id}} is on the way!</p>",
"text": "Order Shipped\n\nHi {{name}}, your order #{{order_id}} is on the way!",
"template_data": {
"name": "John",
"order_id": "12345"
},
"tags": ["transactional", "shipping"],
"metadata": {
"user_id": "usr_123",
"order_id": "ord_456"
}
}'
Response
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"message_id": "<abc123@mailingapi.com>",
"from": "hello@yourdomain.com",
"to": "john@example.com",
"subject": "Your order has shipped",
"status": "queued",
"tags": ["transactional", "shipping"],
"metadata": {"user_id": "usr_123", "order_id": "ord_456"},
"created_at": "2024-01-15T10:30:00Z"
}
}
Attachments
{
"attachments": [
{
"filename": "invoice.pdf",
"content": "base64-encoded-content",
"content_type": "application/pdf"
},
{
"filename": "logo.png",
"content": "base64-encoded-content",
"content_type": "image/png",
"content_id": "logo"
}
]
}
Use content_id for inline images, then reference with <img src="cid:logo">.
Tracking options
Control open and click tracking per message:
{
"tracking": {
"opens": true,
"clicks": true
}
}
| Field | Type | Default | Description |
|---|---|---|---|
opens |
boolean |
true |
Track email opens (inserts a tracking pixel) |
clicks |
boolean |
true |
Track link clicks (rewrites URLs through tracking domain) |
When both opens and clicks are set to false, the email is treated as transactional:
- No tracking pixel is inserted
- Links are not rewritten
-
List-Unsubscribeheader is not added (prevents Gmail from classifying the email as promotional/bulk)
Best practice: Disable tracking for transactional notifications (password resets, order confirmations, system alerts) to improve inbox placement. Keep tracking enabled for marketing and newsletter emails.
{
"from": "alerts@yourdomain.com",
"to": "user@example.com",
"subject": "New login detected",
"html": "<p>A new login was detected on your account.</p>",
"tracking": {
"opens": false,
"clicks": false
}
}
Shorthands
tracking also accepts a plain boolean, and transactional states the intent
directly. All three of these are equivalent:
{ "tracking": { "opens": false, "clicks": false } }
{ "tracking": false }
{ "transactional": true }
transactional takes precedence over tracking — it is the more specific
declaration, so {"transactional": true, "tracking": {"opens": true}} still
sends with tracking off.
Anything else is an error. A
trackingvalue that is neither an object nor a boolean (for example"tracking": "off") returns 400. Until 2026-07 such values were silently ignored, so a caller could believe tracking was off while the pixel kept shipping. If you integrated before that date, check that you are sending one of the three shapes above.
Why this matters beyond deliverability
Click tracking rewrites every href to https://api.mailingapi.com/c/<id>.
If your links carry credentials — invitation tokens, magic links, one-time
password-reset URLs — those credentials travel through, and are logged by, this
service. An outage of the redirect also breaks links already delivered. For
that class of mail, turn tracking off rather than treating it as a spam-folder
tuning knob.
Batch send
Send multiple personalized emails in one request.
POST /v1/messages/batch
Using recipient variables
curl -X POST https://api.mailingapi.com/v1/messages/batch \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "hello@yourdomain.com",
"subject": "Welcome, {{name}}!",
"html": "<p>Hi {{name}}, your code is {{code}}.</p>",
"recipient_variables": {
"alice@example.com": {"name": "Alice", "code": "ABC123"},
"bob@example.com": {"name": "Bob", "code": "XYZ789"}
}
}'
Using messages array
curl -X POST https://api.mailingapi.com/v1/messages/batch \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"from": "hello@yourdomain.com",
"to": "alice@example.com",
"subject": "Your invoice",
"html": "<p>Invoice #001 attached.</p>"
},
{
"from": "hello@yourdomain.com",
"to": "bob@example.com",
"subject": "Your receipt",
"html": "<p>Receipt #002 attached.</p>"
}
]
}'
Response
{
"data": {
"total": 2,
"queued": 2,
"errors": 0,
"messages": [
{"index": 0, "status": "queued", "id": "550e8400-e29b-41d4-a716-446655440000", "to": "alice@example.com"},
{"index": 1, "status": "queued", "id": "550e8400-e29b-41d4-a716-446655440001", "to": "bob@example.com"}
]
}
}
Limits
- Maximum 1,000 messages per request
- Each message processed independently
- Partial failures don’t block others
Get message
Retrieve details of a sent message.
GET /v1/messages/{message_id}
Example request
curl https://api.mailingapi.com/v1/messages/msg_1a2b3c4d5e6f \
-H "Authorization: Bearer $API_KEY"
Response
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"message_id": "<abc123@mailingapi.com>",
"from": "hello@yourdomain.com",
"to": "john@example.com",
"subject": "Your order has shipped",
"status": "delivered",
"sent_at": "2024-01-15T10:30:02Z",
"delivered_at": "2024-01-15T10:30:05Z",
"opened_at": "2024-01-15T11:45:00Z",
"tags": ["transactional", "shipping"],
"metadata": {"user_id": "usr_123", "order_id": "ord_456"},
"created_at": "2024-01-15T10:30:00Z"
}
}
Message statuses
| Status | Description |
|---|---|
pending |
Message created, not yet queued |
queued |
Message accepted, waiting to send |
sent |
Message sent to recipient server |
delivered |
Message accepted by recipient server |
bounced |
Message rejected by recipient server |
failed |
Permanent failure |
List messages
Retrieve a list of sent messages.
GET /v1/messages
Query parameters
| Parameter | Type | Description |
|---|---|---|
limit |
integer | Results per page (default: 50, max: 100) |
offset |
integer | Number of results to skip (default: 0) |
status |
string | Filter by status |
to |
string | Filter by recipient email |
since |
string | Start date (ISO 8601) |
until |
string | End date (ISO 8601) |
Example request
curl "https://api.mailingapi.com/v1/messages?status=delivered&since=2024-01-01T00:00:00Z&limit=50" \
-H "Authorization: Bearer $API_KEY"
Response
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"from": "hello@yourdomain.com",
"to": "john@example.com",
"subject": "Your order has shipped",
"status": "delivered",
"created_at": "2024-01-15T10:30:00Z"
}
],
"meta": {
"count": 1,
"total": 1250,
"limit": 50,
"offset": 0,
"has_more": true
}
}
Analyze message
Validate an email before sending. Returns spam score and potential issues.
POST /v1/messages/analyze
Example request
curl -X POST https://api.mailingapi.com/v1/messages/analyze \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "hello@yourdomain.com",
"to": "user@example.com",
"subject": "Test email",
"html": "<p>Content here</p>"
}'
Response
{
"data": {
"score": 85,
"grade": "good",
"issues_count": 1,
"critical_count": 0,
"high_count": 0,
"medium_count": 1,
"low_count": 0,
"can_send": true,
"recommendations": [
"Consider adding a text version for better deliverability"
],
"issues": [
{
"type": "content",
"subtype": "missing_text",
"severity": "medium",
"detail": "No plain text version",
"penalty": 5
}
]
}
}
Schedule message
Schedule an email for future delivery. Use scheduled_at in send request:
curl -X POST https://api.mailingapi.com/v1/messages/send \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "hello@yourdomain.com",
"to": "user@example.com",
"subject": "Holiday greeting",
"html": "<p>Happy holidays!</p>",
"scheduled_at": "2024-12-25T09:00:00Z"
}'
List scheduled messages
GET /v1/messages/scheduled
Response
{
"data": [
{
"id": "msg_abc123",
"to": "user@example.com",
"subject": "Holiday greeting",
"scheduled_at": "2024-12-25T09:00:00Z",
"status": "scheduled"
}
]
}
Cancel scheduled message
DELETE /v1/messages/{message_id}/schedule
Example request
curl -X DELETE https://api.mailingapi.com/v1/messages/msg_abc123/schedule \
-H "Authorization: Bearer $API_KEY"
Response
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "cancelled",
"created_at": "2024-01-15T10:30:00Z"
}
}
Message events
Get the event history for a message.
GET /v1/messages/{message_id}/events
Example request
curl https://api.mailingapi.com/v1/messages/550e8400-e29b-41d4-a716-446655440000/events \
-H "Authorization: Bearer $API_KEY"
Response
{
"data": [
{"id": "evt_1", "type": "queued", "timestamp": "2024-01-15T10:29:55Z", "metadata": {}},
{"id": "evt_2", "type": "sent", "timestamp": "2024-01-15T10:30:00Z", "metadata": {}},
{"id": "evt_3", "type": "delivered", "timestamp": "2024-01-15T10:30:05Z", "metadata": {}},
{"id": "evt_4", "type": "opened", "timestamp": "2024-01-15T11:00:00Z", "metadata": {"user_agent": "Mozilla/5.0"}}
]
}
Event types
| Type | Description |
|---|---|
queued |
Message entered the send queue |
sent |
Message handed off to recipient server |
delivered |
Recipient server accepted the message |
opened |
Recipient opened the email |
clicked |
Recipient clicked a link |
bounced |
Message was rejected |
complained |
Recipient marked as spam |
unsubscribed |
Recipient unsubscribed |
Error codes
| Code | Description |
|---|---|
invalid_from_address |
From address invalid or not from verified domain |
invalid_to_address |
To address is invalid |
missing_subject |
Subject line required |
missing_body |
HTML or text body required |
attachment_too_large |
Attachment exceeds 10 MB |
too_many_attachments |
Maximum 10 attachments |
invalid_template |
Template not found or inactive |
domain_not_verified |
Sending domain not verified |
rate_limit_exceeded |
Too many requests |