Search the docs

Find a page, a section, or an endpoint.

n8n

A trigger for mail that arrives, actions, and three templates.

Give an n8n workflow an email address of its own. Mail that arrives starts the workflow; the workflow replies, saves drafts for a person to send, hands threads to people and waits for verification codes. Nobody's own inbox is connected to n8n, and a model in the workflow only ever reads the one message in front of it.

Use an address on pidgeon.email now, or connect your own domain. Pidgeon writes the SPF, DKIM and DMARC records for a domain you connect; the domain stays yours, and we do not sell domains. The inboxes you already have elsewhere stay where they are.

The package is @pidgeon-ai/n8n-nodes-pidgeon, a community node. It has two nodes:

  • Pidgeon Trigger starts a workflow when mail arrives at an address, or when a thread is handed to a person or back to the agent.
  • Pidgeon acts: create and list addresses; get, search, send and reply to messages; wait for a verification code; save and send drafts; hand a thread to a person or take it back; download an attachment.

It was run end to end on n8n 2.44.6, against production, with a test key.

Install

On a self-hosted n8n, as an owner or admin: Settings → Community Nodes → Install, and enter the package name.

@pidgeon-ai/n8n-nodes-pidgeon

n8n 3.0 stops loading community nodes it has not verified unless N8N_UNVERIFIED_PACKAGES_ENABLED=true is set, and this one is not verified yet. On n8n 2.x it loads as it is.

n8n Cloud runs verified community nodes only, so the package is not available there until n8n verifies it. On Cloud today, use n8n's own MCP Client node (below).

A trigger needs n8n on a public HTTPS URL, because Pidgeon delivers webhooks only to HTTPS. n8n uses WEBHOOK_URL as that address. On a laptop, a tunnel such as cloudflared tunnel --url http://localhost:5678 gives you one.

The credential

Make a key at Developers → API keys, then in n8n: Credentials → New → Pidgeon API, and paste it. n8n tests it against GET /v1/me.

One address and one key per workflow, with the least access it needs. Whatever the key reaches, the workflow can reach, and so can any model you give the workflow's output to.

The workflowAccess
Only triggers, searches and readsread
Saves drafts, hands threads overdraft
Replies or sendssend
Creates addressesadmin

A test key (pgn_test_…) works the same way, and nothing it sends leaves Pidgeon (test mode). Build the workflow on one, deliver mail to it with POST /v1/test/inbound, and switch the credential to a live key when it works. A test key cannot create addresses.

The trigger

Choose Message Received or Thread Handed Off, and the address to watch. One address per trigger.

When the workflow starts listening, the trigger creates its own webhook on Pidgeon for that address, keeps the signing secret where only n8n can read it, and checks the signature on every delivery: a request that is not signed by Pidgeon, or is more than five minutes old, gets 401 and starts nothing. When the workflow stops, the webhook is deleted. Listening in the editor and the published workflow each have their own webhook, and each counts against your plan's webhook endpoints while it exists.

Message Received

Pidgeon's webhooks carry ids and metadata, never a body. With Fetch the message on, the default, the trigger reads the message and its thread before the workflow starts, so the item carries the text, the sender's authentication, codes and links. Every field a router branches on is a plain field, so IF and Switch nodes test it with no model in between:

json
{
"event": "message.received",
"event_id": "0044ed22-…",
"message_id": "1a70b25d-…",
"thread_id": "463ec73a-…",
"address": "quotes@acme.pidgeon.email",
"from": "priya@supplier.de",
"from_name": "Priya Raman",
"to": ["quotes@acme.pidgeon.email"],
"cc": [],
"delivered_to": "quotes@acme.pidgeon.email",
"matched_by": "identity",
"subject": "Angebot 4471",
"received_at": "2026-10-25T09:14:03Z",
"spam": false,
"from_self": false,
"bcc_to_this_address": false,
"is_reply": false,
"firewall_verdict": "clean",
"firewall_signals": [],
"auth_spf": "pass",
"auth_dkim": "pass",
"auth_dmarc": "pass",
"thread_status": "open",
"thread_owner_type": "agent",
"thread_assignee_id": null,
"text": "Guten Tag, anbei unser Angebot …",
"reply_text": "Guten Tag, anbei unser Angebot …",
"codes": [],
"links": [],
"attachments": [
  { "id": "0b1d4e8c-…", "filename": "angebot.pdf", "content_type": "application/pdf", "size": 48211 }
],
"test": false
}
  • text is clean by default. Pidgeon Firewall takes out anything hidden or addressed to an AI. firewall_verdict is suspicious when it found something: route that mail to a person, not to a model. Original is the text exactly as sent, one dropdown away.
  • from_self is the one to check before replying. Mail one of your addresses sends to another arrives as ordinary mail.
  • auth_dmarc is pass only when the From is not forged. Check it before acting on who an email says it is from.
  • bcc_to_this_address is true when the address is in neither to nor cc. A BCC gives the agent one message, not a conversation: the reply goes to you, not to it.
  • thread_owner_type is human once a person has taken the thread. Leave those alone.

