# Email-OpenClaw Bridge v1 Design (KISS) ## 1) Scope & Non-goals ### Scope v1 - IMAP ingest -> OpenClaw dispatch -> callback -> SMTP reply. - Stateful processing with SQLite. - Thread handling via `thread_id`. - Idempotency by `message_id`. - Health endpoints: - `GET /healthz` (liveness) - `GET /readyz` (readiness) - Retry mechanism: - OpenClaw dispatch retries: 3 attempts with backoff 1s, 5s, 15s. - SMTP send retries: 3 attempts with backoff 1s, 5s, 15s. ### Non-goals v1 - No rate limiting. - No DLQ / reprocess UI. - No advanced metrics stack. ## 2) State Machine & Schema ### Task states - `IGNORED` - `RECEIVED` - `AI_PROCESSING` - `CALLBACK_DONE` - `SMTP_RETRYING` - `COMPLETED` - `FAILED` ### Retry rules - OpenClaw dispatch failure: retry 3 times (1s, 5s, 15s). Exhausted retries -> `FAILED`. - SMTP send failure: transition to `SMTP_RETRYING`, retry 3 times (1s, 5s, 15s). Exhausted retries -> `FAILED`. - Persist final failure reason in `last_error`. ### SQLite schema updates (`tasks`) - `attempt_openclaw INTEGER DEFAULT 0` - `attempt_smtp INTEGER DEFAULT 0` - `last_error TEXT NULL` - `next_retry_at DATETIME NULL` (used only if retry scheduling is asynchronous) ## 3) API Contracts & Security ### OpenClaw callback contract Required fields: - `metadata.task_uuid` - `result` (text) - `status` ### Webhook authentication (KISS) - Bridge requires header `X-Bridge-Token` on callback requests. - Expected secret is configured in `.env` (e.g., `BRIDGE_CALLBACK_TOKEN`). - Missing/invalid token -> `401 Unauthorized`. ### Callback idempotency - If task already in `COMPLETED`, callback handler returns `200` and skips updates. ### Health endpoints behavior - `GET /healthz` -> `200 {"status":"ok"}` when process is alive. - `GET /readyz` checks: - DB writable - required config present (IMAP/SMTP/OpenClaw/token) - Returns `503` on any failed check. ## 4) Acceptance Criteria 1. Valid incoming email eventually reaches `COMPLETED` and reply preserves email thread headers. 2. OpenClaw/SMTP transient failures retry with exact backoff sequence 1s, 5s, 15s. 3. Exhausted retries result in `FAILED` with `last_error` populated. 4. Anti-loop, whitelist, and idempotency behavior work as defined. ## 5) Test Matrix (v1) 1. Happy path: new mail -> valid callback -> SMTP success -> `COMPLETED`. 2. OpenClaw fails twice then succeeds -> `COMPLETED`, `attempt_openclaw=3`. 3. SMTP fails all retries -> `FAILED`, `last_error` present. 4. Callback with invalid token -> `401`, no task state change. 5. Duplicate `message_id` -> no new task created. 6. System sender or non-whitelisted sender -> `IGNORED`. ## 6) Logging (minimum) Structured logs must include: - `task_uuid` - `thread_id` - `message_id` - `status` - `attempt` - `error` (when present)