- Skip task_uuid key when merging DispatchContext into dispatch metadata - Update requirements.md acceptance criteria and test matrix for external rules Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
6.2 KiB
6.2 KiB
PROJECT: EMAIL-OPENCLAW BRIDGE (STATEFUL, KISS)
- 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.
- 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).
- Khuyến nghị:
- IMAP:
github.com/emersion/go-imap(+ IDLE). - SMTP:
net/smtphoặc thư viện gửi mail Go tương đương. - HTTP/Webhook:
gin-gonic/ginhoặcgofiber/fiber. - Proxy IMAP (optional):
golang.org/x/net/proxy. - Triển khai: Docker + Docker Compose.
- Database schema
Bảng tasks:
idINTEGER PRIMARY KEY AUTOINCREMENTtask_uuidTEXT UNIQUEthread_idTEXTmessage_idTEXTsenderTEXTsubjectTEXTbody_plainTEXTai_responseTEXTstatusTEXTattempt_openclawINTEGER DEFAULT 0attempt_smtpINTEGER DEFAULT 0last_errorTEXT NULLnext_retry_atDATETIME NULL (chỉ cần nếu retry xử lý theo scheduler/worker)created_atDATETIMEupdated_atDATETIME
Danh sách trạng thái hợp lệ:
IGNOREDRECEIVEDAI_PROCESSINGCALLBACK_DONESMTP_RETRYINGCOMPLETEDFAILED
- Luồng xử lý chi tiết
4.1 Ingress (IMAP)
- Theo dõi mailbox qua IMAP IDLE.
- Nếu có
IMAP_PROXY_URLthì kết nối IMAP qua proxy; nếu không thì direct. - Khi có email mới:
- Anti-loop: nếu
sendertrùng email hệ thống ->IGNORED. - Idempotency: nếu
message_idđã tồn tại -> bỏ qua. - External rules: chạy pipeline các rule configurable (whitelist, blocklist, v.v.). Nếu reject ->
IGNORED. Rule metadata được lưu vàodispatch_context. - Threading:
- Nếu có
In-Reply-To/References: tìm email cha trong DB, kế thừathread_id. - Nếu không có:
thread_id = message_id.
- Nếu có
- Lưu DB với
status = RECEIVED, bao gồmdispatch_contexttừ rules.
- Anti-loop: nếu
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 ghiCOMPLETED). - Gọi OpenClaw API bằng HTTP client đi direct (không kế thừa proxy hệ thống).
- Payload tối thiểu:
inputsession_id=thread_idhistory(optional)callback_urlmetadata.task_uuidmetadata.*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, ghilast_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-TovàReferenceskhớ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, ghilast_error. - Thành công:
status = COMPLETED.
- API contract & bảo mật
5.1 Callback contract (từ OpenClaw) Required:
metadata.task_uuidresult(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.
- 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_uuidthread_idmessage_idstatusattempterror(nếu có)
- Cấu hình môi trường
Đọc từ .env:
IMAP_HOST,IMAP_PORT,IMAP_USER,IMAP_PASSSMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASSOPENCLAW_URL,OPENCLAW_API_KEY(nếu dùng)BRIDGE_CALLBACK_TOKENWHITELIST_EMAILS(comma-separated)BLOCKLIST_EMAILS(comma-separated, optional)SYSTEM_EMAILIMAP_PROXY_URL(optional)
Ví dụ:
WHITELIST_EMAILS="user1@example.com,user2@example.com"IMAP_PROXY_URL="socks5://user:pass@proxy-host:port"
- Docker triển khai
- Multi-stage build để tối ưu image size.
docker-compose.ymlmount volume cho SQLite DB (vddatabase.db).- Xem log bằng:
docker logs -f <container_name>.
- Acceptance criteria (bắt buộc đạt)
- Email hợp lệ đi hết pipeline và kết thúc
COMPLETED. - Thread reply giữ đúng
In-Reply-To/References. - OpenClaw/SMTP retry đúng thứ tự 1s -> 5s -> 15s.
- Hết retry thì
FAILEDvà cólast_error. - Callback sai token trả 401 và không đổi state task.
- Anti-loop + idempotency + external rules hoạt động đúng thứ tự.
- Test matrix tối thiểu
- Happy path: mail mới -> callback hợp lệ -> SMTP thành công ->
COMPLETED. - OpenClaw fail 2 lần, lần 3 thành công ->
COMPLETED,attempt_openclaw = 3. - SMTP fail hết retry ->
FAILED, cólast_error. - Callback sai token -> 401, state không đổi.
- Duplicate
message_id-> không tạo task mới. - Sender là chính hệ thống ->
IGNORED. - Sender ngoài whitelist ->
IGNOREDbởi external rules. - Sender trong blocklist ->
IGNOREDbởi external rules. - Rule metadata được truyền qua dispatch context đến OpenClaw.