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 (
idleorpoll) 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.mdandassets/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
idlemode, IMAP IDLE receives push events only while listener process and IMAP connection are alive. - In
pollmode, 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=0by 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=statusfor lifecycle events.type=messagefor fetched emails with:account,mailbox,seq,uidsubject,from,to,datemessage_id_raw,message_id_norm(and compatibility fieldmessage_id)snippet(plain-text preview only)attachment_count,attachment_manifest(summary only, no attachment content)mail_refmachine-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_modeisidleorpollin cycle status output.wait_eventsrecords the active wait strategy details.event=webhook_deliveredstatus events when OpenClaw webhook POST succeeds.type=errorfor account-level failures.event=webhook_failederror events when OpenClaw webhook POST fails.
Parameters
--cycles: IDLE cycles per account (0means forever).--idle-seconds: max wait time for each IDLE call.--poll-seconds: interval used when polling mode is active.--idle-mode:idleorpoll.--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_CYCLESIMAP_IDLE_MODEIMAP_IDLE_SECONDSIMAP_POLL_SECONDSIMAP_MAX_MESSAGESIMAP_MARK_SEENIMAP_SNIPPET_CHARSIMAP_CONNECT_TIMEOUTIMAP_RETRY_SECONDS
OpenClaw webhooks forwarding:
OPENCLAW_WEBHOOKS_ENABLEDOPENCLAW_WEBHOOKS_TOKENOPENCLAW_WEBHOOKS_BASE_URLOPENCLAW_WEBHOOKS_MODE(agentorwake)OPENCLAW_WEBHOOKS_ENDPOINT(optional endpoint override)OPENCLAW_WEBHOOKS_PATHOPENCLAW_WEBHOOKS_WAKE_MODEOPENCLAW_WEBHOOKS_DELIVEROPENCLAW_WEBHOOKS_TIMEOUTOPENCLAW_WEBHOOKS_NAMEOPENCLAW_WEBHOOKS_AGENT_IDOPENCLAW_WEBHOOKS_CHANNELOPENCLAW_WEBHOOKS_TOOPENCLAW_WEBHOOKS_MODELOPENCLAW_WEBHOOKS_THINKINGOPENCLAW_WEBHOOKS_AGENT_TIMEOUT_SECONDSOPENCLAW_WEBHOOKS_SESSION_KEY_PREFIX
Error Handling
- Invalid env configuration exits with code
2. - In
idlemode, unsupported IDLE returns explicit error and suggestsIMAP_IDLE_MODE=poll. - Runtime failures are emitted as
type=error. - Command exits non-zero when account processing errors occur.
References
references/env.md
Assets
assets/config.example.env
Scripts
scripts/imap_idle_fetch.py