# Inbound email lands in your app.

URL: https://samva.dev/features/inbound-email

Inbound email API

Receive email on your domain, parse it, and get it in your app as a signed webhook, threaded to the email it answers. No shared inbox, no janky script matching replies to users.

[Start sending free](https://samva.dev/signup?entry=marketing_page)

[Follow the inbound guide](https://samva.dev/guides/inbound-email-parsing)

A customer's reply carries an In-Reply-To header that matches the Message-ID of the email it answers, so it joins that conversation.

## A customer replies. Your app gets the context.

From their inbox to your app

A customer replies. Your app gets the email, the sender's address, and the conversation it belongs to.

A customer email from maya@example.com to support@reply.example.com, subject Re: Your order A-1042, says: Could you update the delivery address? I've attached the details. Thanks, Maya Attached: delivery-address.pdf. The webhook posts message.received with messageId and conversationId. Webhook excerpt: {"type":"message.received","data":{"messageId":"msg_7q2xk9mvt4znw8rh","channel":"email","direction":"inbound","from":"maya@example.com","to":"support@reply.example.com","subject":"Re: Your order A-1042","conversationId":"conv_8r3ym2nkv5xpq9tw","hasAttachments":true,"isAutoReply":false,"body":"Could you update the delivery address? I've attached the details. Thanks, Maya"}} Email details excerpt: {"id":"msg_7q2xk9mvt4znw8rh","conversationId":"conv_8r3ym2nkv5xpq9tw","hasAttachments":true,"attachmentCount":1,"attachments":[{"id":"att_5n8xq2kvr7wpm9yt","filename":"delivery-address.pdf","contentType":"application/pdf","size":18432,"isInline":false,"contentId":null}]} Verify the webhook signature before using these fields. The body contains HTML when available, otherwise text. Read attachment metadata by message id. Add includeDownloadUrls=true to request temporary links to the stored email content.

1. **Receive the reply** Enable receiving on your domain and route incoming email to your registered webhook.
2. **Verify the event** Check the signature, then use messageId and conversationId to connect the reply to your app.
3. **Read the details** Fetch the email for attachment metadata and content links, or the conversation for its history.

Fig 3. Isometric drawing: a reply enters the slot for support@acme.co, a parser reads its headers, and a sorter files it under conversation conv_5nz8qd3hv6r0wxkt.

Fig 3.

A reply comes in on your domain, is parsed, and is filed under the conversation of the email it answers.

## Receive, parse, and reply in three steps.

1. **Turn on receiving.** For a domain you send from, or a subdomain like `reply.yourapp.com` if your team's inbox already lives on the root domain.
2. **Get the webhook.** Each email arrives parsed as `message.received`, with the sender, subject, body, an attachments flag, and the conversation id. Verify the signature and dedupe on the webhook id.
3. **Reply in the thread.** Send with `inReplyToMessageId`. The answer stays on the same conversation in the customer's inbox and in yours.

## What your app gets.

- **Parsed, not raw**: Headers, text and HTML bodies, and attachments you can download by id.
- **Threaded to the right conversation**: Matched by reply headers. An email with no reply headers is matched by subject and participants. A new conversation starts when nothing matches.
- **Auto-replies flagged**: Out-of-office and other automatic replies are marked, so they don't page your support queue.
- **Readable by your agent**: Your coding agent can fetch any conversation by id through MCP or the SDK.

## An email parser that hands you fields, not MIME.

- **Sender and recipients**: The webhook carries `from`, `to`, and `toEmails`, every address of yours the email was routed through. The message details add cc, bcc, and reply-to.
- **Subject and bodies**: The webhook has `subject` and a `body`: the HTML when there is one, otherwise the text. The message details return signed links to the HTML, the text, and the raw MIME.
- **Attachments**: `hasAttachments` tells you whether to look. List them by message, with filename, content type, size, and whether each is inline, then fetch any one by id through a time-limited download link.
- **Threading headers**: `Message-ID`, `In-Reply-To`, and `References` are parsed and returned with the message. They place the email in its conversation, and `conversationId` is in the webhook.
- **Auto-replies, with the reason**: `isAutoReply` is in the webhook. The message details say why: out-of-office, auto-response, delivery status, or read receipt.

## One reply, wherever your app needs it.

message.received

POST /hooks/samva

your endpoint, signature checked

Samva signs the webhook. Your endpoint checks the signature, then hands the reply to whatever needs it.

- Support queue
   
   ticket
- Customer record
   
   note
- Your agent
   
   draft reply

## A parse webhook, or an inbound email API.

Inbound email API compared with a parse webhook

A parse webhook hands you an email. The inbound email API hands you that email with the sender's address and the conversation it belongs to.

| What your app receives | The email, in the shape that webhook posts | A signed message.received webhook with the sender, subject, body, and conversation id |
| --- | --- | --- |
| Which thread it joins | You match the reply | Filed on the conversation of the email it answers. Your next send stays there when you pass that conversation or message |
| How you reply | A separate send you thread yourself | Send with inReplyToMessageId so the answer stays in the customer's thread |
| Attachments | Often included in the payload | hasAttachments on the webhook, then each file by id |
| Automatic replies | You detect them | isAutoReply is on the webhook, with the reason on the message |

Read next: [Parse and reply](https://samva.dev/guides/inbound-email-parsing) · [Run the inbound replies example](https://github.com/SamvaHQ/samva/tree/main/examples/inbound-email-replies) · [Receive email in Node.js](https://samva.dev/guides/receive-email-nodejs) · [Receive email in Python](https://samva.dev/guides/receive-email-python) · [Move SendGrid Inbound Parse](https://samva.dev/guides/sendgrid-inbound-migration) · [Move Mailgun Routes](https://samva.dev/guides/mailgun-inbound-migration) · [inbound.new alternative](https://samva.dev/compare/inbound-new) · [Support replies](https://samva.dev/solutions/support) · [Email for an agent](https://samva.dev/docs/mailboxes)

## Common questions.

### What is an inbound email API?

It receives email on a domain you control and gives your app the parsed message. Samva delivers each one as a signed message.received webhook, with the sender's address and the conversation of the email it answers. Reply by passing that conversation, or the message it answers, on the next send.

### What does Samva's email parser return?

A \`message.received\` webhook with the sender, the addresses it was routed through, the subject, a body, attachment and auto-reply flags, and the conversation id. The message details add the threading headers, cc and bcc, signed links to the HTML, text, and raw MIME, and each attachment.

### How do I turn an incoming email into a webhook?

Enable receiving on a domain and point it at an HTTPS endpoint that subscribes to \`message.received\`. Samva accepts the email, parses it, and POSTs it to your endpoint as a signed JSON event. Verify the signature over the raw body before you read it. The Node.js and Python guides show a working handler for each.

### Will this break our existing inbox?

Receiving moves the mail records for the domain you pick. Use a subdomain if your team's email already runs on the root domain.

### How does Samva know which conversation a reply belongs to?

From the reply's headers. An email with no reply headers is matched by subject and participants. Outbound email carries the headers replies need.

### Can I get attachments?

Yes. The webhook says whether an email has attachments; fetch each one by id.

### Does Samva clean quoted text out of replies?

Not yet. You get the body as the sender wrote it, including any quoted history.

### How is this different from a parse webhook?

A parse webhook hands you an email. Samva hands you the email with the sender's address and the conversation id, already threaded to the email it answers.

## The rest of the email API.

- [Send email in one typed call](https://samva.dev/features/transactional-email): Transactional email from the SDK, REST, CLI, or your agent through MCP. Retries are safe.
- [Replies land in your app](https://samva.dev/features/inbound-email): Receive on your domain, parsed and threaded to the email it answers, delivered as a signed webhook.
- [Change the email without a deploy](https://samva.dev/features/templates): Versioned templates in Git. Review the diff, publish that version.
- [Know why an email did or didn't land](https://samva.dev/features/deliverability): SPF and DKIM on your domain, suppression you can see, events for every send.
- [Send the announcement too](https://samva.dev/features/campaigns): Campaigns go to a list of contacts from the same templates and domain.
- [An inbox for your AI agent](https://samva.dev/features/mailboxes): A mailbox your agent reads and replies from, with a key that reaches only it.

## Handle your first reply today.

[Start sending free](https://samva.dev/signup?entry=marketing_page)

[Build the inbound path](https://samva.dev/guides/inbound-email-parsing)
