Two email channels depending on how you want inbound messages delivered.
Who can talk to the agent
Inbound senders are gated against the peer set resolved for the bound
agent, drawn from the peer_groups config the agent belongs to. Matching strips
a leading @ and is case-insensitive against the channel’s native sender
identifier. An empty set denies everyone; a set containing "*" accepts
anyone; otherwise only the listed external peers (and peer agents) are accepted.
This is separate from gateway pairing (gateway.require_pairing), which
authenticates HTTP/WebSocket clients, not chat-channel senders.
A peer group for email sets channel to email, lists the allowed senders in
external_peers (for email, the sender’s email address; ["*"] accepts anyone), optionally
names peer agents for cross-agent dispatch, an ignore blocklist, and an
output_modality (mirror, voice, or text). See Peer Groups
for the field reference.
Where to set this:
Gateway dashboard
Open /config/peer_groups in the web dashboard.
zerocode
In the Config pane, under Peer groups.
IMAP + SMTP (email_channel)
The general-purpose email channel. Polls IMAP for new messages and, when SMTP is configured, sends via SMTP. Works with Gmail, Outlook, Fastmail, self-hosted Postfix, and anything else that speaks IMAP/SMTP.
default_subject
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.default_subject field.
zerocode
In the Config pane, set the channels.email.<alias>.default_subject field.
zeroclaw config
zeroclaw config set channels.email.<alias>.default_subject <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__default_subject=
excluded_tools
Tools excluded from this channel’s tool spec. When set, these tools are not exposed to the model when responding via this channel.
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.excluded_tools field.
zerocode
In the Config pane, set the channels.email.<alias>.excluded_tools field.
zeroclaw config
zeroclaw config set channels.email.<alias>.excluded_tools <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__excluded_tools=
from_address
From identity for outbound mail. Optional for the same reason as smtp_host: outbound sending requires both, and inbound-only channels never build an outbound message.
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.from_address field.
zerocode
In the Config pane, set the channels.email.<alias>.from_address field.
zeroclaw config
zeroclaw config set channels.email.<alias>.from_address <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__from_address=
html_body
When true (default), outbound emails are rendered as HTML via Markdown conversion. Set to false to send plain-text emails instead.
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.html_body field.
zerocode
In the Config pane, set the channels.email.<alias>.html_body field.
zeroclaw config
zeroclaw config set channels.email.<alias>.html_body <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__html_body=
idle_timeout_secs
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.idle_timeout_secs field.
zerocode
In the Config pane, set the channels.email.<alias>.idle_timeout_secs field.
zeroclaw config
zeroclaw config set channels.email.<alias>.idle_timeout_secs <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__idle_timeout_secs=
imap_folder
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.imap_folder field.
zerocode
In the Config pane, set the channels.email.<alias>.imap_folder field.
zeroclaw config
zeroclaw config set channels.email.<alias>.imap_folder <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__imap_folder=
imap_host*
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.imap_host field.
zerocode
In the Config pane, set the channels.email.<alias>.imap_host field.
zeroclaw config
zeroclaw config set channels.email.<alias>.imap_host <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__imap_host=
imap_port
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.imap_port field.
zerocode
In the Config pane, set the channels.email.<alias>.imap_port field.
zeroclaw config
zeroclaw config set channels.email.<alias>.imap_port <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__imap_port=
max_attachment_bytes
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.max_attachment_bytes field.
zerocode
In the Config pane, set the channels.email.<alias>.max_attachment_bytes field.
zeroclaw config
zeroclaw config set channels.email.<alias>.max_attachment_bytes <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__max_attachment_bytes=
oauth2
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.oauth2 field.
zerocode
In the Config pane, set the channels.email.<alias>.oauth2 field.
zeroclaw config
zeroclaw config set channels.email.<alias>.oauth2 <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__oauth2=
observer_mode
When true, the daemon observes new mail but never modifies any IMAP flag.
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.observer_mode field.
zerocode
In the Config pane, set the channels.email.<alias>.observer_mode field.
zeroclaw config
zeroclaw config set channels.email.<alias>.observer_mode <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__observer_mode=
password*
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.password field.
zerocode
In the Config pane, set the channels.email.<alias>.password field.
zeroclaw config
zeroclaw config set channels.email.<alias>.password <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__password=
poll_interval_secs
Polling interval used when the IMAP server does not advertise the IDLE capability (RFC 2177). Ignored when IDLE is available.
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.poll_interval_secs field.
zerocode
In the Config pane, set the channels.email.<alias>.poll_interval_secs field.
zeroclaw config
zeroclaw config set channels.email.<alias>.poll_interval_secs <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__poll_interval_secs=
smtp_host
SMTP relay host. Optional: when omitted (or blank) the channel stays read-write on IMAP (inbound processing, flag updates) but refuses to send, so an operator can grant mailbox access without outbound email.
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.smtp_host field.
zerocode
In the Config pane, set the channels.email.<alias>.smtp_host field.
zeroclaw config
zeroclaw config set channels.email.<alias>.smtp_host <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__smtp_host=
smtp_password
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.smtp_password field.
zerocode
In the Config pane, set the channels.email.<alias>.smtp_password field.
zeroclaw config
zeroclaw config set channels.email.<alias>.smtp_password <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__smtp_password=
smtp_port
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.smtp_port field.
zerocode
In the Config pane, set the channels.email.<alias>.smtp_port field.
zeroclaw config
zeroclaw config set channels.email.<alias>.smtp_port <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__smtp_port=
smtp_tls
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.smtp_tls field.
zerocode
In the Config pane, set the channels.email.<alias>.smtp_tls field.
zeroclaw config
zeroclaw config set channels.email.<alias>.smtp_tls <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__smtp_tls=
smtp_username
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.smtp_username field.
zerocode
In the Config pane, set the channels.email.<alias>.smtp_username field.
zeroclaw config
zeroclaw config set channels.email.<alias>.smtp_username <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__smtp_username=
username*
Set it on any surface:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.username field.
zerocode
In the Config pane, set the channels.email.<alias>.username field.
zeroclaw config
zeroclaw config set channels.email.<alias>.username <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__email__<alias>__username=
password (and smtp_password if you use a separate relay) are secrets:
channels.email.<alias>.passwordis a secret. Stored encrypted, never in plainconfig.toml. Set it through one of these, which encrypt on write:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.password field there.
zerocode
In the Config pane, set the channels.email.<alias>.password field (input is masked).
zeroclaw config
zeroclaw config set channels.email.<alias>.password # prompts for masked input, stores encrypted
Inbound-only mode (no SMTP)
imap_host is the only transport endpoint required. Leave smtp_host and
from_address unset (or blank) to give the agent read-write access to the
mailbox without the ability to send email:
- When the alias is bound to an agent, IMAP still runs: new mail is delivered to
the agent and read/flag updates are written unless
observer_mode = true. - Every outbound send from this channel is refused with an
outbound email is disablederror, so agent replies fail rather than leaving the mailbox. Surfaces that require real delivery (SOP approval routes, no-reply notices, escalations, text polls) treat the channel as unable to deliver and reject or skip it up front. - Set both
smtp_hostandfrom_addressto enable sending again; either one alone keeps the channel inbound-only and raises anemail_smtp_partially_configuredconfig warning naming the missing field.
The restriction is outbound-only. Pair it with a peer group (above) to control
who may address the agent, and with observer_mode if the mailbox must not be
mutated at all.
Tools-only: enable it, don’t bind it
To use an IMAP mailbox as a pull-only tool, set enabled = true on the alias and
leave it out of every agent’s channels list and out of every approval route
that would name it. Enabling the alias registers the email_search and
email_read tools. Binding it to an agent is one way to start the IMAP listener;
an SOP approval request_route / escalation_route, or an enabled agent’s risk-
profile approver_channel, also starts it. A route may name the bare channel type
email; when exactly one email alias is enabled, that resolves to the alias. An
alias that only an approval route names stays live so approval replies can be
delivered, but it is not assigned to an agent for ordinary traffic.
The distinction matters for aliases with no SMTP configured (no smtp_host or
from_address), which are inbound-only: they can receive mail, but send refuses
to reply. If you bind such an alias, every inbound message from a sender your peer
group admits dispatches an agent turn. The agent tries to reply, send refuses,
and the reply fails, so you pay for a model turn on every email and get nothing
back.
[channels.email.myserver]
enabled = true # registers the read-only tools
imap_host = "imap.example.com"
username = "user"
password = "..." # leave smtp_host / from_address unset
[agents.example]
channels = ["telegram.home"] # any bound channel; email alias deliberately absent
Watch out for the fallback. The alias is only left unbound when at least one agent,
anywhere in the config, declares a non-empty channels list. If no agent declares
any bindings, ZeroClaw falls back to the legacy behavior: it starts every enabled
channel under the default agent (the agent named default, otherwise the first
alphabetically). In an email-only config, that means the IMAP listener starts anyway
and you pay the per-email turn cost described above. To keep the alias tools-only,
make sure some agent binds at least one other channel, as in the example where
agents.example binds telegram.home, and also leave the alias out of SOP
approval request_route / escalation_route values and every enabled agent’s
risk-profile approver_channel (including a bare email route when only one
email alias is enabled).
Gmail gotchas
- App passwords required if 2FA is on. Regular account password is rejected.
- “Less secure app access” is gone: app password is the only path.
- Consider the Gmail Push channel below for real-time delivery instead of polling.
Outlook / Office 365
password (and smtp_password) are secrets:
channels.email.<alias>.passwordis a secret. Stored encrypted, never in plainconfig.toml. Set it through one of these, which encrypt on write:
Gateway dashboard
Open /config/channels/email and set the channels.email.<alias>.password field there.
zerocode
In the Config pane, set the channels.email.<alias>.password field (input is masked).
zeroclaw config
zeroclaw config set channels.email.<alias>.password # prompts for masked input, stores encrypted
Gmail Push (gmail_push)
Real-time delivery via Google Cloud Pub/Sub, no polling.
excluded_tools
Tools excluded from this channel’s tool spec. When set, these tools are not exposed to the model when responding via this channel.
Set it on any surface:
Gateway dashboard
Open /config/channels/gmail_push and set the channels.gmail_push.<alias>.excluded_tools field.
zerocode
In the Config pane, set the channels.gmail_push.<alias>.excluded_tools field.
zeroclaw config
zeroclaw config set channels.gmail_push.<alias>.excluded_tools <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__gmail_push__<alias>__excluded_tools=
label_filter
Set it on any surface:
Gateway dashboard
Open /config/channels/gmail_push and set the channels.gmail_push.<alias>.label_filter field.
zerocode
In the Config pane, set the channels.gmail_push.<alias>.label_filter field.
zeroclaw config
zeroclaw config set channels.gmail_push.<alias>.label_filter <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__gmail_push__<alias>__label_filter=
oauth_token
Set it on any surface:
Gateway dashboard
Open /config/channels/gmail_push and set the channels.gmail_push.<alias>.oauth_token field.
zerocode
In the Config pane, set the channels.gmail_push.<alias>.oauth_token field.
zeroclaw config
zeroclaw config set channels.gmail_push.<alias>.oauth_token <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__gmail_push__<alias>__oauth_token=
topic*
Set it on any surface:
Gateway dashboard
Open /config/channels/gmail_push and set the channels.gmail_push.<alias>.topic field.
zerocode
In the Config pane, set the channels.gmail_push.<alias>.topic field.
zeroclaw config
zeroclaw config set channels.gmail_push.<alias>.topic <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__gmail_push__<alias>__topic=
webhook_secret
Set it on any surface:
Gateway dashboard
Open /config/channels/gmail_push and set the channels.gmail_push.<alias>.webhook_secret field.
zerocode
In the Config pane, set the channels.gmail_push.<alias>.webhook_secret field.
zeroclaw config
zeroclaw config set channels.gmail_push.<alias>.webhook_secret <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__gmail_push__<alias>__webhook_secret=
webhook_url
Set it on any surface:
Gateway dashboard
Open /config/channels/gmail_push and set the channels.gmail_push.<alias>.webhook_url field.
zerocode
In the Config pane, set the channels.gmail_push.<alias>.webhook_url field.
zeroclaw config
zeroclaw config set channels.gmail_push.<alias>.webhook_url <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__gmail_push__<alias>__webhook_url=
oauth_token and webhook_secret are secrets:
channels.gmail_push.<alias>.oauth_tokenis a secret. Stored encrypted, never in plainconfig.toml. Set it through one of these, which encrypt on write:
Gateway dashboard
Open /config/channels/gmail_push and set the channels.gmail_push.<alias>.oauth_token field there.
zerocode
In the Config pane, set the channels.gmail_push.<alias>.oauth_token field (input is masked).
zeroclaw config
zeroclaw config set channels.gmail_push.<alias>.oauth_token # prompts for masked input, stores encrypted
Setup
- Create a Google Cloud project, enable Gmail API and Pub/Sub API
- Create a Pub/Sub topic the Gmail service can publish to, set it as
topic - Authorize the agent’s Gmail access and store the resulting token via the secret path above
- The agent watches for new-mail notifications and routes them to the bound agent
Gmail Push sends through the Gmail API using its own oauth_token, independently
of SMTP. Omitting smtp_host and from_address disables sending only for an
IMAP+SMTP [channels.email.<alias>] block, not for Gmail Push.
Reply threading
Both email channels thread replies using In-Reply-To and References headers so conversations stay grouped in whatever client the sender uses.
Outbound body format
Agent replies are sent as multipart/alternative with both a plain-text and an HTML part by default. The HTML part is the Markdown-rendered body; the plain-text part is the raw body text. Mail clients that prefer plain text will select the plain-text alternative automatically.
To send plain text only (no HTML part, for clients or setups that prefer it), set the channel’s html_body field to false.
When attachments are present the body alternatives are wrapped in an outer multipart/mixed.
Attachment handling
Inbound attachments are stored under <workspace>/attachments/<conversation>/. The agent gets file paths in its context and can read them via the file_read tool. Filenames are taken from the Content-Disposition header first, falling back to the Content-Type name parameter.
Outbound attachments are sent from the bytes supplied with each attachment. The Email channel treats the attachment filename as display metadata, not as a local path. Integrations that intentionally send a local file must validate or constrain the path and load it explicitly with MediaAttachment::from_file before sending.
Rate and volume limits
Email isn’t optimised for conversational latency. Expect:
- IMAP poll latency:
poll_interval_secs(default 60 s). Lower at the cost of server load; some providers rate-limit aggressive polling. - SMTP send: subject to your provider’s daily-send quota (Gmail: 500/day for free accounts, 2000/day for Workspace).
Safety
Email has no auth at the protocol level beyond SMTP’s envelope; anyone can claim to be anyone. Gate inbound senders with a peer group (above) before exposing the agent to an inbox that receives public mail.