API Reference
Mailzeno exposes a versioned REST API for sending transactional emails through your own SMTP server.
The base URL for all API requests is:
GET
https://api.mailzeno.devAuthentication
All API requests require a valid API key passed in the Authorization header using the Bearer scheme:
Authorization: Bearer mz_api_your_api_keyAPI keys are validated by hashing (SHA-256) and comparing against stored key hashes. Inactive or invalid keys return a 401 status.
Send Email
POST
v1/emailsSends a transactional email through your configured SMTP server.
Request headers
| Header | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer token with your API key |
Content-Type | string | Yes | Must be application/json |
Idempotency-Key | string | No | Unique key to prevent duplicate sends |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
smtpId | string | Yes | SMTP configuration ID |
from | string | Yes | Sender email (must match SMTP account username) |
to | string | string[] | Yes | Recipient email address(es) |
subject | string | Conditional | Email subject (required if not using templates) |
html | string | Conditional | HTML email body (required if not using templates) |
text | string | No | Plain text fallback |
templateId | string | No | Template UUID |
templateKey | string | No | Template lookup key |
variables | object | No | Dynamic variables for template or raw content interpolation |
Provide either html + subject, or a templateId / templateKey.
Example request
cURL
curl -X POST https://api.mailzeno.dev/v1/emails \
-H "Authorization: Bearer mz_api_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"smtpId": "your_smtp_id",
"from": "you@example.com",
"to": "recipient@example.com",
"subject": "Hello from Mailzeno",
"html": "<h1>Hello World</h1>"
}'Request Body
{
"smtpId": "your_smtp_id",
"from": "you@example.com",
"to": "recipient@example.com",
"subject": "Hello",
"html": "<h1>Hello</h1>"
}Success response
200 OK
{
"success": true,
"messageId": "<unique-message-id@smtp.example.com>"
}Error response
400 Bad Request
{
"error": "Missing required fields: smtpId, from, to",
"code": "missing_required_fields"
}401 Unauthorized
401 Unauthorized
{
"error": "Invalid or inactive API key",
"code": "invalid_api_key"
}Response headers
Every API response includes these headers:
| Header | Description |
|---|---|
x-request-id | Unique request identifier for debugging |
x-ratelimit-limit | Maximum requests allowed per window |
x-ratelimit-remaining | Remaining requests in the current window |
x-ratelimit-reset | Unix timestamp when the rate limit resets |
retry-after | Seconds to wait before retrying (only on 429) |
Request lifecycle
The API processes each request through this pipeline:
- Authentication — Validate the Bearer token against stored API key hashes
- Plan resolution — Determine the user's plan (
freeorpro) - Rate limiting — Check per-minute and daily rate limits via Redis
- Input validation — Verify required fields are present
- SMTP ownership check — Verify the SMTP config belongs to the authenticated user
- From address validation — Ensure
frommatches the SMTP account username - Template resolution — If using templates, fetch and render with variables
- Usage check — Verify daily send limit not exceeded
- SMTP decryption — Decrypt the stored SMTP password (AES-256-GCM)
- Send via core engine — Send through
@mailzeno/corewith pooling and retry - Logging — Log the email with retention policy
- Usage increment — Update the user's daily send count
Rate limits
API endpoints are rate limited per API key. See the Rate Limits page for details.