# Receive & reply

Set up inbound email handling with webhooks, SSE streaming, or polling, and send automatic replies.

## 1. Create a webhook

```curl
curl -X POST https://api.robotomail.com/v1/webhooks \
  -H "Authorization: Bearer $ROBOTOMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/email",
    "events": ["message.received"]
  }'
```


## 2. Handle the webhook

When an email arrives, Robotomail sends a POST request to your endpoint with the message data. Verify the signature before processing:

```node.js
import crypto from "crypto";

app.post("/webhooks/email", (req, res) => {
  // The signature is computed over the raw request body string, not parsed JSON
  const rawBody = req.body; // use express.raw() or express.text() middleware
  const signature = req.headers["x-robotomail-signature"];
  const expected = crypto
    .createHmac("sha256", WEBHOOK_SECRET)
    .update(rawBody)
    .digest("hex");

  if (signature !== expected) return res.status(401).send("Invalid signature");

  const { event, timestamp, data } = JSON.parse(rawBody);

  if (data.over_limit) {
    // Account is over its monthly inbound cap. The payload omits body and
    // attachments — only identity fields are present. The message is safely
    // persisted; upgrading or the first-of-month reset unlocks it.
    console.log(`[over-limit] message_id=${data.message_id} mailbox=${data.mailbox_id}`);
    return res.status(200).send("OK");
  }

  console.log(`[${event}] from ${data.from}: ${data.subject} at ${timestamp}`);

  res.status(200).send("OK");
});
```

See [402 `INBOUND_LIMIT_EXCEEDED`](https://robotomail.com/docs/api/errors#inbound-limit-exceeded) for the full over-limit behavior across webhooks, SSE, and the REST API.


## 3. Send a reply

Reply to the inbound message by passing its `messageId` (the RFC 5322 Message-ID header value) in the `inReplyTo` field:

```curl
curl -X POST https://api.robotomail.com/v1/mailboxes/MAILBOX_ID/messages \
  -H "Authorization: Bearer $ROBOTOMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": ["sender@example.com"],
    "subject": "Re: Their subject",
    "bodyText": "Thanks for your email! Here is my reply.",
    "inReplyTo": "<original-message-id@example.com>"
  }'
```

This automatically threads the reply with the original message.


## Alternative: Polling or SSE

If you can't set up a webhook endpoint, you have two alternatives:

**SSE streaming:** Open a persistent connection to `GET /v1/events` for real-time events without a public URL. Use `robotomail listen` from the CLI, or connect directly. See the [Events (SSE) API](https://robotomail.com/docs/api/events).

**Polling:** Poll for new messages using the `since` parameter:

```curl
curl "https://api.robotomail.com/v1/mailboxes/MAILBOX_ID/messages?direction=INBOUND&since=2026-03-11T00:00:00Z" \
  -H "Authorization: Bearer $ROBOTOMAIL_API_KEY"
```


---

Previous: [Send your first email](https://robotomail.com/docs/guides/send-first-email.md) | Next: [Custom domain setup](https://robotomail.com/docs/guides/custom-domain.md)
