Send Email
POST /v1/send
Send an email through Optail. The API validates the request, checks suppressions, resolves the provider via routing rules, and queues the email for delivery. Returns 202 Accepted immediately.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
to | string | string[] | Yes | Recipient email(s). Max 1,000 per request. |
from | string | Yes | Sender email address. Domain must be verified on the resolved provider. |
subject | string | Yes | Email subject line (max 998 characters). |
html | string | Conditional | HTML body. Required if templateId and text are not provided. |
text | string | Conditional | Plain text body. Required if templateId and html are not provided. |
templateId | string | Conditional | UUID of a template to render. Required if html and text are not provided. |
variables | object | No | Key-value pairs for Handlebars template variables. |
replyTo | string | No | Reply-to email address. |
tags | string[] | No | Up to 10 tags (max 100 chars each). Used for routing and analytics. |
metadata | object | No | Arbitrary metadata stored with the message. |
unsubscribeGroupId | string | No | UUID of the unsubscribe group. Adds an unsubscribe link and checks group-specific suppressions. |
At least one of templateId, html, or text must be provided.
Response
Status: 202 Accepted
{
"messageId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"providerId": "p1q2r3s4-t5u6-7890-vwxy-z12345678901",
"providerType": "SENDGRID",
"status": "queued",
"domainVerified": true
}
If all recipients are suppressed:
{
"messageId": null,
"providerId": null,
"status": "suppressed",
"suppressedCount": 1
}
Examples
curl
curl -X POST https://api.optail.io/v1/send \
-H "Authorization: Bearer ms_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"to": "user@example.com",
"from": "hello@yourdomain.com",
"subject": "Welcome!",
"html": "<h1>Hello World</h1>",
"tags": ["welcome"]
}'
Node.js SDK
import { Optail } from '@optail/node';
const optail = new Optail({
apiKey: process.env.OPTAIL_API_KEY,
});
const result = await optail.send({
to: 'user@example.com',
from: 'hello@yourdomain.com',
subject: 'Welcome!',
html: '<h1>Hello World</h1>',
tags: ['welcome'],
});
Template-based send
curl -X POST https://api.optail.io/v1/send \
-H "Authorization: Bearer ms_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"to": "user@example.com",
"from": "hello@yourdomain.com",
"subject": "Welcome, {{name}}!",
"templateId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"variables": {
"name": "Jane",
"activationUrl": "https://app.example.com/activate?token=abc"
},
"unsubscribeGroupId": "g1h2i3j4-k5l6-7890-mnop-q12345678901"
}'
POST /v1/emails/batch
Send multiple emails in a single request. Each message is independently validated and queued.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
messages | SendEmailParams[] | Yes | Array of email objects (same schema as single send). |
Response
Status: 200 OK
{
"results": [
{ "messageId": "msg-1-uuid", "status": "queued" },
{ "messageId": "msg-2-uuid", "status": "queued" },
{ "error": "Validation failed: 'to' is required" }
]
}
Node.js SDK
const result = await optail.sendBatch({
messages: [
{
to: 'alice@example.com',
from: 'hello@yourdomain.com',
subject: 'Hello Alice',
html: '<p>Hi Alice!</p>',
},
{
to: 'bob@example.com',
from: 'hello@yourdomain.com',
subject: 'Hello Bob',
html: '<p>Hi Bob!</p>',
},
],
});
for (const item of result.results) {
if ('messageId' in item) {
console.log(`Sent: ${item.messageId}`);
} else {
console.error(`Failed: ${item.error}`);
}
}
How Routing Works
When you send an email, Optail resolves which provider to use:
- Match routing rules by domain and tags, ordered by priority (highest first)
- The first matching rule's provider is selected
- If no rule matches, the first active provider account is used as a fallback
Configure routing rules in the dashboard or via the Providers API.