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-pidgeonn8n 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 workflow | Access |
|---|---|
| Only triggers, searches and reads | read |
| Saves drafts, hands threads over | draft |
| Replies or sends | send |
| Creates addresses | admin |
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:
{
"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
}textis clean by default. Pidgeon Firewall takes out anything hidden or addressed to an AI.firewall_verdictissuspiciouswhen it found something: route that mail to a person, not to a model. Original is the text exactly as sent, one dropdown away.from_selfis the one to check before replying. Mail one of your addresses sends to another arrives as ordinary mail.auth_dmarcispassonly when the From is not forged. Check it before acting on who an email says it is from.bcc_to_this_addressis true when the address is in neithertonorcc. A BCC gives the agent one message, not a conversation: the reply goes to you, not to it.thread_owner_typeishumanonce 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:
{
"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
| Operation | What it does | Access |
|---|---|---|
| Address → Create | A new address: agent or workflow, and who it may write to | admin |
| Address → Get Many | The addresses the key reaches | read |
| Message → Get | One message as the trigger's item, clean by default | read |
| Message → Search | Messages by words, sender or folder | read |
| Message → Wait for a Code | Holds until mail with a verification code arrives; returns code | read |
| Message → Reply | Writes to people outside your account: answers in the thread | send |
| Message → Send | Writes to people outside your account: a new conversation | send |
| Draft → Save | A draft in the address's Drafts folder, threaded as a reply | draft |
| Draft → Send | Writes to people outside your account: sends a saved draft | send |
| Thread → Hand to a Person | Marks it as a person's, optionally assigned to somebody | draft |
| Thread → Take Back | Gives it back to the agent | draft |
| Attachment → Download | The file, as n8n binary data | read |
- Sends are safe to retry. Every write carries an
Idempotency-Keymade 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 returnedcursoras 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
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
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
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.