Email IMAP Fetch
Core Goal
- Wait for new mail with IMAP IDLE.
- Fetch unread messages after each wake-up.
- Support multiple mailbox accounts configured with env.
- Control IDLE support strictly with env mode (
idle or poll) without runtime probing.
- Forward each fetched email to OpenClaw webhooks.
- Emit machine-readable JSON lines for downstream steps.
- Keep this skill strictly in stage-1 routing mode: send snippet + structured refs only, never send full raw message body, and never send attachment binary/content.
Workflow
- Configure account env variables and OpenClaw webhook env variables (see
references/env.md and assets/config.example.env).
- Validate configuration:
python3 scripts/imap_idle_fetch.py check-config
- Run one IDLE cycle per account (smoke test):
python3 scripts/imap_idle_fetch.py listen --cycles 1 --idle-seconds 120 --max-messages 10
- Run continuously (default resident mode):
python3 scripts/imap_idle_fetch.py listen
Runtime Model
- Skill files are installed locally, but the listener is not auto-started.
- In
idle mode, IMAP IDLE receives push events only while listener process and IMAP connection are alive.
- In
poll mode, listener sleeps for poll interval and then fetches unread messages.
- If the process exits, push events are missed; next run can still fetch existing unread emails with
UNSEEN.
- Default runtime is resident mode (
IMAP_CYCLES=0 by default).
- Default IDLE mode is
poll (safe for servers without IDLE support).
- In production, always-on deployment must run under
systemd, launchd, supervisor, or an equivalent daemon manager.
- Do not run the listener as a foreground process bound to an interactive exec session; once that session exits, the listener will stop.
Output Contract
- Output format is JSONL (one JSON object per line).
type=status for lifecycle events.
type=message for fetched emails with:
account, mailbox, seq, uid
subject, from, to, date
message_id_raw, message_id_norm (and compatibility field message_id)
snippet (plain-text preview only)
attachment_count, attachment_manifest (summary only, no attachment content)
mail_ref machine-readable object (account, mailbox, uid, message_id_raw, message_id_norm, date)
- Webhook message includes two fixed machine-readable blocks for deterministic dispatch extraction:
<<<MAIL_REF_JSON>>> ... <<<END_MAIL_REF_JSON>>>
<<<ATTACHMENT_MANIFEST_JSON>>> ... <<<END_ATTACHMENT_MANIFEST_JSON>>>
wait_mode is idle or poll in cycle status output.
wait_events records the active wait strategy details.
event=webhook_delivered status events when OpenClaw webhook POST succeeds.
type=error for account-level failures.
event=webhook_failed error events when OpenClaw webhook POST fails.
Parameters
--cycles: IDLE cycles per account (0 means forever).
--idle-seconds: max wait time for each IDLE call.
--poll-seconds: interval used when polling mode is active.
--idle-mode: idle or poll.
--max-messages: max unread emails fetched each cycle.
--mark-seen / --no-mark-seen: control unread state updates.
--snippet-chars: preview length limit.
--connect-timeout: connection timeout seconds.
--retry-seconds: retry delay after failure.
Environment defaults:
IMAP_CYCLES
IMAP_IDLE_MODE
IMAP_IDLE_SECONDS
IMAP_POLL_SECONDS
IMAP_MAX_MESSAGES
IMAP_MARK_SEEN
IMAP_SNIPPET_CHARS
IMAP_CONNECT_TIMEOUT
IMAP_RETRY_SECONDS
OpenClaw webhooks forwarding:
OPENCLAW_WEBHOOKS_ENABLED
OPENCLAW_WEBHOOKS_TOKEN
OPENCLAW_WEBHOOKS_BASE_URL
OPENCLAW_WEBHOOKS_MODE (agent or wake)
OPENCLAW_WEBHOOKS_ENDPOINT (optional endpoint override)
OPENCLAW_WEBHOOKS_PATH
OPENCLAW_WEBHOOKS_WAKE_MODE
OPENCLAW_WEBHOOKS_DELIVER
OPENCLAW_WEBHOOKS_TIMEOUT
OPENCLAW_WEBHOOKS_NAME
OPENCLAW_WEBHOOKS_AGENT_ID
OPENCLAW_WEBHOOKS_CHANNEL
OPENCLAW_WEBHOOKS_TO
OPENCLAW_WEBHOOKS_MODEL
OPENCLAW_WEBHOOKS_THINKING
OPENCLAW_WEBHOOKS_AGENT_TIMEOUT_SECONDS
OPENCLAW_WEBHOOKS_SESSION_KEY_PREFIX
Error Handling
- Invalid env configuration exits with code
2.
- In
idle mode, unsupported IDLE returns explicit error and suggests IMAP_IDLE_MODE=poll.
- Runtime failures are emitted as
type=error.
- Command exits non-zero when account processing errors occur.
References
Assets
assets/config.example.env
Scripts
scripts/imap_idle_fetch.py
1---2name: email-imap-fetch3description: Listen for one or more IMAP inboxes with the IDLE command, fetch unread email metadata plus text previews, and forward each message to OpenClaw webhooks. Use when tasks need near-real-time mailbox monitoring, multi-account inbox ingestion via environment variables, and automatic trigger delivery into OpenClaw automation.4---5
6# Email IMAP Fetch
7
8## Core Goal
9- Wait for new mail with IMAP IDLE.
10- Fetch unread messages after each wake-up.
11- Support multiple mailbox accounts configured with env.
12- Control IDLE support strictly with env mode (`idle` or `poll`) without runtime probing.
13- Forward each fetched email to OpenClaw webhooks.
14- Emit machine-readable JSON lines for downstream steps.
15- Keep this skill strictly in stage-1 routing mode: send snippet + structured refs only, never send full raw message body, and never send attachment binary/content.
16
17## Workflow
181. Configure account env variables and OpenClaw webhook env variables (see `references/env.md` and `assets/config.example.env`).
192. Validate configuration:
20
21```bash
22python3 scripts/imap_idle_fetch.py check-config
23```
24
253. Run one IDLE cycle per account (smoke test):
26
27```bash
28python3 scripts/imap_idle_fetch.py listen --cycles 1 --idle-seconds 120 --max-messages 10
29```
30
314. Run continuously (default resident mode):
32
33```bash
34python3 scripts/imap_idle_fetch.py listen
35```
36
37## Runtime Model
38- Skill files are installed locally, but the listener is not auto-started.
39- In `idle` mode, IMAP IDLE receives push events only while listener process and IMAP connection are alive.
40- In `poll` mode, listener sleeps for poll interval and then fetches unread messages.
41- If the process exits, push events are missed; next run can still fetch existing unread emails with `UNSEEN`.
42- Default runtime is resident mode (`IMAP_CYCLES=0` by default).
43- Default IDLE mode is `poll` (safe for servers without IDLE support).
44- In production, always-on deployment must run under `systemd`, `launchd`, `supervisor`, or an equivalent daemon manager.
45- Do not run the listener as a foreground process bound to an interactive exec session; once that session exits, the listener will stop.
46
47## Output Contract
48- Output format is JSONL (one JSON object per line).
49- `type=status` for lifecycle events.
50- `type=message` for fetched emails with:
51 - `account`, `mailbox`, `seq`, `uid`
52 - `subject`, `from`, `to`, `date`
53 - `message_id_raw`, `message_id_norm` (and compatibility field `message_id`)
54 - `snippet` (plain-text preview only)
55 - `attachment_count`, `attachment_manifest` (summary only, no attachment content)
56 - `mail_ref` machine-readable object (`account`, `mailbox`, `uid`, `message_id_raw`, `message_id_norm`, `date`)
57- Webhook message includes two fixed machine-readable blocks for deterministic dispatch extraction:
58 - `<<<MAIL_REF_JSON>>> ... <<<END_MAIL_REF_JSON>>>`
59 - `<<<ATTACHMENT_MANIFEST_JSON>>> ... <<<END_ATTACHMENT_MANIFEST_JSON>>>`
60- `wait_mode` is `idle` or `poll` in cycle status output.
61- `wait_events` records the active wait strategy details.
62- `event=webhook_delivered` status events when OpenClaw webhook POST succeeds.
63- `type=error` for account-level failures.
64- `event=webhook_failed` error events when OpenClaw webhook POST fails.
65
66## Parameters
67- `--cycles`: IDLE cycles per account (`0` means forever).
68- `--idle-seconds`: max wait time for each IDLE call.
69- `--poll-seconds`: interval used when polling mode is active.
70- `--idle-mode`: `idle` or `poll`.
71- `--max-messages`: max unread emails fetched each cycle.
72- `--mark-seen` / `--no-mark-seen`: control unread state updates.
73- `--snippet-chars`: preview length limit.
74- `--connect-timeout`: connection timeout seconds.
75- `--retry-seconds`: retry delay after failure.
76
77Environment defaults:
78- `IMAP_CYCLES`
79- `IMAP_IDLE_MODE`
80- `IMAP_IDLE_SECONDS`
81- `IMAP_POLL_SECONDS`
82- `IMAP_MAX_MESSAGES`
83- `IMAP_MARK_SEEN`
84- `IMAP_SNIPPET_CHARS`
85- `IMAP_CONNECT_TIMEOUT`
86- `IMAP_RETRY_SECONDS`
87
88OpenClaw webhooks forwarding:
89- `OPENCLAW_WEBHOOKS_ENABLED`
90- `OPENCLAW_WEBHOOKS_TOKEN`
91- `OPENCLAW_WEBHOOKS_BASE_URL`
92- `OPENCLAW_WEBHOOKS_MODE` (`agent` or `wake`)
93- `OPENCLAW_WEBHOOKS_ENDPOINT` (optional endpoint override)
94- `OPENCLAW_WEBHOOKS_PATH`
95- `OPENCLAW_WEBHOOKS_WAKE_MODE`
96- `OPENCLAW_WEBHOOKS_DELIVER`
97- `OPENCLAW_WEBHOOKS_TIMEOUT`
98- `OPENCLAW_WEBHOOKS_NAME`
99- `OPENCLAW_WEBHOOKS_AGENT_ID`
100- `OPENCLAW_WEBHOOKS_CHANNEL`
101- `OPENCLAW_WEBHOOKS_TO`
102- `OPENCLAW_WEBHOOKS_MODEL`
103- `OPENCLAW_WEBHOOKS_THINKING`
104- `OPENCLAW_WEBHOOKS_AGENT_TIMEOUT_SECONDS`
105- `OPENCLAW_WEBHOOKS_SESSION_KEY_PREFIX`
106
107## Error Handling
108- Invalid env configuration exits with code `2`.
109- In `idle` mode, unsupported IDLE returns explicit error and suggests `IMAP_IDLE_MODE=poll`.
110- Runtime failures are emitted as `type=error`.
111- Command exits non-zero when account processing errors occur.
112
113## References
114- `references/env.md`
115
116## Assets
117- `assets/config.example.env`
118
119## Scripts
120- `scripts/imap_idle_fetch.py`