# Migrate from Resend and keep replies in the thread
URL: https://samva.dev/guides/migrate-from-resend
> Map Resend sends, batches, templates, webhooks, and domains onto Samva, then cut over one flow while replies stay in the conversation.
- Published: 2026-10-16



Start with [Samva vs Resend](/compare/resend) if you are still choosing. It compares the published
plans. Return here once the decision is made: this is the implementation path for one reversible
flow, not another pricing comparison.

Resend sends email, accepts a batch of up to 100 messages, renders published templates, signs
webhooks, verifies a domain you own, and receives mail on that domain. The facts below are from
Resend's own docs, checked October 16, 2026, and linked at the end. Where Samva does not offer the
same call, the table says so.

Samva is an email API. A reply threads into the conversation of the email it answers, and your
application gets that reply as a signed `message.received` event with the sender's address and the
conversation id. A later send stays on that thread only when you pass the conversation, or the
message it replies to. You change the email in the AI email editor or in a Git-backed template, and
you can drive the same API from the TypeScript SDK, the CLI, or hosted MCP.

## Map the send call [#map-the-send-call]

`resend.emails.send` and `POST https://api.resend.com/emails` become `samva.email.send` or
`POST https://api.samva.dev/v1/messages`. The [send an email](/docs/channels/email/send-an-email)
guide is the full request. This is the field map.

