Sending and monitoring emails in one simple platform.
Zen Mail is built for both tech and non-tech teams: minimal markup friction compared to raw SES, fast template workflows, and a clear queue + deliverability view.
How it works
Keep SES as your sending provider, then let Zen Mail handle templates, scheduling, retries, and monitoring.
Register your SES sender
Build templates & audiences
Schedule sends & monitor delivery
Core features
Templates + preview
system.* fields (see docs below).People management
Queue + retries
Deliverability webhooks
Tracking + unsubscribe
Assets + API keys
Template variables (Liquid)
Every send (template or raw HTML/text) merges a system object into your Liquid scope. You do not need to pass these from the API for real mail; use Sample data in the template editor only so the preview can resolve the same paths.
{{ system.unsubscribe }}— signed URL for one-click unsubscribe from the specific From address used for that send.{{ system.people.first_name }},{{ system.people.last_name }},{{ system.people.email }}— resolved from the recipient when they exist in People (or from job variables).
Set PUBLIC_BASE_URL on the server so system.unsubscribe is a real link in production. Optional person_id on API jobs pins the CRM row for unsubscribe and merge fields.
<p style="font-size:12px;color:#6b7280">
<a href="{{ system.unsubscribe }}">Unsubscribe</a>
· sent to {{ system.people.email }}
</p>Hi {{ system.people.first_name }}, here's your updateFor developers
Scheduling an email is a single API call. Zen Mail stores the job, queues it, and sends it at the scheduled time.
curl -X POST "$BASE_URL/api/email-jobs" \
-H "Authorization: Bearer $ID_TOKEN" \
-H "x-tenant-id: $TENANT_ID" \
-H "Content-Type: application/json" \
-d '{
"type": "template",
"template_id": "welcome_email",
"to": ["person@example.com"],
"subject": "Welcome to Zen Mail",
"variables": { "firstName": "Ada" },
"scheduled_at": 1760000000000,
"idempotency_key": "welcome_email_person@example.com_1760000000000",
"max_retries": 3
}'- Idempotency built-in: repeated calls with the same idempotency_key return the same job.
- Schedule in epoch ms: set scheduled_at (or omit it to send immediately).