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