Email Sending Guide
This comprehensive guide covers everything you need to know about sending emails through EDITH, including request structure, personalization, attachments, tracking, and best practices.
Overview
The Email Send API enables you to send transactional and marketing emails with:
- HTML and plain text content
- File attachments
- Open and click tracking
- Per-recipient personalization
- Email validation
- Priority queue management
Send an Email
Endpoint
POST /v1/email/send
Authentication
Requires Bearer token authentication.
Request Body Structure
Complete Request Schema
{
"from": {
"email": "sender@mail.yourcompany.com",
"name": "Your Company"
},
"to": [
{
"email": "recipient@example.com",
"name": "John Doe"
}
],
"cc": [],
"bcc": [],
"replyTo": "support@yourcompany.com",
"subject": "Your Order Confirmation",
"content": [
{
"type": "text/html",
"value": "<html>...</html>"
},
{
"type": "text/plain",
"value": "Plain text version..."
}
],
"attachments": [],
"headers": {},
"substitutions": {},
"custom_args": {},
"campaign_id": "order-confirmation-2024",
"mailer_id": "domain_01JC3BBW8S9YGX2VNKG5MD7BTA",
"template_id": "",
"settings": {
"open_tracking": { "enable": true },
"click_tracking": { "enable": true },
"validate": { "enable": true },
"phishing_protection": { "enable": false },
"unsubscribe": { "enable": true },
"ip_pool": ""
},
"process_email_inbulk": false,
"priority": 0
}
Field-by-Field Reference
from (Required)
The sender information for the email.
| Field | Type | Required | Description |
|---|---|---|---|
email | string | ✅ Yes | The sender's email address. Must be from a verified domain associated with your account. |
name | string | No | Display name shown to recipients (e.g., "Your Company Support"). If omitted, only the email address appears. |
Example:
{
"from": {
"email": "notifications@mail.yourcompany.com",
"name": "YourCompany Notifications"
}
}
Important Notes:
- The email domain must match a verified sending domain
- The
mailer_idmust correspond to this domain - Using a recognizable sender name improves open rates
to (Required)
Array of primary recipients. At least one recipient is required.
| Field | Type | Required | Description |
|---|---|---|---|
email | string | ✅ Yes | Recipient's email address. Must be a valid email format. |
name | string | No | Recipient's display name. Used for personalization and better deliverability. |
Example:
{
"to": [
{ "email": "john.doe@example.com", "name": "John Doe" },
{ "email": "jane.smith@example.com", "name": "Jane Smith" }
]
}
Limits:
- Maximum recipients when
process_email_inbulk: false: No limit (emails sent individually) - Maximum recipients when
process_email_inbulk: true: Combined to + cc + bcc ≤ 100
cc (Optional)
Carbon copy recipients. They see each other's email addresses.
| Field | Type | Required | Description |
|---|---|---|---|
email | string | ✅ Yes | CC recipient's email address |
name | string | No | CC recipient's display name |
⚠️ Important: CC recipients are only allowed when process_email_inbulk: true
{
"cc": [
{ "email": "manager@example.com", "name": "Team Manager" }
]
}
bcc (Optional)
Blind carbon copy recipients. Hidden from other recipients.
| Field | Type | Required | Description |
|---|---|---|---|
email | string | ✅ Yes | BCC recipient's email address |
name | string | No | BCC recipient's display name |
⚠️ Important: BCC recipients are only allowed when process_email_inbulk: true
replyTo (Optional)
Email address(es) for recipient replies.
| Type | Format | Example |
|---|---|---|
| string | Email only | "support@yourcompany.com" |
| string | Name + Email | "Support Team <support@yourcompany.com>" |
| string | Multiple | "support@yourcompany.com, sales@yourcompany.com" |
Examples:
// Simple email
{ "replyTo": "support@yourcompany.com" }
// With display name
{ "replyTo": "Customer Support <support@yourcompany.com>" }
// Multiple addresses
{ "replyTo": "support@yourcompany.com, billing@yourcompany.com" }
subject (Conditionally Required)
The email subject line.
| Field | Type | Required | Description |
|---|---|---|---|
subject | string | ✅ When no template_id | The subject line displayed to recipients. Required unless using a template. |
Best Practices:
- Keep subjects under 50 characters for mobile compatibility
- Avoid spam trigger words (FREE, URGENT, !!!)
- Personalize with recipient's name when possible
content (Conditionally Required)
Email body content in HTML and/or plain text format.
| Field | Type | Required | Description |
|---|---|---|---|
type | string | ✅ Yes | MIME type: "text/html" or "text/plain" |
value | string | ✅ Yes | The actual content. HTML or plain text depending on type. |
Example with both formats:
{
"content": [
{
"type": "text/html",
"value": "<!DOCTYPE html><html><body><h1>Welcome!</h1><p>Thank you for joining us.</p></body></html>"
},
{
"type": "text/plain",
"value": "Welcome!\n\nThank you for joining us."
}
]
}
Content Requirements:
- Required when
template_idis not provided - Include both HTML and plain text for best deliverability
- HTML should be valid and well-formed
- Keep total content under 25MB
attachments (Optional)
Files to attach to the email.
| Field | Type | Required | Description |
|---|---|---|---|
content | string | ✅ Yes | Base64-encoded file content |
filename | string | ✅ Yes | Filename with extension (e.g., "invoice.pdf") |
type | string | ✅ Yes | MIME type of the file (see supported types below) |
disposition | string | No | "attachment" (default) or "inline" for embedded images |
contentId | string | No | Content-ID for inline images (used in HTML <img src="cid:...">) |
contentLocation | string | No | Original URL of the content (informational) |
Supported MIME Types:
| Category | Types |
|---|---|
| Documents | application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document |
| Spreadsheets | application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
| Presentations | application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation |
| Text | text/plain, text/csv, text/html, text/xml, text/calendar, text/css |
| Images | image/jpeg, image/png, image/gif, image/svg+xml, image/webp, image/bmp, image/tiff |
| Audio | audio/mpeg, audio/wav, audio/ogg |
| Video | video/mp4, video/x-msvideo, video/quicktime, video/webm |
| Archives | application/zip, application/x-tar, application/gzip, application/vnd.rar, application/x-7z-compressed |
| Other | application/json, application/xml, application/rtf, application/octet-stream, message/rfc822 |
Example - Regular Attachment:
{
"attachments": [
{
"content": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9U...",
"filename": "invoice_12345.pdf",
"type": "application/pdf",
"disposition": "attachment"
}
]
}
Example - Inline Image:
{
"attachments": [
{
"content": "iVBORw0KGgoAAAANSUhEUgAAAAUA...",
"filename": "logo.png",
"type": "image/png",
"disposition": "inline",
"contentId": "company-logo"
}
]
}
Then reference in HTML:
<img src="cid:company-logo" alt="Company Logo">
headers (Optional)
Custom email headers.
| Type | Description |
|---|---|
| object | Key-value pairs of custom headers |
Example:
{
"headers": {
"X-Custom-Header": "custom-value",
"X-Priority": "1",
"Message-ID": "<unique-id@yourcompany.com>"
}
}
Common Use Cases:
X-Priority: Email priority (1=High, 3=Normal, 5=Low)Message-ID: Custom message identifierReferences: For email threadingIn-Reply-To: Reference to a previous message
substitutions (Optional)
Per-recipient personalization variables.
| Structure | Description |
|---|---|
{ "recipient@email.com": { "var": "value" } } | Map of recipient email to their variable values |
Example:
{
"substitutions": {
"john@example.com": {
"first_name": "John",
"order_id": "ORD-12345",
"discount": "20%"
},
"jane@example.com": {
"first_name": "Jane",
"order_id": "ORD-12346",
"discount": "15%"
}
}
}
In your content, use double curly braces:
<p>Hello {{first_name}},</p>
<p>Your order {{order_id}} qualifies for {{discount}} off!</p>
⚠️ Important: Substitutions are NOT allowed when process_email_inbulk: true
mailer_id (Required)
The identifier for your email configuration.
| Type | Description |
|---|---|
| string | Unique ID returned when you added a domain or configured SMTP/OAuth |
This ties your email to the correct:
- Verified sending domain
- DKIM/SPF authentication
- IP pool (if configured)
- Tracking domain
template_id (Optional)
Reference a pre-created email template instead of providing content inline.
| Type | Description |
|---|---|
| string | Template ID returned when creating a template |
When using a template:
subjectbecomes optional (uses template subject if not provided)contentbecomes optional (uses template content)- You can still override with inline values
settings (Required)
Email sending configuration and tracking options.
{
"settings": {
"open_tracking": { "enable": true },
"click_tracking": { "enable": true },
"validate": { "enable": true },
"phishing_protection": { "enable": false },
"unsubscribe": { "enable": true },
"ip_pool": "transactional-pool"
}
}
| Setting | Type | Default | Description |
|---|---|---|---|
open_tracking.enable | boolean | false | Track when recipients open the email. Inserts an invisible tracking pixel. |
click_tracking.enable | boolean | false | Track link clicks. Rewrites URLs to pass through tracking servers. |
validate.enable | boolean | false | Validate recipient email addresses before sending. Invalid addresses are rejected. |
phishing_protection.enable | boolean | false | Scan email content for potential phishing indicators. |
unsubscribe.enable | boolean | false | Include an unsubscribe link in the email. Required for marketing emails. |
ip_pool | string | "" | Specific IP pool to use for sending. Leave empty for default routing. |
Note: Unsubscribe is NOT allowed when process_email_inbulk: true
process_email_inbulk (Optional)
Controls how multi-recipient emails are processed.
| Value | Behavior |
|---|---|
false (default) | Each recipient receives an individual email. Allows substitutions. |
true | All recipients receive the same email. CC/BCC allowed. No substitutions. Maximum 100 total recipients. |
Use Cases:
false: Personalized transactional emails, newsletters with personalizationtrue: Team notifications, internal announcements where all recipients should see each other
priority (Optional)
Email queue priority.
| Value | Description |
|---|---|
0 (default) | Normal priority - processed in order |
1 | High priority - processed before normal priority emails |
Use high priority sparingly for time-sensitive emails like:
- Password reset emails
- Two-factor authentication codes
- Critical security alerts
campaign_id (Optional)
Identifier for grouping emails by campaign.
| Type | Default | Description |
|---|---|---|
| string | "NIL" | Your custom campaign identifier for analytics and tracking |
Example:
{ "campaign_id": "welcome-series-2024-q1" }
Use campaign IDs to:
- Group email logs for reporting
- Filter webhook events
- Track performance by campaign
custom_args (Optional)
Custom data passed through webhooks.
| Type | Description |
|---|---|
| object | Any JSON object with your custom data |
This data is included in webhook payloads, allowing you to:
- Associate emails with internal records
- Pass user IDs, order IDs, or other identifiers
- Add context for event processing
Example:
{
"custom_args": {
"user_id": "usr_123456",
"order_id": "ord_789012",
"source": "checkout-flow"
}
}
Email Threading and Replies
Understanding email threading is crucial for maintaining conversation context and ensuring replies are properly associated with original messages.
Threading Headers Overview
| Header | Purpose | Used By | When to Include |
|---|---|---|---|
Message-ID | Unique identifier for THIS email | All providers | Auto-generated by EDITH |
In-Reply-To | References the Message-ID being replied to | All providers | When replying to an email |
References | Chain of all Message-IDs in the thread | All providers | When replying (cumulative) |
Thread-Id | Gmail's conversation thread identifier | Gmail only | When replying in Gmail |
Message-ID: Auto-Generated by EDITH
You DON'T need to provide Message-ID - EDITH automatically generates it for every email.
EDITH Message-ID Format
<edith_mailer{unique_id}@sparrowmailer.com>
Components:
- Prefix:
edith_mailer(identifies EDITH-sent emails) - Unique ID: UUID or custom identifier from your headers
- Domain:
@sparrowmailer.com
Example:
Message-ID: <edith_mailer550e8400-e29b-41d4-a716-446655440000@sparrowmailer.com>
Custom Message-ID (Non-Gmail Only)
For SMTP, Outlook, and other providers (NOT Gmail), you can provide a custom unique ID in headers:
{
"headers": {
"Message-ID": "order-12345-confirmation"
}
}
EDITH wraps it with the prefix and domain:
Result: <edith_mailer_order-12345-confirmation@sparrowmailer.com>
⚠️ Gmail Exception: Gmail API does NOT allow custom Message-IDs. EDITH always generates a random UUID for Gmail.
When EDITH Sends Message-ID
EDITH includes the message_id in webhook payloads for ALL email events:
Outgoing Email Webhooks
{
"event": "MAIL_DELIVERED",
"details": {
"ref_id": "01JC3BBW8S9YGX2VNKG5MD7BTA",
"email": ["recipient@example.com"],
"message_id": "<edith_mailer550e8400@sparrowmailer.com>",
"thread_id": "18c5a1b2d3e4f5g6",
"custom_args": { "order_id": "12345" }
}
}
Events that include message_id:
MAIL_DELIVERED- Email successfully deliveredMAIL_OPENED- Recipient opened the emailMAIL_CLICKED- Link clickedMAIL_BOUNCED- Email bouncedMAIL_SPAM- Marked as spamGENERATION_FAILURE- Failed to generate email
Store the message_id in your database to correlate replies!
Incoming Email Webhooks
{
"event": "INCOMING_EMAIL",
"details": {
"message-id": "<CABc123def@mail.example.com>",
"in-reply-to": "<edith_mailer550e8400@sparrowmailer.com>",
"thread-id": "18c5a1b2d3e4f5g6",
"references": "<edith_mailer550e8400@sparrowmailer.com> <CABc123def@mail.example.com>",
"from": "customer@example.com",
"subject": "Re: Your order #12345"
}
}
In-Reply-To: For Standard Email Replies
Use In-Reply-To when replying to ANY email (Gmail, Outlook, SMTP).
Purpose: References the exact Message-ID of the email being replied to.
When to use:
- ✅ Replying to a customer email
- ✅ Continuing a conversation
- ✅ Following up on a previous message
Example: Reply to Customer
Original email sent:
{
"from": { "email": "support@company.com" },
"to": [{ "email": "customer@example.com" }],
"subject": "Thank you for contacting us",
"mailer_id": "your-mailer-id"
}
EDITH webhook response:
{
"event": "MAIL_DELIVERED",
"details": {
"message_id": "<edith_mailerabc123@sparrowmailer.com>"
}
}
Store this message_id in your database!
Customer replies, you receive via incoming webhook:
{
"event": "INCOMING_EMAIL",
"details": {
"in-reply-to": "<edith_mailerabc123@sparrowmailer.com>",
"message-id": "<CABxyz@mail.example.com>",
"from": "customer@example.com",
"subject": "Re: Thank you for contacting us"
}
}
Your reply back to customer:
{
"from": { "email": "support@company.com" },
"to": [{ "email": "customer@example.com" }],
"subject": "Re: Thank you for contacting us",
"headers": {
"In-Reply-To": "<CABxyz@mail.example.com>",
"References": "<edith_mailerabc123@sparrowmailer.com> <CABxyz@mail.example.com>"
},
"mailer_id": "your-mailer-id"
}
Result: Email clients group this as a threaded conversation!
References: Full Thread History
References contains the complete chain of Message-IDs in the conversation.
Purpose: Helps email clients understand the entire conversation flow.
Format: Space-separated list of Message-IDs, oldest first.
Example Threading:
1. Initial Email (You → Customer)
{
"subject": "Welcome to our service"
// EDITH generates: <edith_mailermsg1@sparrowmailer.com>
}
2. Customer Reply (Customer → You)
In-Reply-To: <edith_mailermsg1@sparrowmailer.com>
References: <edith_mailermsg1@sparrowmailer.com>
Message-ID: <customer_msg2@gmail.com>
3. Your Reply (You → Customer)
{
"headers": {
"In-Reply-To": "<customer_msg2@gmail.com>",
"References": "<edith_mailermsg1@sparrowmailer.com> <customer_msg2@gmail.com>"
}
}
4. Customer Reply Again (Customer → You)
In-Reply-To: <edith_mailermsg3@sparrowmailer.com>
References: <edith_mailermsg1@sparrowmailer.com> <customer_msg2@gmail.com> <edith_mailermsg3@sparrowmailer.com>
Pattern: Keep adding Message-IDs to References, always include In-Reply-To for immediate parent.
Thread-Id: Gmail OAuth-Specific Threading
Gmail OAuth Only: Gmail uses its own Thread-Id system for grouping conversations when using OAuth authentication.
When to use:
- ✅ ONLY when sending/receiving via Gmail OAuth (not basic SMTP)
- ✅ When replying to emails received via Gmail OAuth
- ❌ NOT needed for Gmail SMTP (basic auth), Outlook, or other providers
How Gmail Thread-Id Works:
Gmail assigns a unique Thread-Id to each conversation. All emails in that conversation share the same Thread-Id.
Example:
Initial email sent via Gmail OAuth:
{
"from": { "email": "you@gmail.com" },
"to": [{ "email": "customer@example.com" }],
"subject": "Hello",
"mailer_id": "gmail-oauth-mailer-id"
}
EDITH webhook:
{
"event": "MAIL_DELIVERED",
"details": {
"message_id": "<edith_mailerxyz@sparrowmailer.com>",
"thread_id": "18c5a1b2d3e4f5g6" // Gmail's Thread-Id
}
}
Customer replies (you receive):
{
"event": "INCOMING_EMAIL",
"details": {
"thread-id": "18c5a1b2d3e4f5g6", // Same Thread-Id
"in-reply-to": "<edith_mailerxyz@sparrowmailer.com>",
"message-id": "<new-message-id>"
}
}
Your reply (include Thread-Id for Gmail OAuth):
{
"from": { "email": "you@gmail.com" },
"to": [{ "email": "customer@example.com" }],
"subject": "Re: Hello",
"headers": {
"Thread-Id": "18c5a1b2d3e4f5g6",
"In-Reply-To": "<new-message-id>",
"References": "<edith_mailerxyz@sparrowmailer.com> <new-message-id>"
},
"mailer_id": "gmail-oauth-mailer-id"
}
⚠️ Important: Gmail OAuth requires thread_id (not Message-ID) for threading replies!
Note: Gmail SMTP (basic auth) does NOT use Thread-Id, only standard In-Reply-To and References.
Provider-Specific Threading Summary
| Provider | Message-ID | In-Reply-To | References | Thread-Id |
|---|---|---|---|---|
| Gmail OAuth | ✅ Auto (EDITH) | ✅ Yes | ✅ Yes | ✅ Required |
| Gmail SMTP | ✅ Auto (EDITH) | ✅ Yes | ✅ Yes | ❌ No |
| Outlook OAuth | ✅ Auto (EDITH) | ✅ Yes | ✅ Yes | ❌ No |
| Outlook SMTP | ✅ Auto (EDITH) | ✅ Yes | ✅ Yes | ❌ No |
| SMTP (Other) | ✅ Auto (EDITH) | ✅ Yes | ✅ Yes | ❌ No |
| SparkPost | ✅ Auto (EDITH) | ✅ Yes | ✅ Yes | ❌ No |
| Mailgun | ✅ Auto (EDITH) | ✅ Yes | ✅ Yes | ❌ No |
Complete Threading Example
Scenario: Support ticket conversation
1. Customer sends initial inquiry (inbound):
{
"event": "INCOMING_EMAIL",
"details": {
"from": "customer@example.com",
"subject": "Need help with order #12345",
"message-id": "<customer-initial@gmail.com>",
"thread-id": "thread_abc123",
"mailer-service": "gmail"
}
}
Store in your database:
{
ticketId: "TKT-001",
messages: [
{
messageId: "<customer-initial@gmail.com>",
threadId: "thread_abc123",
from: "customer",
timestamp: "2024-01-15T10:00:00Z"
}
]
}
2. You reply to customer:
curl -X POST https://api.edith.example.com/v1/email/send \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"from": { "email": "support@company.com", "name": "Support Team" },
"to": [{ "email": "customer@example.com", "name": "Customer" }],
"subject": "Re: Need help with order #12345",
"content": [
{ "type": "text/html", "value": "<p>We are looking into this...</p>" }
],
"headers": {
"In-Reply-To": "<customer-initial@gmail.com>",
"References": "<customer-initial@gmail.com>",
"Thread-Id": "thread_abc123"
},
"mailer_id": "your-mailer-id",
"custom_args": { "ticket_id": "TKT-001" }
}'
EDITH webhook response:
{
"event": "MAIL_DELIVERED",
"details": {
"ref_id": "01JC3BBW8S9YGX2VNKG5MD7BTA",
"message_id": "<edith_mailersupport1@sparrowmailer.com>",
"thread_id": "thread_abc123",
"custom_args": { "ticket_id": "TKT-001" }
}
}
Update database:
{
ticketId: "TKT-001",
messages: [
{ messageId: "<customer-initial@gmail.com>", from: "customer" },
{ messageId: "<edith_mailersupport1@sparrowmailer.com>", from: "support" }
]
}
3. Customer replies again:
{
"event": "INCOMING_EMAIL",
"details": {
"from": "customer@example.com",
"subject": "Re: Need help with order #12345",
"message-id": "<customer-reply2@gmail.com>",
"in-reply-to": "<edith_mailersupport1@sparrowmailer.com>",
"references": "<customer-initial@gmail.com> <edith_mailersupport1@sparrowmailer.com>",
"thread-id": "thread_abc123"
}
}
4. You reply again (building the chain):
{
"headers": {
"In-Reply-To": "<customer-reply2@gmail.com>",
"References": "<customer-initial@gmail.com> <edith_mailersupport1@sparrowmailer.com> <customer-reply2@gmail.com>",
"Thread-Id": "thread_abc123"
}
}
Result: Perfect threaded conversation in Gmail, Outlook, and all email clients!
Best Practices for Threading
1. Always store message_id from EDITH webhooks
// When you send an email
const sentEmail = await sendEmailViaEdith({...});
// Store the ref_id
await db.emails.create({
refId: sentEmail.ref_id,
// Other data
});
// When webhook arrives
app.post('/webhooks/email-events', (req, res) => {
const { ref_id, message_id, thread_id } = req.body.details;
// Update with message_id and thread_id
await db.emails.update(
{ refId: ref_id },
{ messageId: message_id, threadId: thread_id }
);
});
2. Build References correctly
// Maintain conversation history
const conversation = await db.conversations.findOne({ threadId });
const messageIds = conversation.messages.map(m => m.messageId);
// Build References header
const references = messageIds.join(' ');
3. Handle provider differences
function buildThreadingHeaders(email, conversation) {
const headers = {
'In-Reply-To': conversation.lastMessageId,
'References': conversation.allMessageIds.join(' ')
};
// Add Thread-Id ONLY for Gmail
if (email.provider === 'gmail') {
headers['Thread-Id'] = conversation.threadId;
}
return headers;
}
4. Test threading
- Send test emails
- Reply in different email clients
- Verify messages appear grouped
- Check both Gmail and Outlook
5. Monitor threading webhooks
// Log threading info
console.log('Threading info:', {
messageId: details['message-id'],
inReplyTo: details['in-reply-to'],
threadId: details['thread-id'],
references: details.references
});
Complete Example Request
curl -X POST https://api.edith.example.com/v1/email/send \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"from": {
"email": "orders@mail.yourcompany.com",
"name": "YourCompany Orders"
},
"to": [
{
"email": "customer@example.com",
"name": "John Customer"
}
],
"replyTo": "support@yourcompany.com",
"subject": "Your Order #12345 Has Been Confirmed",
"content": [
{
"type": "text/html",
"value": "<!DOCTYPE html><html><head><style>body{font-family:Arial,sans-serif;}</style></head><body><h1>Thank you for your order!</h1><p>Hi {{first_name}},</p><p>Your order #{{order_id}} has been confirmed and will ship within 2-3 business days.</p><p>Track your order: <a href=\"{{tracking_url}}\">Click here</a></p></body></html>"
},
{
"type": "text/plain",
"value": "Thank you for your order!\n\nHi {{first_name}},\n\nYour order #{{order_id}} has been confirmed and will ship within 2-3 business days.\n\nTrack your order: {{tracking_url}}"
}
],
"substitutions": {
"customer@example.com": {
"first_name": "John",
"order_id": "12345",
"tracking_url": "https://track.yourcompany.com/12345"
}
},
"attachments": [
{
"content": "JVBERi0xLjQKJeLjz9M...",
"filename": "invoice_12345.pdf",
"type": "application/pdf"
}
],
"mailer_id": "domain_01JC3BBW8S9YGX2VNKG5MD7BTA",
"campaign_id": "order-confirmation",
"settings": {
"open_tracking": { "enable": true },
"click_tracking": { "enable": true },
"validate": { "enable": true },
"unsubscribe": { "enable": false }
},
"custom_args": {
"order_id": "12345",
"user_id": "usr_67890"
},
"priority": 1
}'
Response
Success Response
{
"success": true,
"ref_id": "01JC3BBW8S9YGX2VNKG5MD7BTA"
}
| Field | Description |
|---|---|
success | Boolean indicating the email was queued successfully |
ref_id | Unique reference ID for tracking this email. Use this to query logs and filter webhooks. |
Error Response
{
"success": false,
"error": "from address does not exist with the provided mailer_id"
}
Common Validation Errors
| Error | Cause | Solution |
|---|---|---|
from address does not exist | The from email doesn't match the mailer_id's domain | Use an email address from the verified domain |
subject is required when template_id is not provided | No subject and no template | Add a subject or use a template_id |
content is required when template_id is not provided | No content and no template | Add content or use a template_id |
cc recipients are not allowed when processing emails individually | Using CC with bulk mode off | Set process_email_inbulk: true or remove CC |
bcc recipients are not allowed when processing emails individually | Using BCC with bulk mode off | Set process_email_inbulk: true or remove BCC |
substitutions are not allowed when processing emails in bulk | Using substitutions with bulk mode | Set process_email_inbulk: false or remove substitutions |
total recipients cannot exceed 100 | Too many recipients in bulk mode | Reduce recipient count or send individually |
unsubscribe is not allowed when processing emails in bulk | Using unsubscribe with bulk mode | Disable unsubscribe or send individually |
invalid email format | Malformed recipient email | Verify email address format |
Best Practices
1. Always Include Plain Text
Include both HTML and plain text versions for:
- Better deliverability
- Accessibility
- Mail clients that don't render HTML
2. Use Meaningful Campaign IDs
Group related emails for better analytics:
{ "campaign_id": "welcome-series-step-1" }
{ "campaign_id": "password-reset" }
{ "campaign_id": "order-shipped" }
3. Enable Tracking Thoughtfully
- Enable open/click tracking for marketing emails
- Consider privacy implications for transactional emails
- Be transparent with recipients about tracking
4. Validate Before Sending
Enable validate to catch invalid email addresses before sending:
{ "settings": { "validate": { "enable": true } } }
5. Use Priority Wisely
Reserve high priority ("priority": 1) for:
- Time-sensitive authentication emails
- Critical security notifications
- Password reset requests
6. Leverage Custom Args
Pass context for webhook processing:
{
"custom_args": {
"user_id": "123",
"trigger": "signup"
}
}
Related Endpoints
- Get Email Logs - Query email delivery status
- Email Templates - Create reusable templates
- Webhooks - Receive real-time delivery events