Emails

Send transactional emails using Handlebars templates with layouts and partials. Delivery status, the rendered HTML, and every provider event land in Email Logs.

POST/api/v1/emails/send

Send a transactional email using a registered template. Supports idempotency keys to prevent duplicate sends, and an optional sendAt to schedule the send up to 30 days ahead.

const result = await helmdesk.emails.send({
  templateKey: 'welcome',
  to: { email: 'user@example.com', name: 'Jane' },
  variables: { activationUrl: 'https://...' },
}, { idempotencyKey: 'signup-jane-2024' })

// Schedule instead of sending now:
const scheduled = await helmdesk.emails.send({
  templateKey: 'trial-expiring',
  to: { email: 'user@example.com' },
  sendAt: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000), // in 3 days
})
// scheduled.status === 'scheduled', scheduled.scheduledAt set
POST/api/v1/emails/batch

Send up to 100 transactional emails in one request. Each item is delivered independently — one failed item does not fail the batch. Idempotency is a per-item field (idempotencyKey) rather than a header. Requires the emails:send scope and the Pro plan or higher.

const result = await helmdesk.emails.sendBatch({
  emails: [
    {
      templateKey: 'welcome',
      to: { email: 'a@example.com', name: 'Ann' },
      variables: { firstName: 'Ann' },
      idempotencyKey: 'welcome-a-2026',
    },
    {
      templateKey: 'welcome',
      to: { email: 'b@example.com' },
      variables: { firstName: 'Bo' },
    },
  ],
})
// result.total / result.sent / result.blocked / result.failed
// result.results[i] -> { index, id, status, to, ... } on success,
//                      { index, to, error } on failure
POST/api/v1/emails/preview

Preview a rendered email template without sending. Uses sample data if no variables are provided.

const { subject, html } = await helmdesk.emails.preview({
  templateKey: 'welcome',
  variables: { name: 'Test User' },
})
GET/api/v1/email-templates

List the project's email templates (with current-version subject and detected variables) plus your account's shared templates (keys already @account/-prefixed). This is how integrations discover valid templateKey values for send and preview. Requires the emails:send scope.

const { templates, accountTemplates } = await helmdesk.emails.templates.list()
// templates[0] -> { key: 'welcome', subject: 'Welcome!', variables: [...] }
GET/api/v1/email-templates/:key/schema

Get the template variable schema (auto-detected from Handlebars expressions).

const schema = await helmdesk.emails.getTemplateSchema('welcome')
// schema.variables -> [{ name: 'activationUrl', required: true }]

Batch sending

POST /api/v1/emails/batch accepts an emails array (min 1, max 100 items). Each item has the same shape as a single send — templateKey and to.email are required; to.name, variables, and environment are optional — plus an optional per-item idempotencyKey (batch idempotency is a field on each item, not the Idempotency-Key header used by single send).

The response returns summary counts (total, sent, blocked, failed) plus a results array. Each item is delivered independently — a failed item does not fail the batch. On success a slot looks like { index, id, status, to, subject, deduplicated, blocked, blockReason, createdAt }; on failure it is { index, to, error }. Always inspect each result's error and blocked fields. Batch sending requires the emails:send scope and the Pro plan or higher (the Free plan returns 403). One batch counts as a single request against the 100 requests/minute rate limit.

Via MCP, use the send_email_batch tool with an emails array where each item is { templateKey, to_email, to_name?, variables?, idempotencyKey? }.

Scheduled sends

Pass sendAt (ISO timestamp or Date, up to 30 days ahead) on a single or batch send. The email renders immediately and waits in status scheduled; suppression, pause, and allowlist rules are re-checked at fire time. A scheduled send can be canceled from Email Logs any time before it fires. A past sendAt sends immediately.

Environments & sending modes

Which data plane a send lands in is decided by your API key — sk_sandbox_ keys capture emails without delivering them (see Sandbox). For live sending, modes include live, test recipient (redirects to a single address), allowlist (only certain domains), and paused (mail is held until you resume).

See Email Templates for the template import API and shared template system.