Without Fetch the message the item has only what the webhook carried: the ids, addresses, subject, Firewall verdict and attachments.

Thread Handed Off

Starts when a person takes a thread or it is assigned to somebody (To a Person), when it is handed back (Back to the Agent), or either. The item:

json
{
"event": "thread.updated",
"thread_id": "463ec73a-…",
"owner_type": "human",
"previous_owner_type": "agent",
"status": "open",
"assignee_id": null,
"assigned_by": null,
"reason": "Complaint about an order",
"address": "hello@acme.pidgeon.email",
"subject": "Order 1182 arrived broken",
"from": "dana@example.com",
"changed_at": "2026-10-25T10:02:11Z"
}

Use it to post to Slack or a CRM when a person must act, or to stop a workflow that would answer a thread somebody now holds.

The actions

OperationWhat it doesAccess
Address → CreateA new address: agent or workflow, and who it may write toadmin
Address → Get ManyThe addresses the key reachesread
Message → GetOne message as the trigger's item, clean by defaultread
Message → SearchMessages by words, sender or folderread
Message → Wait for a CodeHolds until mail with a verification code arrives; returns coderead
Message → ReplyWrites to people outside your account: answers in the threadsend
Message → SendWrites to people outside your account: a new conversationsend
Draft → SaveA draft in the address's Drafts folder, threaded as a replydraft
Draft → SendWrites to people outside your account: sends a saved draftsend
Thread → Hand to a PersonMarks it as a person's, optionally assigned to somebodydraft
Thread → Take BackGives it back to the agentdraft
Attachment → DownloadThe file, as n8n binary dataread
  • Sends are safe to retry. Every write carries an Idempotency-Key made from your n8n, the workflow, the execution, the node and the item, so n8n's Retry On Fail replays a send whose answer was lost rather than sending it twice, and two n8n instances on one account never share a key.
  • Wait for a Code does not fail when nothing arrives: the item has timed_out: true, for an IF node to branch on. It looks back two minutes first, so a code that arrived before the wait is not missed; pass the returned cursor as After to wait for the next one.
  • As an AI Agent tool, the node offers the operation you chose when you added it, and the model fills in its fields. Give an agent Search or Save a draft, and keep sending as a step you wire.

A draft waits because nothing sends it. Pidgeon holds no draft back by itself yet, and a send key that saves drafts can also send. To approve before anything goes out, give the workflow a draft key, and send from the web inbox, from a mail client (Drafts is a folder there too), or with Slack's Send and Wait for Response followed by Draft → Send on a send key.

Templates

Each one is a workflow to import: in n8n, Workflows → Import from URL, and paste the link. Each opens with a note that says how to set it up.

Draft replies to emails you forward

forward-to-your-agent.json

You forward one email to the agent's address. The workflow checks the forward came from one of your own addresses, passed DMARC and is clean; a model drafts an answer in your style; and the draft comes back to you as a reply, threaded under what you sent. You edit it and send it from your own address. The address only answers people who wrote first, and the key is send on that one address.

The trigger reads the original text here. Pidgeon treats a forwarded original as quoted history, so the clean text of a forward holds only your note on top. The Firewall still screens the whole message, which is why the workflow goes on only when the verdict is clean.

Forward is for "answer this". BCC is for "watch what I send": the agent gets your message, and the reply goes to you.

Sort, draft and hand off inbound email

inbound-qualifier.json

The public address (hello@, sales@) is the agent's. Spam, your own mail and threads a person has taken are left alone. Rules on the subject and text sort the rest, with no model: quote requests and orders get a drafted reply saved for a person to send; complaints, anything the Firewall marks suspicious and what the rules cannot place are handed to a person, and Slack hears about it; out-of-office replies are dropped. The key is draft on that one address.

An address per workflow

address-per-workflow.json

A supplier that can only email its exports. The workflow owns an address, checks the mail is from the expected sender and passed DMARC, downloads the CSV attachment, and appends its rows to Google Sheets. The address must keep mail: one without an inbox stores nothing, so there would be no file to download. The key is read on that one address.

Pidgeon finds verification codes and links in mail. Parsing a file or pulling names, dates and amounts out of text is n8n's job, or a model's.

All three are also in pidgeon-ai/pidgeon-examples.

On n8n Cloud today

n8n's own MCP Client node can call Pidgeon's hosted MCP server on Cloud now, with no package. Add an MCP Client node (or MCP Client Tool under an AI Agent), set:

  • Server Transport: HTTP Streamable
  • MCP Endpoint URL: https://pidgeon.ai/api/mcp
  • Authentication: Bearer Auth, with a Pidgeon key

and pick a tool, such as list_addresses or await_message. It has no trigger: for mail as it arrives, a Webhook node needs a webhook you create with POST /v1/webhooks and a Code node that checks the signature.

Limits

  • The trigger watches one address. For several, add a trigger for each, with a key for each.
  • Each listening trigger uses one webhook endpoint against your plan.
  • Search returns at most 100 messages per run.
  • Wait for a Code waits at most 280 seconds per run.