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

messages.list

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

Arguments

unread_only boolean
thread_id string
limit number
Defaults to 25.

Returns{ messages: Message[] }

messages.get

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

Arguments

id string required

ReturnsMessage

messages.reply

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

Arguments

id string required
The message you are answering.
html string
text string

Returns{ id, status }

threads.get

Every message in one conversation, oldest first.

Arguments

id string required

ReturnsThread

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.