> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackshift.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# 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.

<Tip>
  **Live.** This area is documented as current, user-reliable behavior.
</Tip>

## Goal

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

## Prerequisites

* A StackShift API key
* A verified sender domain for outbound workflows
* DNS access for inbound domains
* StackShift Assets uploaded when using asset-backed attachments

## Workflow

<Steps>
  <Step>
    Create scheduled messages with sendAt and either a direct message payload or template payload.
  </Step>

  <Step>
    Create batch sends for multiple direct messages or batch-template sends for many recipients using one template.
  </Step>

  <Step>
    Inspect batches and batch items from the dashboard or API.
  </Step>

  <Step>
    Create and verify inbound domains before expecting StackShift to store incoming messages.
  </Step>

  <Step>
    Use analytics filters to summarize message activity by time range, interval, domain, or template.
  </Step>
</Steps>

## Scheduled messages

```ts theme={null}
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

```ts theme={null}
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

```ts theme={null}
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

```ts theme={null}
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

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

## Common failures

<Warning>
  * 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.
</Warning>

## Related guides

<CardGroup cols={2}>
  <Card title="StackShift Assets overview" href="/assets/overview">
    StackShift Assets is now a live media platform: storage, CDN delivery, image optimization, upload sessions, DAM, video, scanning, governance, AI metadata, and version history.
  </Card>

  <Card title="Templates and OTP" href="/stackshift-mail/templates-and-otp">
    Create versioned templates, preview and test them, send from a template, and use the built-in one-time-code challenge flow.
  </Card>

  <Card title="Bounces, suppressions, and reputation" href="/stackshift-mail/bounces-suppressions-and-reputation">
    Handle hard and soft bounces, workspace-scoped suppressions, sending limits, warmup stage, domain reputation, and reputation events.
  </Card>
</CardGroup>
