# Receiving replies

Publish an MX record and the replies to your transactional mail arrive as JSON instead of nowhere.

Most transactional email goes out from an address nobody watches, and every reply to it is lost. emails.sh can receive on a domain you verified, so a customer answering your receipt reaches you rather than a bounce.

This is the second half of the product and not the first. If all you need is to send, skip this page entirely.

### Turn it on

Publish the MX record listed with your domain's other records: MX mail.acme.com pointing at inbound-smtp.eu-west-1.amazonaws.com with priority 10. Only publish it on a subdomain that has no other mail on it, since an MX record decides where all mail for that name goes.

Once it resolves, mail to any address on that domain is stored and available over the API. There is no per-address setup: support@mail.acme.com and receipts@mail.acme.com both arrive.

### Get it pushed to you

Register a webhook for the email.received event and you get the message as JSON the moment it lands, signed, with the body and the attachment list. That is the shape most applications want: no polling, no cron.

Subscribe to inbound mail:
```bash
curl -X POST https://emails.sh/v1/webhooks \
  -H "Authorization: Bearer $EMAILSSH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://acme.com/hooks/emails",
    "events": ["email.received"]
  }'
```

### Or read it

- `GET /v1/messages` ?unread_only=true&thread_id=&limit= over received mail.
- `GET /v1/messages/:id` One received message in full.
- `POST /v1/messages/:id/reply-all` { body } answers on the same thread.
- `POST /v1/messages/:id/forward` { to, body?, mode? }
- `POST /v1/messages/:id/archive` { archived?, unread? }
- `GET /v1/messages/:id/attachments/:filename` One attachment, as its own bytes.
- `GET /v1/threads` Conversations, newest first.
- `GET /v1/threads/:id` Every message in one conversation.
- `GET /v1/search` ?q= ranked full-text search over received mail.

#### `messages.list`

`{ unread_only?: boolean, thread_id?: string, limit?: number }`

Mail that arrived at an address on a domain of yours with inbound turned on.

| Parameter | Type | Required |
| --- | --- | --- |
| unread_only | `boolean` | no |
| thread_id | `string` | no |
| limit | `number` | no |

Returns: { messages: Message[] }

#### `messages.get`

`{ id: string }`

One received message with its full body, headers, and attachment list.

| Parameter | Type | Required |
| --- | --- | --- |
| id | `string` | yes |

Returns: Message

#### `messages.reply`

`{ id: string, html?: string, text?: string }`

Answer a received message on its own thread, with References and In-Reply-To set for you.

| Parameter | Type | Required |
| --- | --- | --- |
| id | `string` | yes |
| html | `string` | no |
| text | `string` | no |

Returns: { id, status }

#### `threads.get`

`{ id: string }`

Every message in one conversation, oldest first.

| Parameter | Type | Required |
| --- | --- | --- |
| id | `string` | yes |

Returns: Thread

A reply is threaded to the message it answers, so GET /v1/threads/:id returns the whole exchange in order. Answering with POST /v1/messages/:id/reply-all sets In-Reply-To and References for you, which is what keeps the conversation in one place in the recipient's client.

Inbound mail is not a mailbox with a password. There is no IMAP and no webmail: it is an API surface, and the dashboard shows it read-only.

---

Base URL: https://emails.sh/v1. Auth: `Authorization: Bearer esh_...`.
Whole API in one file: https://emails.sh/llms.txt. All documentation: https://emails.sh/docs.md.
