# Chat SDK

> A pattern for building conversational, two-way email on MailBlastr — send with the SDK, receive via webhooks, thread with email headers.

You can turn email into a two-way communication channel for an agent or app: **send** with the official [`mailblastr` SDK](https://www.mailblastr.com/docs/resources/sdks) (or [POST /emails](https://www.mailblastr.com/docs/api/emails-send)), **receive** inbound mail through [webhooks](https://www.mailblastr.com/docs/webhooks/overview), and **thread** conversations using standard email headers. This page describes that pattern and shows how to package it as a [Vercel Chat SDK](https://chat-sdk.dev) adapter so reply chains map cleanly onto Chat SDK threads.

> **Note:** MailBlastr does not publish a prebuilt Chat SDK adapter package. The adapter below is a thin wrapper *you* write over the real primitives (the SDK + inbound webhooks). It is roughly 100 lines; the sections that follow give you the building blocks.

## Prerequisites

- [Create an API key](https://www.mailblastr.com/docs/api-keys/overview).
- [Verify your domain](https://www.mailblastr.com/docs/domains/managing).
- [Set up webhooks](https://www.mailblastr.com/docs/webhooks/overview) for `email.received` events.
- [Enable receiving](https://www.mailblastr.com/docs/receiving/introduction) on your domain.

## 1. Send with the SDK

Install the official Node SDK. Every reply you post is just an `emails.send` call from a verified address.

```bash
npm install mailblastr
```

```ts
import { MailBlastr } from 'mailblastr';

const mb = new MailBlastr(process.env.MAILBLASTR_API_KEY!);

async function reply(to: string, subject: string, text: string, headers?: Record<string, string>) {
  const { data, error } = await mb.emails.send({
    from: 'My Bot <bot@yourdomain.com>',
    to: [to],
    subject,
    text,
    headers, // set In-Reply-To / References here to keep the thread intact
  });
  if (error) throw new Error(`${error.name}: ${error.message}`);
  return data;
}
```

## 2. Receive via webhooks

Point a MailBlastr webhook at your server and subscribe to the `email.received` event. Verify the signature against your signing secret, then fetch the full message — including headers and body — from the [Receiving API](https://www.mailblastr.com/docs/receiving/introduction).

```ts
// POST /webhook
async function handler(req: Request) {
  const payload = await req.text();

  // Verify the signature against MAILBLASTR_WEBHOOK_SECRET before trusting input.
  if (!verifyMailblastrSignature(payload, req.headers, process.env.MAILBLASTR_WEBHOOK_SECRET!)) {
    return new Response('invalid signature', { status: 400 });
  }

  const event = JSON.parse(payload);
  if (event.type === 'email.received') {
    // Fetch the full inbound message (headers, text, html, attachments).
    const { data: email } = await mb.emails.receiving.get(event.data.email_id);
    await onInbound(email);
  }
  return new Response('ok', { status: 200 });
}
```

See [Webhook signatures](https://www.mailblastr.com/docs/webhooks/overview) for the verification details and [Receiving](https://www.mailblastr.com/docs/receiving/introduction) for the inbound message shape.

## 3. Thread with email headers

Email threading is carried entirely by standard headers — there is no special API. When you reply, set `In-Reply-To` to the inbound message's `Message-ID` and append it to `References`. Group inbound messages into a conversation by following the same chain.

```ts
async function onInbound(email) {
  const messageId = email.headers['message-id'];
  const references = [email.headers['references'], messageId].filter(Boolean).join(' ');

  await reply(email.from, `Re: ${email.subject}`, `Got your email: ${email.text}`, {
    'In-Reply-To': messageId,
    'References': references,
  });
}
```

> **Warning:** Email is immutable: there is no edit, delete, reaction, or typing indicator. A "conversation" is just a chain of sent and received messages linked by `In-Reply-To`/`References`.

## Packaging it as a Chat SDK adapter

If you use the Vercel Chat SDK, you can wrap the three steps above in a custom adapter so reply chains surface as Chat SDK threads. The adapter's `post` maps to `mb.emails.send`, its webhook handler maps to step 2, and thread resolution uses the `In-Reply-To`/`References` headers from step 3. A minimal shape:

```ts
import { MailBlastr } from 'mailblastr';

// A custom adapter you author — not a published package.
function createMailblastrAdapter(opts: { fromAddress: string; fromName?: string }) {
  const mb = new MailBlastr(process.env.MAILBLASTR_API_KEY!);
  return {
    name: 'mailblastr',
    async post(thread, text) {
      await mb.emails.send({
        from: opts.fromName ? `${opts.fromName} <${opts.fromAddress}>` : opts.fromAddress,
        to: [thread.recipient],
        subject: thread.subject,
        text,
        headers: thread.threadHeaders, // In-Reply-To / References
      });
    },
    // verify signature -> fetch via mb.emails.receiving.get -> resolve thread by headers
    async handleWebhook(request) { /* step 2 + step 3 */ },
  };
}
```

> **Note:** Keep the adapter name `"mailblastr"` consistent across your Chat config and your thread routing so inbound emails resolve to the right thread.

## Going further

- [Card emails](https://www.mailblastr.com/docs/ai/chat-sdk-cards) — send rich HTML emails with structured card elements.
- [Attachments](https://www.mailblastr.com/docs/ai/chat-sdk-attachments) — handle inbound email attachments.
- [Proactive outreach](https://www.mailblastr.com/docs/ai/chat-sdk-outreach) — start new email threads without waiting for inbound.
