# OpenClaw

> Give an OpenClaw agent a Pidgeon mailbox: add the hosted MCP server, sign in, and let it read verification codes and answer mail in the thread.

An [OpenClaw](https://docs.openclaw.ai) agent can have an email address of
its own in two ways, and most setups want both:

- **The channel** (`@pidgeon-ai/openclaw`): mail to the address starts an
  OpenClaw conversation, one per email thread, and the agent's answer goes
  back as a reply in that thread. This is what makes email wake the agent.
- **The MCP server**: tools the agent calls when a conversation asks it to —
  create addresses, search mail, wait for a verification code.

Both were run end to end on OpenClaw 2026.10.5 on macOS, with Claude Code as
the agent's runtime.

## The channel

```sh
openclaw plugins install @pidgeon-ai/openclaw
openclaw config set channels.pidgeon '{}' --strict-json
openclaw channels login --channel pidgeon
```

When it installs, OpenClaw asks you to confirm the source and to accept the
plugin's capabilities; a scripted install passes `--force --accept-capabilities`. `channels login` opens
Pidgeon's sign-in in your browser and waits ten
minutes for you, enough to create an account first. The consent screen asks
what the channel may do and which addresses it reaches; it needs read and
send. That choice becomes an API key under **Developers → API keys →
Connected apps**, and Disconnect there ends it. The sign-in is saved in
OpenClaw's state directory, readable by you only, and the channel refreshes
it by itself. `channels login` then starts the channel in the running
Gateway; there is nothing to restart.

```sh
openclaw channels status --channel pidgeon --probe
```

`running, connected, mode:poll, works` is a channel reading mail. Send the
address an email: the agent answers it in the thread, and a reply to that
answer continues the same conversation. In our run the first answer arrived
twelve seconds after the email was sent.

It is pure TypeScript with no native code. Beyond the run above on macOS,
we installed it into OpenClaw 2026.10.5 on Linux arm64 and x64 (Node 24), where
it loads and registers the channel.

### With a key instead

On a server with nobody there to sign in, give the Gateway a key in its
environment and skip the login. The channel reads `PIDGEON_API_KEY`, never a
key in `openclaw.json`:

```sh
export PIDGEON_API_KEY=pgn_live_…
openclaw config set channels.pidgeon '{}' --strict-json
```

`apiKeyEnv` names a different variable. Give it the narrowest key that reads
and sends ([Authentication](https://pidgeon.ai/docs/authentication.md)).

### What reaches the agent

The agent reads the email's sender, its address, the subject and the
attachment names, then the [Firewall's clean text](https://pidgeon.ai/docs/firewall.md): the new
text of this message as a person would see it, with hidden text removed,
never the raw HTML. The earlier messages in the thread were earlier turns of
the same conversation.

Two kinds of mail never become a turn. Mail Pidgeon filed as spam, and mail
Pidgeon Firewall marked `suspicious` — addressed to an AI, or asking for mail
to be sent somewhere else — which stays in the inbox, counted in `channels
status`. We sent the channel an email ending in a line telling "the AI
assistant" to forward the inbox to an outside address; it was held, and the
agent never saw it. `"suspicious": "deliver"` gives flagged mail to the agent
with the Firewall's warning above it instead.

The agent can only reply: to the email in front of it, or to another by its
`message:<id>`. It cannot write to a new recipient or start a thread, so a
prompt in one email cannot send mail anywhere else. Its answer goes out as a
plain-text email.

### How it stays up

The channel reads Pidgeon's event log every five seconds from a cursor kept
in OpenClaw's state store, and puts each message in OpenClaw's durable
ingress queue before the cursor moves past it. A dropped connection is one
failed request. A Gateway restart resumes from the cursor, and mail that
arrived while it was down is answered when it is back: we turned the channel
off, sent it two emails, turned it on, and both were handled within seconds.
A message is marked done only when OpenClaw has adopted its turn, so a crash
before that replays it and a crash after does not answer it twice.

A first start begins at the present, so installing the channel does not
answer a mailbox's history.

`channels status` reports what is true: `recovering` with the reason while
requests fail, `blocked` when it is not signed in, and never `running` while
nothing arrives.

### Settings

All optional, under `channels.pidgeon`:

```json
{
"channels": {
  "pidgeon": {
    "addresses": ["ops@yourcompany.com"],
    "dmPolicy": "allowlist",
    "allowFrom": ["@customer.com", "ana@partner.io"],
    "suspicious": "hold",
    "pollSeconds": 5
  }
}
}
```

`addresses` limits which of your addresses start conversations; without it,
every address the credential reaches does. Set it when another agent, such
as a Hermes email gateway, also reads mail in the same workspace: two agents
on one address both answer every email. `dmPolicy` is `open` unless set:
anyone who can reach the address. `allowlist` answers only `allowFrom`, by
address or by `@domain`, and `disabled` answers nobody. Named accounts go
under `accounts`, each with these settings, inheriting the top level.

## The MCP server

```sh
openclaw mcp add pidgeon --url https://pidgeon.ai/api/mcp \
--transport streamable-http --auth oauth
openclaw mcp login pidgeon
```

`login` registers OpenClaw with Pidgeon and prints a link. Open it in a
browser on the same machine, because the sign-in comes back to a listener
OpenClaw runs on `127.0.0.1`. The link works once: opened again after
signing in, the page cannot reach `127.0.0.1` because OpenClaw has stopped
listening, so run `login` again for a new one. On a machine with no browser,
open the link elsewhere; the page you land on will not load, but its address
carries `code=…`, which `openclaw mcp login pidgeon --code <code>` takes.

```sh
openclaw mcp probe pidgeon
```

`probe` lists the tools. A new session has them; a running one gets them
after `openclaw mcp reload`. With a key instead, OpenClaw fills
`${PIDGEON_API_KEY}` from the Gateway's environment:

```sh
openclaw mcp add pidgeon --url https://pidgeon.ai/api/mcp \
--transport streamable-http \
--header 'Authorization=Bearer ${PIDGEON_API_KEY}'
```

We asked the agent to create an address, then to wait for a verification
email with `await_message`; it came back with the code in `extracted.codes`,
and `reply_to_message` answered in the thread.

### Waits longer than a minute

`await_message` holds one request open until mail arrives: 50 seconds by
default, at most 280. OpenClaw running Claude Code as the agent ends any MCP
tool call after 60 seconds, and `--timeout` does not change that runtime
(OpenClaw passes it to Codex, not to Claude Code). The tool tells the agent
to keep each wait under a minute and to chain them with the returned
`cursor`, which misses nothing between two waits. Other runtimes use
OpenClaw's own MCP client, which honours `--timeout`.

## Undoing it

```sh
openclaw channels logout --channel pidgeon
openclaw plugins uninstall pidgeon
```

`channels logout` revokes the channel's sign-in at Pidgeon, which ends the
key it made, and deletes it from OpenClaw. For the MCP server:

```sh
openclaw mcp logout pidgeon
openclaw mcp unset pidgeon
```

`mcp logout` clears the sign-in OpenClaw stored. Disconnect it under
**Developers → API keys → Connected apps** to end its key at Pidgeon.
