---
title: "Message source"
description: "Download any message as an `.eml` file, keep the original of every message an address receives, and hand the source to a webhook."
url: "https://nextmail.sh/docs/knowledge/developers/raw-messages"
area: "Knowledge base"
category: "Developers"
---

# Message source

Download any message as an `.eml` file, keep the original of every message an address receives, and hand the source to a webhook.

## Original or rebuilt

Every message in Nextmail can be downloaded as its source: one `message/rfc822` file with the headers and the MIME body, the file a mail app saves as `.eml` or shows under Show original. Each download says which of two sources it is.

| Source | What it is |
| --- | --- |
| `original` | The message byte for byte as it arrived, with every header it carried: the `Received` lines, `Authentication-Results`, the DKIM signatures and the rest. It exists only for mail an address received while it had Keep original on. |
| `rebuilt` | Written again from the message Nextmail stored, the same bytes its IMAP server hands a mail app: the addresses, the subject, the date, the Message-ID, the threading headers, the text and HTML and every attachment. Every message has one, including the ones sent from Nextmail and drafts. |

> A rebuilt source has none of the other headers the message arrived with, so a DKIM signature cannot be checked against it and a parser that looks for a particular header may not find it. When you need the exact bytes, turn Keep original on before the mail arrives: it is never kept for mail that came in earlier.

## Keep original

Keep original is a setting of one address, off until somebody turns it on. While it is on, every message the address receives is also stored exactly as it arrived, sealed like an attachment, and its download answers `original`. Turning it off stops keeping new messages and leaves the ones already kept where they are.

- An original belongs to its message. It is deleted when the conversation is deleted for good and when the workspace is deleted, and it moves with its conversation when a domain moves to another workspace.
- Removing an address keeps its conversations, and with them their originals, until they are deleted.
- Each address keeps its own copy, so a message sent to two addresses that keep originals is stored twice.
- If an original cannot be stored, the message is still filed as usual and its download answers `rebuilt`.

- In the web app, Keep original messages is a switch on the Delivery tab of the address page. In the phone app, the same switch is on the Delivery tab of the address screen.
- Over REST, `keepOriginal` on `POST /domains/{id}/addresses` and `PATCH /domains/{id}/addresses/{addressId}`, and every address reports it.
- In the SDKs, `keepOriginal` on `domains.createAddress` and `domains.updateAddress`, written the way each language writes names.
- On the command line, `nextmail domains update-address <domain-id> <address-id> --keep-original`.
- Over MCP and in the assistant, `keepOriginal` on `addDomainAddress` and `updateDomainAddress`.

## Download a message

`GET /threads/{id}/messages/{messageId}/raw` answers the file, named after the message id, with `Content-Type: message/rfc822` and the source in the `X-Message-Source` header. It needs `threads:read`, and the thread is checked first and then the message, exactly as `GET /threads/{id}/messages/{messageId}` does, so a key limited to some addresses only reaches the mail that arrived at them. The `emailId` of an `email.received` webhook is the message id to pass, beside its `threadId`.

- In the web app, open the conversation and choose Download original in the More menu of the message, the three dots beside it. The phone app has no Download original.
- In the SDKs, `threads.getRawMessage(threadId, messageId)` returns the bytes, as a `Uint8Array` in TypeScript and the byte type of each other language.
- On the command line, `nextmail threads get-raw-message <thread-id> <message-id> --out message.eml` writes the file, and without `--out` the bytes go to a pipe.
- Over MCP and in the assistant, `getRawMessage` returns the source as text, at most the first 256 KiB, with `source` and whether it was `truncated`. Without a message id it reads the latest message of the thread.

**Terminal**

```
nextmail threads get-raw-message <thread-id> <message-id> --out message.eml
```

## Source in webhooks

An endpoint with `includeRaw` on gets a link to the source in every `email.received` event, as `data.raw`. The link downloads the message with no key, and is worked out again for every attempt, so a retry or a replay always carries a fresh one and the delivery log never holds it. Turning `includeRaw` on needs `threads:read`, as `includeContent` does, and the two can be on together. In the web app it is the Include the raw message switch in the form of the endpoint, and in the phone app the same switch is on the webhook screen. The webhooks guide covers the rest of the payload.

| Field | What it holds |
| --- | --- |
| `url` | The link, under `/public/webhook-raw/`. |
| `size` | The size of the source in bytes. |
| `source` | `original` or `rebuilt`, as above. |
| `expiresAt` | When the link stops working, an hour after the attempt was sent. |

> The link also stops working as soon as the endpoint is switched off or stops including the source, and when the message is deleted. Download it when the event arrives rather than storing the link.

- [Webhooks](https://nextmail.sh/docs/knowledge/developers/webhooks.md): Events, signatures, retries and what each payload carries.
- [SDK methods](https://nextmail.sh/docs/sdk/reference/threads.md): The `threads` methods, `getRawMessage` among them.
- [CLI commands](https://nextmail.sh/docs/cli/reference/threads.md): The `nextmail threads` commands, with every flag.
- [MCP tools](https://nextmail.sh/docs/mcp/tools/reading.md): The tools that find and read mail.
