Files
claw-email/checkpoints/002-imap-ingress.md
T
thuanleandClaude Opus 4.7 8815c20c13 Initial commit: email-openclaw bridge v1
Full pipeline: IMAP ingress -> OpenClaw dispatch -> callback -> SMTP reply.
SQLite stateful storage with idempotency, threading, and retry logic.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-27 18:16:57 +07:00

83 lines
3.0 KiB
Markdown

# Checkpoint 002 — IMAP Ingress
**Ngày:** 2026-04-24
**Trạng thái:** ✅ Hoàn thành
**Verify:** `go build ./...` thành công
---
## Việc đã làm
### 1. Task Repository (`internal/database/repository.go`)
Thêm các helper function cho CRUD operations:
- `FindByMessageID` — lookup cho idempotency check
- `FindLatestByThreadID` — tìm task COMPLETED gần nhất trong thread
- `FindByTaskUUID` — lookup cho callback handler
- `ThreadHistory` — lấy toàn bộ history thread (cho OpenClaw context)
- `CreateTask`, `UpdateTask` — CRUD cơ bản
### 2. IMAP Watcher (`internal/mail/imap.go`)
Module chính cho Ingress, bao gồm:
**Kết nối & IDLE:**
- `DialTLS` → Login → Select INBOX
- IDLE loop với timer 28 phút (RFC recommends < 29 min)
- Auto-reconnect sau 10s khi mất kết nối
- Graceful shutdown qua `context.Context`
- `UnilateralDataHandler` nhận notification khi có email mới
**Xử lý email (đúng 5 bước theo requirements 4.1):**
1. **Anti-loop**: sender == `SYSTEM_EMAIL``IGNORED`
2. **Whitelist**: sender không trong danh sách → `IGNORED` (empty whitelist = cho phép tất cả)
3. **Idempotency**: `message_id` đã tồn tại → skip
4. **Threading**: parse `In-Reply-To` header → tìm parent task → kế thừa `thread_id`
5. **Save**: tạo task `status = RECEIVED`
**Extras:**
- Fetch UNSEEN messages on startup (xử lý email đến trong lúc offline)
- Mark `\Seen` sau khi xử lý xong
- Lưu task IGNORED vào DB cho audit
- Parse body parts qua `go-message` để lấy plain text
- Hook `OnReceived` cho dispatch (chưa wire)
### 3. Entrypoint (`cmd/bridge/main.go`)
- Chạy IMAP watcher + HTTP server concurrently
- Graceful shutdown qua SIGINT/SIGTERM
- `sync.WaitGroup` đợi cả hai goroutine
---
## Dependencies mới
```
github.com/emersion/go-imap/v2 v2.0.0-beta.8
github.com/emersion/go-message v0.18.2
github.com/google/uuid (for task_uuid generation)
```
## Quyết định thiết kế
| Quyết định | Lý do |
|---|---|
| go-imap v2 thay vì v1 | IDLE tích hợp sẵn, API hiện đại hơn, dự án mới nên dùng v2 |
| IDLE timer 28 min | RFC recommends < 29 min, close + reopen IDLE để tránh server timeout |
| Fetch UNSEEN on startup | Xử lý email đến lúc bridge offline |
| Empty whitelist = allow all | UX tốt hơn: không cấu hình whitelist thì mặc định chấp nhận mọi sender |
| Lưu IGNORED vào DB | Auditability: biết email nào bị bỏ qua và lý do |
| `UnilateralDataHandler` | Nhận notification realtime khi mailbox thay đổi (không cần polling) |
---
## Files thay đổi
- **Mới:** `internal/database/repository.go`
- **Mới:** `internal/mail/imap.go`
- **Cập nhật:** `cmd/bridge/main.go` (IMAP watcher + graceful shutdown)
- **Xóa:** `internal/mail/mail.go` (stub cũ)
## Tiếp theo
1. **OpenClaw Dispatch** — wire `OnReceived` → HTTP POST to OpenClaw
2. **Callback handler**`POST /callback` + token auth
3. **SMTP Egress** — gửi reply với In-Reply-To/References