| Resend send field                   | Samva destination                                             | What to decide                                                                                                                                                                                                                     |
| ----------------------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `from`                              | `from: { email, name }`, optional                             | Resend requires `from`. If you omit it, Samva uses the template default, then the organization default sender, then your only verified sender. With several verified senders and no default, the send fails validation.            |
| `to`, `cc`, `bcc`                   | `to`, `cc`, `bcc`                                             | A string, `{ email }`, or `{ contactId }`. Resend caps `to` at 50 addresses.                                                                                                                                                       |
| `subject`, `html`, `text`           | `subject` plus `html` or `text`                               | Inline content needs a subject and at least one body. A template send omits all three.                                                                                                                                             |
| `react` (Node.js SDK)               | No `react` field                                              | Send HTML, or publish a template and pass its slug. The send call does not accept a React component.                                                                                                                               |
| `reply_to`                          | `replyTo`                                                     | An array of addresses, or `null`.                                                                                                                                                                                                  |
| `headers`                           | No field                                                      | The send payload has no custom email headers. See below.                                                                                                                                                                           |
| `tags`                              | `metadata`                                                    | A JSON object stored on the message and returned on message events. It is not an email tag, and it is not a conversation tag.                                                                                                      |
| `scheduled_at`                      | `scheduledMessages.create`                                    | `messages.send` has no scheduling field. The scheduled message is a separate resource you can read or cancel.                                                                                                                      |
| `attachments`                       | `attachments`                                                 | Media you have uploaded, or bounded base64 content. Resend's batch endpoint does not accept attachments; a single Resend send does.                                                                                                |
| `template.id`, `template.variables` | `templateSlug` or `templateId`, plus `templateData`           | Name one published template. Do not also send `subject`, `html`, or `text`.                                                                                                                                                        |
| `Idempotency-Key`                   | `Idempotency-Key`                                             | Resend keys expire after 24 hours and allow 256 characters. Pass your own `idempotencyKey` on the Samva call; the SDK otherwise generates a fresh key. The [REST API](/docs/developers/rest-api#idempotency) states Samva's rules. |
| `topic_id`                          | `unsubscribeGroupId` on the email, when you mean a preference | A Resend topic decides send or fail from the contact's opt-in. An unsubscribe group records which mail an address has declined. They are not the same object.                                                                      |

The send API has no custom email headers. Resend's send reference includes a `headers` object.
Samva's email content does not. You cannot set `List-Unsubscribe`, `X-Entity-Ref-ID`, or any other
header of your own on `email.send` or `POST /v1/messages`. If the flow needs a header you supply,
keep it on Resend or drop the header before cutover.

Samva still writes headers a send needs. A reply that names the conversation or the message it
answers gets `In-Reply-To` and `References` from that message. A campaign adds one-click unsubscribe
headers for its unsubscribe group. Those are not a place to put your own headers.

```typescript title="send-receipt.ts"
import { createClient } from "samva";

const samva = createClient({ apiKey: process.env.SAMVA_API_KEY! });

const message = await samva.email.send(
  {
    from: { email: "receipts@example.com", name: "Acme" },
    to: "ada@example.com",
    replyTo: "support@example.com",
    subject: "Your receipt",
    html: "<p>Thanks for your order.</p>",
    metadata: { orderId: "A-1042" },
  },
  { idempotencyKey: "receipt:A-1042" },
);

console.log(message.id, message.status);
```

The REST call is the same product operation:

```bash title="send-receipt.sh"
curl -X POST https://api.samva.dev/v1/messages \
  -H "X-API-Key: $SAMVA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: receipt:A-1042" \
  -d '{
    "from": { "email": "receipts@example.com", "name": "Acme" },
    "to": [{ "email": "ada@example.com" }],
    "channel": "email",
    "metadata": { "orderId": "A-1042" },
    "email": {
      "replyTo": ["support@example.com"],
      "subject": "Your receipt",
      "html": "<p>Thanks for your order.</p>"
    }
  }'
```

Persist `message.id` with the order. Acceptance is not delivery.

### Replace a batch with one send per email [#replace-a-batch-with-one-send-per-email]

Resend's `resend.batch.send` and `POST /emails/batch` accept up to 100 emails in one request. Each
entry can differ. Attachments are not supported on that endpoint. The response lists ids in the
same order as the request.

Samva has no batch send endpoint. There is no `POST /v1/messages` body that takes an array of
different emails. Send each one, with an idempotency key derived from the business id, so a retry
returns the original message instead of sending a second copy:

```typescript title="send-batch-as-singles.ts"
import { createClient } from "samva";

const samva = createClient({ apiKey: process.env.SAMVA_API_KEY! });

const orders = [
  { id: "A-1042", email: "ada@example.com" },
  { id: "A-1043", email: "grace@example.com" },
];

for (const order of orders) {
  const message = await samva.email.send(
    {
      to: order.email,
      subject: `Receipt ${order.id}`,
      html: `<p>Order ${order.id} is confirmed.</p>`,
    },
    { idempotencyKey: `receipt:${order.id}` },
  );
  console.log(order.id, message.id);
}
```

A campaign is the other shape: one subject and body, many contacts, one run. Use it when Resend
today sends the same email to a list, including a broadcast. It is not a stand-in for a batch of
distinct messages. [Send a campaign](/docs/channels/email/send-a-campaign) is that path.
[Schedule an email](/docs/channels/email/schedule-an-email) is the path for `scheduled_at`: one
known email at a future instant, created with `scheduledMessages.create`, not a field on the send.

## Map templates [#map-templates]

Both products store templates, render them at send time, and separate a draft from the published
version a send can use. Resend's template docs describe a no-code editor, version history, variables,
and creating a template from HTML or React Email. You pass `template.id` (an id or alias) and
`template.variables`. `from`, `subject`, and `reply_to` on that request override the template
defaults.

Samva templates are versioned TSX in a Git-backed project. You publish a commit, and you can roll
back to an earlier publication. The AI email editor is one way to change the template. A send names
`templateSlug` or `templateId` and passes `templateData`. Omit `subject`, `html`, and `text`. To pin
one publication, or to follow new publications while the input shape stays the same, see
[Choose which publication renders](/docs/channels/email/send-an-email#choose-which-publication-renders).

```typescript title="send-template.ts"
await samva.email.send(
  {
    to: "ada@example.com",
    templateSlug: "order-confirmation",
    templateData: { orderId: "A-1042", total: "$42.00" },
  },
  { idempotencyKey: "receipt:A-1042" },
);
```

Keep sending inline HTML until the template is published and a test send matches. The first cutover
does not require a template rewrite. Resend's version history and Samva's publications are both
real. Move the content you need, then point the send at the slug.

## Map webhooks and events [#map-webhooks-and-events]

Keep `/webhooks/resend` and `/webhooks/samva` as separate routes while both providers can still
deliver. Resend's webhook introduction documents signature verification and replay. Samva signs
with the Standard Webhooks headers `webhook-id`, `webhook-timestamp`, and `webhook-signature`.
Pass the untouched request to `verifyRequest` from `samva/webhooks`. The
[webhook guide](/guides/email-webhooks) is the handler, and the
[event catalog](/docs/platform/webhook-events) is every payload.

| Resend event                                            | Samva event                                                               | Difference worth keeping                                                                                                                                                                                                                   |
| ------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `email.sent`                                            | The `201` is acceptance. `message.sent` is later.                         | Resend's `email.sent` means the API accepted the email and will try to deliver it. Samva's `201` is that moment. `message.sent` fires when the email is on its way to the recipient's server, and it does not mean the server accepted it. |
| `email.delivered`                                       | `message.delivered`                                                       | The recipient's mail server accepted the email.                                                                                                                                                                                            |
| `email.bounced`                                         | `message.bounced`                                                         | A permanent rejection.                                                                                                                                                                                                                     |
| `email.complained`                                      | `message.complained`                                                      | The recipient reported spam.                                                                                                                                                                                                               |
| `email.failed`                                          | `message.failed`                                                          | Samva uses this when it did not send, or when a temporary rejection was abandoned.                                                                                                                                                         |
| `email.delivery_delayed`                                | No equivalent event                                                       | A delay that later succeeds shows up as `message.delivered`. A temporary failure that is given up shows up as `message.failed`.                                                                                                            |
| `email.opened`                                          | `message.opened`                                                          | Open tracking.                                                                                                                                                                                                                             |
| `email.clicked`                                         | `message.clicked`                                                         | Click tracking.                                                                                                                                                                                                                            |
| `email.received`                                        | `message.received`                                                        | Samva includes the conversation id. Fetch the email when you need headers or raw MIME.                                                                                                                                                     |
| `email.scheduled`                                       | No equivalent event                                                       | Read the scheduled message. Cancel it before it sends if the plan changes.                                                                                                                                                                 |
| `email.suppressed`                                      | `422 ValidationError`, or `message.failed` with `errorCode: "SUPPRESSED"` | An address already on the suppression list fails the request when every recipient is excluded. The webhook fires only after the message is accepted.                                                                                       |
| `domain.updated`                                        | `domain.updated`                                                          | Samva also emits `domain.warming.updated`.                                                                                                                                                                                                 |
| `domain.created`, `domain.deleted`                      | No equivalent events                                                      | Read the domain from the API when you need its current status.                                                                                                                                                                             |
| `contact.created`, `contact.updated`, `contact.deleted` | The same event names                                                      | Samva's contact payload is the contact after the change.                                                                                                                                                                                   |
| `contact.topics.updated`                                | `contact.unsubscribed`, `contact.resubscribed`                            | Those events name an unsubscribe group, not a Resend topic.                                                                                                                                                                                |
| `suppression.added`, `suppression.removed`              | No equivalent events                                                      | Add or lift an address from the dashboard. See [suppression](/docs/channels/email/deliverability#reputation-bounces-complaints-and-suppression).                                                                                           |

Suppression has two outcomes, and a mixed envelope has a third. When every recipient is already
suppressed or unsubscribed, `POST /v1/messages` returns
[`422 ValidationError`](/docs/developers/error-reference#validationerror-422) and `fields` names
each address and reason. That request accepts no message, so no webhook follows. When at least one
recipient remains, the request returns `201` and `skippedRecipients` lists the excluded addresses.
Those addresses do not get their own `message.failed`. After a message is accepted, a suppression
that lands before send emits [`message.failed`](/docs/platform/webhook-events#messagefailed) with
`errorCode: "SUPPRESSED"`. Handle the `422` on the send call. The
[response format](/docs/developers/rest-api#response-format) is the receipt.

`message.received` is the message event that carries `conversationId`. Delivery events do not.
Store `webhook-id` with the effect it guards. Samva retries a non-success response. The
[webhook reference](/docs/platform/webhooks) has the schedule.

## Move the domain without taking Resend offline [#move-the-domain-without-taking-resend-offline]

Add the sending domain in Samva and publish the records it generates. Leave Resend's records in
place until that provider is done sending. [Verify your sending domain](/docs/channels/email/verify-your-domain)
is the Samva workflow. The [authentication guide](/guides/email-authentication) is what SPF, DKIM,
and DMARC each do.

| Record              | Resend, checked October 16, 2026                                                                                                                                                     | Samva                                                                                                                                         |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
| DKIM                | A TXT record Resend generates. Copy it from the domain's Records tab.                                                                                                                | A TXT record Samva generates for the domain. A second selector can exist beside Resend's.                                                     |
| SPF and return path | TXT and MX on the return-path host, or CNAME records for domains created after August 2026. The default host is `send.example.com`. A CNAME cannot share a name with another record. | MX and SPF TXT on `mail.example.com`. That host is the return path, not the address people see in From, and not an inbox.                     |
| DMARC               | You publish the policy. Resend shows the parameters on the domain.                                                                                                                   | You publish the policy. Samva reads it and does not create or replace the record.                                                             |
| Receiving MX        | An MX on the domain, or on a hostname you dedicate to receiving, routes inbound mail to Resend.                                                                                      | An MX on the domain when receiving is enabled. It does not block sending. A domain can be ready to send while that MX still points at Resend. |

Resend's domain setup also offers a sending region and enforced TLS. Those stay with the Resend
domain. Samva's domain check is the DKIM record, the return-path records, and, once you turn
receiving on, the inbound MX. Customer email requires TLS on the connection to the receiving
server.

Do this before production mail moves:

1. Compare the hostnames. Resend's default return path is `send.example.com` (or the custom return
   path you set, plus an `r`-prefixed sibling when the records are CNAMEs). Samva's return path is
   `mail.example.com`. If either name is already taken, change the Resend return path or pick
   records that do not collide. A CNAME cannot sit on a name that already has TXT or MX.
2. Publish Samva's DKIM and return-path records beside Resend's. Do not delete Resend's records
   while Resend still sends.
3. Wait until the Samva domain is ready to send. DNS often takes minutes and sometimes a few hours.
4. Leave the receiving MX where it is. One hostname has one set of MX targets that matter. Moving
   it is the last step, after a test reply lands on Samva.

If Cloudflare or Vercel hosts the zone, [automatic DNS setup](/docs/channels/email/automatic-dns-setup)
can apply the Samva plan after you review it. Copy every value from the dashboard either way.

## Move inbound mail onto conversations [#move-inbound-mail-onto-conversations]

Resend receives mail at a verified domain, or at the account's `.resend.app` subdomain. It parses
the message and POSTs `email.received` to the endpoint you choose. You then retrieve HTML, text,
headers, and attachments from the API. Resend's receiving docs also describe forwarding and
replying in the same thread. Its webhook catalog documents a separate inbox event set, including
threads, drafts, and assignments, and marks those inbox events private beta.

Samva's receiving path for this migration is `message.received` on a domain with receiving enabled.
The event includes the sender, your recipient addresses, the subject, attachment and auto-reply
flags, a parsed body when there is one, and the `conversationId`. It does not include a headers
map. Read [get email details](/docs/api-reference/messages/getEmail) for `messageIdHeader`,
`inReplyTo`, `references`, and a signed URL for the raw MIME. Other headers you care about are in
that MIME, not in a `headers` field on the send API.

An inbound reply threads into the conversation of the email it answers. Samva does not gather every
email from one person into a single conversation. A send you make joins a conversation only when
you pass `conversationId` or `email.inReplyToMessageId`. The reply send still has no custom email
headers. Samva sets the threading headers from the message you name.

Return before you send when `isAutoReply` is true. That flag is on `message.received`. It covers
an out-of-office reply and other automatic replies. Each of those messages has its own `messageId`,
so the idempotency key `reply:${messageId}` does not stop the next automatic reply from starting
another send.

```typescript title="reply-in-conversation.ts"
import { createClient } from "samva";

const samva = createClient({ apiKey: process.env.SAMVA_API_KEY! });

async function replyInConversation(event: {
  messageId: string;
  conversationId: string;
  from: string;
  subject?: string;
  isAutoReply?: boolean;
}) {
  if (event.isAutoReply) return;

  const conversation = await samva.conversations.getById({ id: event.conversationId });
  return samva.email.send(
    {
      conversationId: conversation.id,
      to: event.from,
      subject: event.subject ? `Re: ${event.subject}` : "Re: your message",
      html: "<p>Thanks, we have your reply.</p>",
      inReplyToMessageId: event.messageId,
    },
    { idempotencyKey: `reply:${event.messageId}` },
  );
}
```

Historical Resend messages do not import. Keep your ticket id, and attach the new message id and
conversation id after the first Samva reply you trust.

[Receive on a subdomain](/guides/inbound-email-parsing#receive-on-a-subdomain) so the receiving MX
does not take over a hostname that already runs mailboxes. The
[inbound guide](/guides/inbound-email-parsing) is the shorter path if you are not moving a provider.

### When the address belongs to an agent or an app [#when-the-address-belongs-to-an-agent-or-an-app]

A mailbox is an address your application or agent owns. It can live on your organization's
`samva.email` subdomain, with no DNS, or on a verified domain that already receives mail. The agent
uses a key scoped to that mailbox. Sends can wait for a person to approve them, and quarantine can
hold a message until someone releases or discards it. [Mailboxes](/features/mailboxes) is that
product. It is a different cutover from `email.received`: use it when the address itself is the
product, not when you are moving a transactional webhook.

Resend's private-beta inbox events are the closest description on that side. This guide does not
map them field by field, because they are not the receiving API the rest of the page uses. If you
depend on inbox assignment, folders, or drafts, write down which of those your application actually
reads before you treat a mailbox as the replacement.

## Cut over with a parallel run [#cut-over-with-a-parallel-run]

Pick one flow. A receipt or a password reset is enough. Write the evidence you will keep, and the
condition that sends the flow back to Resend.

| Checkpoint                   | Evidence to retain                                                                                    | Rollback condition                                         |
| ---------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| Headers                      | A written list of every custom header the Resend payload sets                                         | Any header is required and has no replacement in your app  |
| Domain                       | The Samva domain is ready to send, and Resend's records are still published                           | Verification is incomplete, or a return-path name collided |
| Send                         | Your record, the idempotency key, and the Samva message id agree                                      | The new path cannot return or store a message id           |
| Delivery                     | One signed Samva event is stored once for that message id                                             | Delivered, bounced, or failed cannot be reconciled         |
| Reply, when the flow has one | `message.received` carries a conversation id your app can read, and a test reply stays on that thread | The reply cannot be attached to the ticket or order        |
| Rollback                     | The Resend call for this flow is still deployable                                                     | Any checkpoint fails during the observation window         |

Run both providers only as alternative paths for that flow. Do not deliver the same production
email through both of them to the same person. Use controlled test recipients for a side-by-side
look, then send a small production slice through one path.

1. Inventory the Resend call: from, recipients, template or HTML, headers, tags, schedule, topic,
   attachments, and the webhook effects your app applies.
2. Stop if the call sets custom email headers you still need. Samva's send API cannot carry them.
3. Verify the domain in Samva without removing Resend's DKIM, SPF, or return-path records.
4. Point this flow at `samva.email.send`, and keep the Resend function in the same deploy so you can
   switch the flow back.
5. Send a controlled test from the verified domain. Reconcile the message id with your record.
6. Confirm `message.delivered`, or `message.bounced` / `message.failed`, on the Samva endpoint.
   When every recipient is suppressed or unsubscribed, the request returns `422 ValidationError`
   and no delivery events follow. Other invalid requests also return this error. Inspect its
   `message` and `fields` on the send call to determine the reason.
   Leave the Resend endpoint and its verifier in place.
7. If the flow receives replies, send a controlled reply to the Resend receiving address first and
   record what your app does today. Then, on a test hostname, enable Samva receiving and confirm
   `message.received`, the conversation id, and a threaded reply. Do not change the production MX
   in this step.
8. Route the next small production slice of this one flow through Samva. Watch the event log and
   the support record.
9. After the window you agreed is quiet, delete the Resend call for this flow only.
10. When no remaining flow sends through Resend, remove Resend's sending records. Move the
    receiving MX last, onto a hostname you have already tested.

Record the window, the volume, and any event you could not explain. The migration is done when
your application can account for every send, failure, and reply from its own records.

## Known limits [#known-limits]

* The send API has no custom email headers. A batch of distinct emails has no single request.
  `scheduled_at`, `tags`, `react`, and `topic_id` do not copy across as the same fields. The map
  above is the replacement, or the statement that there is none.
* This guide does not import historical Resend emails, events, contacts, or suppressions. Export
  what your policy says you must keep before you retire the account.
* Do not send one production recipient the same email from both providers to compare them.
* Inbound cutover needs its own rollback. Leave the Resend receiving MX in place until a controlled
  reply has produced `message.received` and a conversation your app can read.
* Acceptance, delivery, and a recipient opening the email are different events. The proof is the
  message id you stored and the webhook you verified.
* Resend documents official SDKs for several languages, a CLI, and hosted MCP. Samva's SDK is
  TypeScript. Other languages call `POST /v1/messages`. The [Python guide](/guides/send-email-python)
  is that call. Hosted MCP and the CLI are on both products.

## Continue from the first stable flow [#continue-from-the-first-stable-flow]

The [TypeScript SDK](/docs/developers/typescript-sdk) is the Promise client.
The [Effect SDK](/docs/integrations/effect-sdk) is the same operations as Effects.
The [REST API](/docs/developers/rest-api) is the path for every other runtime.
The [email messaging model](/docs/platform/unified-messaging) is how an immediate send, a scheduled
send, and a campaign share one message id and one conversation.

Move the next flow only after this one can explain itself.

## Sources [#sources]

Checked October 16, 2026:

* [Resend: send email](https://resend.com/docs/api-reference/emails/send-email)
* [Resend: send batch emails](https://resend.com/docs/api-reference/emails/send-batch-emails)
* [Resend: webhook event types](https://resend.com/docs/webhooks/event-types)
* [Resend: webhooks](https://resend.com/docs/dashboard/webhooks/introduction)
* [Resend: templates](https://resend.com/docs/dashboard/templates/introduction)
* [Resend: receiving emails](https://resend.com/docs/dashboard/receiving/introduction)
* [Resend: add a domain](https://resend.com/docs/add-a-domain)
* [Resend: managing domains](https://resend.com/docs/dashboard/domains/manage-domains)
* [Resend: custom return path](https://resend.com/docs/dashboard/domains/custom-return-path)
* [Resend: avoid MX conflicts](https://resend.com/docs/knowledge-base/how-do-i-avoid-conflicting-with-my-mx-records)

## FAQ

### Can I migrate one Resend flow at a time?

Yes. Verify the domain in Samva, send one low-risk flow through the API, and compare its delivery events before you move more traffic. Keep the Resend call for that flow until the new path is reconciled, and do not send the same production email through both providers to the same person.

### Does Samva's send API accept custom email headers?

No. The send payload has no headers field. You cannot attach your own List-Unsubscribe, X-Entity-Ref-ID, or any other header. If a flow depends on a header you set, keep that flow on Resend or remove the header before you cut over. When you reply in a conversation, Samva sets the threading headers from the message you reply to. Campaign mail carries one-click unsubscribe headers for its unsubscribe group. Neither is a general headers API.

### Is there a batch send like Resend's?

No. Resend accepts up to 100 emails in one batch request, and that request does not take attachments. Samva has no batch send endpoint. Send each email with its own idempotency key. A campaign is a different call: one subject and body to many contacts, not a list of distinct emails.

### Will existing Resend threads import into Samva?

No. Keep historical messages and your own ticket ids in your application. A new inbound email threads into the conversation of the email it answers, and a later send joins that conversation only when you pass the conversation id or the message you are replying to.

### Can I keep Resend for some email while Samva sends the rest?

Yes. DKIM records for the two providers can sit side by side. Leave each provider's return-path records in place while it still sends, and point a receiving hostname's MX at only one of them. Move the receiving MX last.
## Related

- [Samva vs Resend](/compare/resend): Side-by-side pricing and features, with sources checked against Resend and Samva pages.
- [How to Choose a Transactional Email API: Checklist](/guides/transactional-email-api): Evaluate the send, authentication, event, template, and suppression requirements before choosing an email API.
- [Email webhooks: events, signatures, and idempotency](/guides/email-webhooks): Verify signed delivery events and make webhook handling safe to retry.
- [Inbound email parsing: receive, thread, and reply](/guides/inbound-email-parsing): Configure receiving and send a reply in its Samva conversation.
- [Email authentication: SPF, DKIM, and DMARC explained](/guides/email-authentication): Set up domain authentication in the right order before moving production traffic.
- [Send an email](/docs/channels/email/send-an-email): The send walkthrough with the TypeScript SDK and curl, including attachments and templates.
