Files
claw-email/requirements.md
thuanleandClaude Opus 4.7 c127018bc9
CI / fmt (pull_request) Failing after 4m45s
CI / test (pull_request) Successful in 10m47s
fix: add dispatch_context to schema docs and test buildDispatchMetadata
- Add dispatch_context column to requirements.md task schema section
- Export buildDispatchMetadata for test coverage
- Add tests: context forwarding, task_uuid overwrite protection, empty context

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 07:08:19 +07:00

6.3 KiB

PROJECT: EMAIL-OPENCLAW BRIDGE (STATEFUL, KISS)

  1. Mục tiêu & phạm vi

Mục tiêu hệ thống:

  • Tự động xử lý email bằng OpenClaw theo luồng: Ingress (IMAP) -> Dispatch (OpenClaw) -> Callback -> Egress (SMTP reply).

Phạm vi v1:

  • Stateful bằng SQLite.
  • Hỗ trợ email thread theo thread_id.
  • Idempotency theo message_id.
  • Webhook callback có xác thực bằng token đơn giản.
  • Bổ sung health endpoints:
    • GET /healthz (liveness)
    • GET /readyz (readiness)
  • Retry cơ bản (KISS) cho OpenClaw và SMTP:
    • Tối đa 3 lần với backoff: 1s, 5s, 15s.

Non-goals v1:

  • Không rate limit.
  • Không DLQ/reprocess UI.
  • Không stack metrics nâng cao.
  1. Công nghệ yêu cầu
  • Ngôn ngữ: Go.
  • Database: SQLite.
    • Khuyến nghị: gorm.io/gorm + modernc.org/sqlite (không cần CGO khi build Docker).
  • IMAP: github.com/emersion/go-imap (+ IDLE).
  • SMTP: net/smtp hoặc thư viện gửi mail Go tương đương.
  • HTTP/Webhook: gin-gonic/gin hoặc gofiber/fiber.
  • Proxy IMAP (optional): golang.org/x/net/proxy.
  • Triển khai: Docker + Docker Compose.
  1. Database schema

Bảng tasks:

  • id INTEGER PRIMARY KEY AUTOINCREMENT
  • task_uuid TEXT UNIQUE
  • thread_id TEXT
  • message_id TEXT
  • sender TEXT
  • subject TEXT
  • body_plain TEXT
  • ai_response TEXT
  • status TEXT
  • attempt_openclaw INTEGER DEFAULT 0
  • attempt_smtp INTEGER DEFAULT 0
  • dispatch_context TEXT (JSON metadata từ external rules pipeline, truyền qua OpenClaw dispatch)
  • last_error TEXT NULL
  • next_retry_at DATETIME NULL (chỉ cần nếu retry xử lý theo scheduler/worker)
  • created_at DATETIME
  • updated_at DATETIME

Danh sách trạng thái hợp lệ:

  • IGNORED
  • RECEIVED
  • AI_PROCESSING
  • CALLBACK_DONE
  • SMTP_RETRYING
  • COMPLETED
  • FAILED
  1. Luồng xử lý chi tiết

4.1 Ingress (IMAP)

  • Theo dõi mailbox qua IMAP IDLE.
  • Nếu có IMAP_PROXY_URL thì kết nối IMAP qua proxy; nếu không thì direct.
  • Khi có email mới:
    1. Anti-loop: nếu sender trùng email hệ thống -> IGNORED.
    2. Idempotency: nếu message_id đã tồn tại -> bỏ qua.
    3. External rules: chạy pipeline các rule configurable (whitelist, blocklist, v.v.). Nếu reject -> IGNORED. Rule metadata được lưu vào dispatch_context.
    4. Threading:
      • Nếu có In-Reply-To/References: tìm email cha trong DB, kế thừa thread_id.
      • Nếu không có: thread_id = message_id.
    5. Lưu DB với status = RECEIVED, bao gồm dispatch_context từ rules.

4.2 Dispatch (OpenClaw)

  • Lấy nội dung email hiện tại và history của cùng thread_id (chỉ các bản ghi COMPLETED).
  • Gọi OpenClaw API bằng HTTP client đi direct (không kế thừa proxy hệ thống).
  • Payload tối thiểu:
    • input
    • session_id = thread_id
    • history (optional)
    • callback_url
    • metadata.task_uuid
    • metadata.* từ dispatch_context (rule-derived context)
  • Cập nhật status = AI_PROCESSING.

