Overview
mailshit offers multiple ways to send emails:
- API - Programmatic sending from your backend
- Flow Builder - Visual workflow with send on API call
- Export - Render in mailshit, send with your own infrastructure
Sending via API
The most common method for transactional emails.
Execute Flow (Recommended)
Use /execute to run your configured flow:
curl -X POST https://api.mailsh.it/v1/execute \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"templateId": "tmpl_abc123",
"variables": {
"firstName": "Alice"
},
"_to": "alice@example.com"
}'
This:
- Renders the template with variables
- Runs any verification nodes
- Sends via your configured provider
Render Only
Use /render to get HTML without sending:
curl -X POST https://api.mailsh.it/v1/render \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"template_id": "tmpl_abc123",
"variables": {
"firstName": "Alice"
}
}'
Response:
{
"html": "<!DOCTYPE html>...",
"subject": "Welcome, Alice!"
}
Then send with your own method.
Required Fields
When sending via provider output, _to is required:
{
"templateId": "...",
"variables": {...},
"_to": "recipient@example.com"
}
Optional Fields
| Field | Description |
|---|---|
_subject | Override template subject |
_replyTo | Reply-to address |
_cc | CC recipients (comma-separated) |
_bcc | BCC recipients (comma-separated) |
Multiple Recipients
Send to multiple addresses by comma-separating:
{
"_to": "alice@example.com, bob@example.com"
}
Each recipient receives the same email.
Handling Responses
Successful Send
{
"success": true,
"type": "sent",
"messageId": "msg_abc123"
}
Store messageId for tracking delivery issues.
Validation Failed
{
"success": false,
"type": "validation_failed",
"error": "Invalid email address",
"field": "_to"
}
The field tells you what to fix.
Send Failed
{
"success": false,
"type": "send_failed",
"error": "Provider error message"
}
Check your provider dashboard for details.
Sending Patterns
Welcome Email on Signup
// After user signs up
await fetch('https://api.mailsh.it/v1/execute', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: WELCOME_TEMPLATE_ID,
variables: {
firstName: user.firstName,
loginUrl: 'https://app.example.com/login',
},
_to: user.email,
}),
})
Order Confirmation
await fetch('https://api.mailsh.it/v1/execute', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: ORDER_CONFIRMATION_ID,
variables: {
firstName: order.customer.firstName,
orderNumber: order.id,
orderTotal: formatCurrency(order.total),
orderItems: formatOrderItems(order.items),
},
_to: order.customer.email,
_subject: `Order #${order.id} confirmed`,
}),
})
Password Reset
await fetch('https://api.mailsh.it/v1/execute', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: PASSWORD_RESET_ID,
variables: {
resetLink: `https://app.example.com/reset?token=${token}`,
expiry: '24 hours',
},
_to: user.email,
}),
})
Error Handling
Always handle API errors:
try {
const response = await fetch('...', {...})
const result = await response.json()
if (result.success) {
console.log('Email sent:', result.messageId)
} else {
console.error('Failed:', result.error)
// Maybe queue for retry, alert admin, etc.
}
} catch (error) {
console.error('Network error:', error)
// Queue for retry
}
Retry Strategy
For failed sends:
- Don’t retry immediately - wait at least a few seconds
- Exponential backoff - double wait time each retry
- Max retries - give up after 3-5 attempts
- Alert on failures - monitor persistent failures
async function sendWithRetry(payload, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const result = await sendEmail(payload)
if (result.success) return result
// Don't retry validation errors
if (result.type === 'validation_failed') throw new Error(result.error)
await sleep(Math.pow(2, i) * 1000) // Exponential backoff
}
throw new Error('Max retries exceeded')
}