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

# Mailhook Trigger

> Give a workflow its own email address: any message sent to it starts a run.

A **mailhook** is a unique email address that belongs to one workflow. Send (or forward) an email to the address and the workflow runs with the parsed message as its input. Think of it as a webhook, but for email: no endpoint to host and no mailbox to connect. The address itself is the integration: unguessable, single-purpose, and revocable at any time.

```
mh-x7k2m9qf4a3vbn8c@mailhook.spojit.com
```

## Mailhook vs. Email trigger

Spojit has two ways to start a workflow from email. They solve different problems:

|                | **Mailhook**                                                                                               | **Email**                                                    |
| -------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| Address        | Generated by Spojit, unique per workflow                                                                   | Your own Gmail / Outlook mailbox                             |
| Authentication | Unguessable capability address, plus optional sender filters                                               | OAuth connection to your provider                            |
| Delivery       | Push: runs start when the message arrives                                                                  | Poll: Spojit checks the mailbox on an interval               |
| Mailbox state  | No mailbox; messages aren't stored in folders                                                              | Messages stay in your mailbox; optional mark-as-read / move  |
| Pick it when   | You control where the mail is sent (forwarding rules, vendor notification settings, system-generated mail) | The mail already lands in a mailbox you own and need to keep |

If you can point the sender at a new address, a mailhook is the simpler option. If the mail is already flowing into a real inbox you can't change, use the [Email trigger](/workflow-editor/nodes/trigger#email).

## Setup

1. Select the trigger node, set **Trigger Type** to **Mailhook**.
2. Optional: enter an **Address prefix** (see below). Leave it empty for the default `mh`.
3. Click **Generate email address**. The address appears immediately with a copy button.
4. Point mail at it: add it to a vendor's notification settings, create a forwarding rule in your mail client, or use it directly as a "send results here" address in another system.
5. Optional: add a **From allowlist** or **Subject regex** filter, then **Save workflow**.

The trigger is active as soon as the address is generated. Use the **Active** toggle to pause it without losing the address.

## The address

Addresses have the shape `<prefix>-<random>@mailhook.spojit.com`:

* The **random part** is 16 characters of cryptographically random base32. This is what makes the address unguessable; treat it like a capability. Anyone who knows the full address can start the workflow (subject to your filters).
* The **prefix** is cosmetic and yours to choose: 1 to 24 lowercase letters, digits, or hyphens. `invoices`, `support-intake`, `crm-sync`. Defaults to `mh`. A recognizable prefix makes forwarding rules and audit logs easier to read.

Changing the prefix in the properties panel does not change an existing address; it applies the next time you generate or regenerate.

## Filters

Two optional filters narrow what fires a run. They are the same filters the Email trigger uses:

* **From allowlist**: comma-separated patterns. `@acme.com` matches any sender at acme.com; `orders@vendor.com` matches the exact address. Multiple patterns are OR'd.
* **Subject regex**: a JavaScript-flavor regular expression. The message fires only if the subject matches.

If both filters are set, both must pass. Messages that don't match are dropped silently (no run, no error).

<Note>
  Sender addresses are trivially spoofable in email. The allowlist is a routing convenience, not an authentication mechanism. The real access control is the unguessable address itself; rotate it if it leaks.
</Note>

Filter changes take effect when you **Save** the workflow.

## Rotating the address

Click **Regenerate address** in the trigger properties panel. A new random address is generated and **the old address stops working immediately**: mail sent to it is silently discarded. There is no grace period, so update your forwarding rules and vendor settings right after rotating.

Rotate whenever the address has spread further than you intended (posted in a ticket, shared with a vendor you've offboarded, leaked in a screenshot).

## Workflow input

The parsed message is the trigger's output, available to downstream nodes as `{{ input }}`:

```json theme={null}
{
  "provider": "resend",
  "emailId": "4ef9a417-02e9-4d39-ad75-9aa401bb7d2a",
  "messageId": "<CAOg7P2Vy@mail.example.com>",
  "from": "Alice Chen <alice@acme.com>",
  "to": ["mh-x7k2m9qf4a3vbn8c@mailhook.spojit.com"],
  "cc": [],
  "replyTo": ["alice@acme.com"],
  "subject": "Invoice INV-2041",
  "text": "Hi, attached is this month's invoice...",
  "html": "<p>Hi, attached is...</p>",
  "truncated": false,
  "receivedAt": "2026-06-12T03:14:11.000Z",
  "attachments": [
    { "id": "att_1", "filename": "INV-2041.pdf", "contentType": "application/pdf" }
  ]
}
```

| Field                         | Description                                                                                                                        |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `from`, `to`, `cc`, `replyTo` | Sender and recipients as the message carried them                                                                                  |
| `subject`                     | Subject line                                                                                                                       |
| `text`, `html`                | Plain-text and HTML bodies. Either can be `null` if the sender didn't include that part                                            |
| `truncated`                   | `true` when a body exceeded 256 KB and was cut at that point                                                                       |
| `receivedAt`                  | ISO-8601 arrival timestamp                                                                                                         |
| `attachments`                 | References: id, filename, content type. The bytes are fetched on demand by an [Attachment node](/workflow-editor/nodes/attachment) |
| `emailId`, `messageId`        | Stable ids for the received message; useful for logging and correlation                                                            |

## Behavior notes

* **Always asynchronous.** The sender gets no response; there is no sync mode for mailhooks. Use a [Send Email node](/workflow-editor/nodes/send-email) in the workflow if you want to reply to `{{ input.replyTo }}`.
* **Deduplicated per message.** If the inbound provider retries delivery of the same message, the workflow still runs once.
* **Any recipient field counts.** The mailhook fires whether its address is in To, Cc, or Bcc.
* **One email, many mailhooks.** A single message addressed to the mailhook addresses of several workflows fires each of them independently.
* **Unknown addresses are accepted silently.** Mail to a rotated or deleted address is discarded without bouncing, so a leaked old address reveals nothing about whether it's still live.

## Tips

* Use one mailhook per source. Separate addresses for "vendor A invoices" and "vendor B invoices" cost nothing and keep filters simple, and you can rotate one without disturbing the other.
* Pair a mailhook with a forwarding rule in your mail client to mirror a slice of a real inbox into a workflow without connecting the mailbox at all.
* Prefer the subject regex over a broad allowlist when the same sender emails you for multiple reasons.
* For testing, email the address from your own account and watch the run appear in [Monitoring](/workflow-editor/monitoring).