Retry OpenClaw:

  • Khi lỗi tạm thời: retry tối đa 3 lần theo backoff 1s, 5s, 15s.
  • Mỗi lần retry tăng attempt_openclaw.
  • Hết retry: status = FAILED, ghi last_error.

4.3 Callback + Egress (SMTP)

  • Webhook nhận callback từ OpenClaw.
  • Tìm task theo metadata.task_uuid.
  • Nếu task đã COMPLETED: trả 200 và không cập nhật gì thêm (idempotent callback).
  • Nếu hợp lệ: cập nhật ai_response, status = CALLBACK_DONE.

Gửi email phản hồi:

  • Subject/Body theo kết quả AI.
  • Bắt buộc set In-Reply-ToReferences khớp message liên quan để giữ thread phía người nhận.

Retry SMTP:

  • Nếu lỗi tạm thời: chuyển SMTP_RETRYING, retry 3 lần theo 1s, 5s, 15s.
  • Mỗi lần retry tăng attempt_smtp.
  • Hết retry: status = FAILED, ghi last_error.
  • Thành công: status = COMPLETED.
  1. API contract & bảo mật

5.1 Callback contract (từ OpenClaw) Required:

  • metadata.task_uuid
  • result (text)
  • status

5.2 Xác thực webhook (KISS)

  • Yêu cầu header: X-Bridge-Token.
  • Giá trị kỳ vọng lấy từ .env, ví dụ: BRIDGE_CALLBACK_TOKEN.
  • Thiếu/sai token -> trả 401 Unauthorized.

5.3 Health endpoints

  • GET /healthz -> 200 {"status":"ok"} nếu process sống.
  • GET /readyz:
    • kiểm tra DB writable,
    • kiểm tra cấu hình bắt buộc có đủ (IMAP/SMTP/OpenClaw/token),
    • nếu lỗi bất kỳ check nào -> 503.
  1. Logging & observability (mức tối thiểu)
  • Structured logging ra stdout.
  • Mỗi log liên quan xử lý email phải có:
    • task_uuid
    • thread_id
    • message_id
    • status
    • attempt
    • error (nếu có)
  1. Cấu hình môi trường

Đọc từ .env:

  • IMAP_HOST, IMAP_PORT, IMAP_USER, IMAP_PASS
  • SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS
  • OPENCLAW_URL, OPENCLAW_API_KEY (nếu dùng)
  • BRIDGE_CALLBACK_TOKEN
  • WHITELIST_EMAILS (comma-separated)
  • BLOCKLIST_EMAILS (comma-separated, optional)
  • SYSTEM_EMAIL
  • IMAP_PROXY_URL (optional)

Ví dụ:

  • WHITELIST_EMAILS="user1@example.com,user2@example.com"
  • IMAP_PROXY_URL="socks5://user:pass@proxy-host:port"
  1. Docker triển khai
  • Multi-stage build để tối ưu image size.
  • docker-compose.yml mount volume cho SQLite DB (vd database.db).
  • Xem log bằng: docker logs -f <container_name>.
  1. Acceptance criteria (bắt buộc đạt)
  1. Email hợp lệ đi hết pipeline và kết thúc COMPLETED.
  2. Thread reply giữ đúng In-Reply-To/References.
  3. OpenClaw/SMTP retry đúng thứ tự 1s -> 5s -> 15s.
  4. Hết retry thì FAILED và có last_error.
  5. Callback sai token trả 401 và không đổi state task.
  6. Anti-loop + idempotency + external rules hoạt động đúng thứ tự.
  1. Test matrix tối thiểu
  1. Happy path: mail mới -> callback hợp lệ -> SMTP thành công -> COMPLETED.
  2. OpenClaw fail 2 lần, lần 3 thành công -> COMPLETED, attempt_openclaw = 3.
  3. SMTP fail hết retry -> FAILED, có last_error.
  4. Callback sai token -> 401, state không đổi.
  5. Duplicate message_id -> không tạo task mới.
  6. Sender là chính hệ thống -> IGNORED.
  7. Sender ngoài whitelist -> IGNORED bởi external rules.
  8. Sender trong blocklist -> IGNORED bởi external rules.
  9. Rule metadata được truyền qua dispatch context đến OpenClaw.