Documentation

Scheduled, batch, inbound, attachments, and analytics

Use the Mail APIs for scheduled delivery, batch sending, batch-template sending, inbound domain capture, asset-backed attachments, and aggregate analytics.

Search Docs

StackShift Mail

Scheduled, batch, inbound, attachments, and analytics

Live

Use the Mail APIs for scheduled delivery, batch sending, batch-template sending, inbound domain capture, asset-backed attachments, and aggregate analytics.

Goal

Use the advanced Mail APIs for workflows that need delayed delivery, fan-out, inbound capture, attachments, or reporting.

Current status

Live

This area is documented as current, user-reliable behavior.

Workflow

  1. 1Create scheduled messages with sendAt and either a direct message payload or template payload.
  2. 2Create batch sends for multiple direct messages or batch-template sends for many recipients using one template.
  3. 3Inspect batches and batch items from the dashboard or API.
  4. 4Create and verify inbound domains before expecting StackShift to store incoming messages.
  5. 5Use analytics filters to summarize message activity by time range, interval, domain, or template.

Scheduled messages

Example

ts
const scheduled = await stackshift.mail.scheduled.create({
  sendAt: '2026-05-12T09:00:00Z',
  message: {
    from: 'noreply@example.com',
    to: 'ada@example.net',
    subject: 'Renewal reminder',
    text: 'Your renewal is coming up.',
    idempotencyKey: 'renewal_ada_2026_05_12',
  },
})

await stackshift.mail.scheduled.cancel(scheduled.id)

Batch template sends

Example

ts
const batch = await stackshift.mail.batch.sendTemplate({
  template: 'weekly-report',
  from: 'reports@example.com',
  recipients: [
    { to: 'ada@example.net', data: { firstName: 'Ada' }, idempotencyKey: 'weekly_ada_2026_19' },
    { to: 'grace@example.net', data: { firstName: 'Grace' }, idempotencyKey: 'weekly_grace_2026_19' },
  ],
})

console.log(batch.id, batch.status, batch.messageCount)

Inbound domains and messages

Example

ts
const inbound = await stackshift.mail.inbound.domains.create('inbound.example.com')

for (const record of inbound.records ?? []) {
  console.log(record.type, record.name, record.value, record.required)
}

await stackshift.mail.inbound.domains.verify(inbound.id)
const messages = await stackshift.mail.inbound.messages.list()

console.log(messages.data.map((message) => message.subject))

Attachments

  • MailSendInput, MailSendTemplateInput, and scheduled/template workflows accept attachments.
  • Attachment input supports assetId or uploadId, filename, and optional contentType.
  • Use StackShift Assets for files you want to attach by assetId.

Analytics

Example

ts
const analytics = await stackshift.mail.analytics.get({
  from: '2026-05-01T00:00:00Z',
  to: '2026-05-10T23:59:59Z',
  interval: 'day',
  domain: 'example.com',
  template: 'weekly-report',
})

console.log(analytics.summary, analytics.series)

API endpoints

  • Scheduled: POST /mail/scheduled, GET /mail/scheduled, GET /mail/scheduled/{scheduledId}, DELETE or POST /mail/scheduled/{scheduledId}/cancel.
  • Batch: POST /mail/batch, POST /mail/batch-template, GET /mail/batches, GET /mail/batches/{batchId}, GET /mail/batches/{batchId}/items.
  • Inbound: POST /mail/inbound/domains, GET /mail/inbound/domains, GET /mail/inbound/domains/{id}, POST /mail/inbound/domains/{id}/verify, GET /mail/inbound/messages, GET /mail/inbound/messages/{id}.
  • Analytics: GET /mail/analytics with from, to, interval, domain, and template filters.

Expected result

Mail workflows that need delay, fan-out, inbound capture, or reporting can use first-class APIs instead of ad hoc application jobs.

Common failures

  • Scheduling with a sendAt timestamp in the past.
  • Using batch sends without per-message idempotency keys for application-level retry safety.
  • Creating an inbound domain but not publishing the required MX or verification records.
  • Expecting attachments to embed raw file bytes. The current SDK attachment input references assetId or uploadId.