> ## Documentation Index
> Fetch the complete documentation index at: https://docs.automate.ax/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Automate.ax automations are TypeScript programs.
> Use Bun for installation and command examples.
> Use Automate.ax for the product name and automate.ax for the package, CLI, and domain.
> Treat documented public APIs as current; do not invent transitional or deprecated names.

# On mailhook

> Run an automation when email arrives at a managed address.

`onMailhook` receives email at a managed `@automations.automate.ax` address. Each call gets its own address by default; set `scope: "automation"` or `scope: "project"` to share one.

## Example

```ts automations/reply-inbox.automation.ts theme={null}
import {
  automation,
  correlate,
  eventId,
  filter,
  onHttpRequest,
  onMailhook,
  sendEmail,
  t,
} from "automate.ax"

export default automation("Reply inbox", () => {
  const request = onHttpRequest()
  const inbox = onMailhook({ scope: "automation" })
  const requestId = eventId(request)

  sendEmail({
    replyTo: { plusPath: requestId, scope: "automation" },
    subject: "Reply to this automation",
    text: t`This message was requested from ${request.path}.`,
  })

  const reply = filter(
    inbox,
    ({ isReply, plusPath }) => isReply && plusPath !== null,
  )

  correlate(
    [
      requestId.keyBy((id) => id, { ttl: "30d" }),
      reply.keyBy(({ plusPath }) => plusPath),
    ],
    { ordered: true },
  )

  sendEmail({
    subject: t`Reply to ${request.path} from ${reply.senderAddress}`,
    text: t`${reply.text}`,
  })
})
```

`inbox.address` is the deployed inbound address as a static string. Use it as the built-in `sendEmail` action's `replyTo` for an exact trigger address. For automation- or project-scoped mailhooks, you can instead pass `{ scope }` and an optional static or signal-valued `plusPath`.

## Options

| Option  | Type                                     | Required | Default     | Description                       |
| ------- | ---------------------------------------- | -------- | ----------- | --------------------------------- |
| `scope` | `"trigger" \| "automation" \| "project"` | No       | `"trigger"` | Scope at which email is received. |

Trigger configuration is static and cannot use signals. Trigger scope gives each `onMailhook` call a unique address. Automation scope shares an address across the automation. Project scope shares an address across the project; every active subscription at that scope receives matching email.

## Plus routing

Append `+suffix` before the `@` to route related addresses through the same mailhook. For example, if `inbox.address` is `abc@automations.automate.ax`, email sent to `abc+invoices@automations.automate.ax` sets `plusPath` to `"invoices"`. Use [`eventId(trigger)`](/reference/signals/coordinate-occurrences#event-identities) when the originating event has no natural correlation key. Use valid email local-part characters and keep the complete local part before `@` within the 64-byte email limit.

## Trigger data

Returns an email signal with static `address: string` and this message data:

| Property               | Type                     | Description                                  |
| ---------------------- | ------------------------ | -------------------------------------------- |
| `senderAddress`        | `string \| null`         | Parsed sender address.                       |
| `senderName`           | `string \| null`         | Parsed sender display name.                  |
| `additionalRecipients` | `string[]`               | Other To, Cc, and Bcc recipients.            |
| `subject`              | `string`                 | Message subject.                             |
| `text`                 | `string \| null`         | Plain-text body.                             |
| `html`                 | `string \| null`         | HTML body. Treat it as untrusted content.    |
| `attachments`          | `File[]`                 | Attached files, including inline MIME parts. |
| `headers`              | `Record<string, string>` | Original headers with lowercase names.       |
| `messageId`            | `string`                 | Sender-supplied RFC Message-ID.              |
| `inReplyTo`            | `string \| null`         | Message-ID named by the In-Reply-To header.  |
| `references`           | `string[]`               | Message-IDs in the conversation ancestry.    |
| `isReply`              | `boolean`                | Whether an In-Reply-To header is present.    |
| `plusPath`             | `string \| null`         | Suffix after `+` in the receiving address.   |
| `receivedAt`           | `Date`                   | Time Resend received the message.            |

Replies use the same trigger as other inbound email. Filter on `isReply` when an automation should only continue for replies.
