docs: reorganize README and technical overview #23
@@ -1,38 +1,26 @@
|
|||||||
# Email-OpenClaw Bridge
|
# Email-OpenClaw Bridge
|
||||||
|
|
||||||
Tự động xử lý email bằng OpenClaw AI theo luồng:
|
Bridge tự động xử lý email bằng OpenClaw AI theo luồng:
|
||||||
|
|
||||||
```
|
```text
|
||||||
Ingress (IMAP) → Safety Checks → External Rules → Apply Context → Dispatch (OpenClaw) → Callback → Egress (SMTP reply)
|
Ingress (IMAP) → Safety Checks → External Rules → Dispatch (OpenClaw) → Callback → Egress (SMTP reply)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tính năng
|
README này tập trung vào onboarding và vận hành cơ bản. Chi tiết kỹ thuật hiện hành được tách sang `docs/architecture/overview.md`.
|
||||||
|
|
||||||
- **IMAP IDLE** — theo dõi mailbox realtime, nhận email mới tức thì
|
## Tính năng chính
|
||||||
- **Threading** — giữ nguyên email thread qua `In-Reply-To` / `References`
|
|
||||||
- **Idempotency** — chống duplicate theo `message_id`
|
|
||||||
- **Anti-loop & Whitelist** — bỏ qua email từ chính hệ thống, chỉ xử lý sender được phép
|
|
||||||
- **External Rules** — pipeline configurable: whitelist, blocklist, và rule metadata cho dispatch
|
|
||||||
- **Retry** — tối đa 3 lần với backoff 1s → 5s → 15s cho cả OpenClaw và SMTP
|
|
||||||
- **Stateful** — SQLite lưu trạng thái pipeline, không mất dữ liệu khi restart
|
|
||||||
|
|
||||||
## Kiến trúc
|
- Theo dõi mailbox realtime bằng IMAP IDLE
|
||||||
|
- Giữ thread email qua `In-Reply-To` và `References`
|
||||||
|
- Chống duplicate theo `message_id`
|
||||||
|
- Chặn anti-loop và hỗ trợ whitelist/blocklist
|
||||||
|
- Gửi callback vào bridge rồi phản hồi lại qua SMTP
|
||||||
|
- Lưu trạng thái pipeline bằng SQLite để không mất tiến trình khi restart
|
||||||
|
|
||||||
```
|
## Yêu cầu tối thiểu
|
||||||
cmd/bridge/main.go Entrypoint
|
|
||||||
internal/
|
|
||||||
├── config/ Đọc cấu hình từ .env
|
|
||||||
├── database/ SQLite + GORM, auto-migrate
|
|
||||||
├── logging/ Structured JSON logging (slog)
|
|
||||||
├── api/ HTTP server (Gin): health checks, webhook callback
|
|
||||||
├── mail/ IMAP ingress + SMTP egress
|
|
||||||
└── ai_client/ OpenClaw HTTP dispatch
|
|
||||||
```
|
|
||||||
|
|
||||||
## Yêu cầu
|
|
||||||
|
|
||||||
- Go 1.23+
|
- Go 1.23+
|
||||||
- Docker & Docker Compose (cho deploy)
|
- Docker và Docker Compose nếu chạy bằng container
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
@@ -43,7 +31,7 @@ cp .env.example .env
|
|||||||
# Sửa .env với thông tin IMAP/SMTP/OpenClaw thực tế
|
# Sửa .env với thông tin IMAP/SMTP/OpenClaw thực tế
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Chạy local (development)
|
### 2. Chạy local
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go run ./cmd/bridge
|
go run ./cmd/bridge
|
||||||
@@ -56,51 +44,39 @@ docker compose up -d
|
|||||||
docker logs -f claw-email-bridge
|
docker logs -f claw-email-bridge
|
||||||
```
|
```
|
||||||
|
|
||||||
## Cấu hình (.env)
|
## Cấu hình `.env`
|
||||||
|
|
||||||
| Biến | Bắt buộc | Mô tả |
|
| Biến | Bắt buộc | Mô tả |
|
||||||
|---|:---:|---|
|
|---|:---:|---|
|
||||||
| `IMAP_HOST` | ✅ | IMAP server hostname |
|
| `IMAP_HOST` | ✅ | IMAP server hostname |
|
||||||
| `IMAP_PORT` | ✅ | IMAP port (thường `993`) |
|
| `IMAP_PORT` | ✅ | IMAP port, thường là `993` |
|
||||||
| `IMAP_USER` | ✅ | IMAP username |
|
| `IMAP_USER` | ✅ | IMAP username |
|
||||||
| `IMAP_PASS` | ✅ | IMAP password |
|
| `IMAP_PASS` | ✅ | IMAP password |
|
||||||
| `SMTP_HOST` | ✅ | SMTP server hostname |
|
| `SMTP_HOST` | ✅ | SMTP server hostname |
|
||||||
| `SMTP_PORT` | ✅ | SMTP port (thường `587`) |
|
| `SMTP_PORT` | ✅ | SMTP port, thường là `587` |
|
||||||
| `SMTP_USER` | ✅ | SMTP username |
|
| `SMTP_USER` | ✅ | SMTP username |
|
||||||
| `SMTP_PASS` | ✅ | SMTP password |
|
| `SMTP_PASS` | ✅ | SMTP password |
|
||||||
| `OPENCLAW_URL` | ✅ | OpenClaw API endpoint |
|
| `OPENCLAW_URL` | ✅ | OpenClaw API endpoint |
|
||||||
| `OPENCLAW_API_KEY` | | OpenClaw API key (nếu cần) |
|
| `OPENCLAW_API_KEY` | | OpenClaw API key nếu cần |
|
||||||
| `BRIDGE_CALLBACK_TOKEN` | ✅ | Token xác thực webhook callback |
|
| `BRIDGE_CALLBACK_TOKEN` | ✅ | Token xác thực webhook callback |
|
||||||
| `SYSTEM_EMAIL` | ✅ | Email của hệ thống (dùng cho anti-loop) |
|
| `SYSTEM_EMAIL` | ✅ | Email của bridge, dùng cho anti-loop |
|
||||||
| `WHITELIST_EMAILS` | | Danh sách email được phép, phân cách bằng dấu phẩy |
|
| `WHITELIST_EMAILS` | | Danh sách email được phép, phân cách bằng dấu phẩy |
|
||||||
| `IMAP_PROXY_URL` | | SOCKS5 proxy cho IMAP (vd: `socks5://user:pass@host:port`) |
|
| `BLOCKLIST_EMAILS` | | Danh sách email bị chặn, phân cách bằng dấu phẩy |
|
||||||
| `LISTEN_ADDR` | | Địa chỉ bind HTTP server cục bộ (mặc định `:8080`) |
|
| `IMAP_PROXY_URL` | | Proxy cho IMAP, hỗ trợ `socks5://`, `http://`, `https://` |
|
||||||
| `CALLBACK_BASE_URL` | | Base URL public để tạo `callback_url` gửi OpenClaw (mặc định theo `LISTEN_ADDR`, ví dụ `http://localhost:8080`) |
|
| `LISTEN_ADDR` | | Địa chỉ bind HTTP server, mặc định `:8080` |
|
||||||
|
| `CALLBACK_BASE_URL` | | Base URL public để tạo `callback_url`, mặc định suy ra từ `LISTEN_ADDR` |
|
||||||
|
|
||||||
## Health Checks
|
## Health checks
|
||||||
|
|
||||||
| Endpoint | Mục đích |
|
| Endpoint | Mục đích |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `GET /healthz` | Liveness — process còn sống |
|
| `GET /healthz` | Liveness check, xác nhận process còn sống |
|
||||||
| `GET /readyz` | Readiness — DB writable + config hợp lệ |
|
| `GET /readyz` | Readiness check, xác nhận DB writable và config bắt buộc hợp lệ |
|
||||||
|
|
||||||
## Pipeline trạng thái
|
## Đọc thêm
|
||||||
|
|
||||||
```
|
- [Technical overview](docs/architecture/overview.md)
|
||||||
RECEIVED → AI_PROCESSING → CALLBACK_DONE → COMPLETED
|
- [Architecture Decision Records](docs/adr/README.md)
|
||||||
↓ ↓ ↓
|
|
||||||
IGNORED FAILED SMTP_RETRYING → FAILED
|
|
||||||
```
|
|
||||||
|
|
||||||
## Công nghệ
|
|
||||||
|
|
||||||
| Thành phần | Thư viện |
|
|
||||||
|---|---|
|
|
||||||
| HTTP Server | [gin-gonic/gin](https://github.com/gin-gonic/gin) |
|
|
||||||
| Database | [GORM](https://gorm.io) + [modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite) (pure Go, no CGO) |
|
|
||||||
| IMAP | [emersion/go-imap](https://github.com/emersion/go-imap) |
|
|
||||||
| Logging | [log/slog](https://pkg.go.dev/log/slog) (stdlib) |
|
|
||||||
| Config | [joho/godotenv](https://github.com/joho/godotenv) |
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
# Technical Overview
|
||||||
|
|
||||||
|
## Mục đích
|
||||||
|
|
||||||
|
Tài liệu này là technical overview hiện hành của `Email-OpenClaw Bridge`. `README.md` chỉ giữ phần onboarding và vận hành cơ bản; phần này giữ các chi tiết kỹ thuật bền vững hơn về flow, package layout, state machine và công nghệ chính.
|
||||||
|
|
||||||
|
## Luồng xử lý
|
||||||
|
|
||||||
|
Bridge xử lý email theo pipeline sau:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Ingress (IMAP) → Safety Checks → External Rules → Dispatch (OpenClaw) → Callback → Egress (SMTP reply)
|
||||||
|
```
|
||||||
|
|
||||||
|
Các giai đoạn runtime chính:
|
||||||
|
|
||||||
|
1. IMAP watcher theo dõi `INBOX` bằng IDLE và fetch email chưa đọc.
|
||||||
|
2. Safety checks loại bỏ mail từ chính hệ thống và chặn duplicate theo `message_id`.
|
||||||
|
3. External rules pipeline áp whitelist/blocklist và sinh `DispatchContext`.
|
||||||
|
4. Thread resolution gắn `thread_id` dựa trên quan hệ email đã biết.
|
||||||
|
5. Task được lưu vào SQLite với trạng thái pipeline hiện tại.
|
||||||
|
6. OpenClaw nhận request xử lý và callback về bridge.
|
||||||
|
7. Callback cập nhật `AIResponse`, sau đó bridge gửi phản hồi lại qua SMTP.
|
||||||
|
|
||||||
|
## Package layout
|
||||||
|
|
||||||
|
- `cmd/bridge`
|
||||||
|
- Entrypoint của process, wiring config, DB, IMAP watcher, HTTP router và SMTP egress.
|
||||||
|
- `internal/config`
|
||||||
|
- Đọc `.env`, chuẩn hóa default như `LISTEN_ADDR`, `CALLBACK_BASE_URL`, và validate biến bắt buộc.
|
||||||
|
- `internal/database`
|
||||||
|
- Khởi tạo SQLite qua GORM, định nghĩa `Task` model, repository helpers và health check DB.
|
||||||
|
- `internal/mail`
|
||||||
|
- Chứa IMAP ingress, thread resolution, proxy support cho IMAP, retry logic và SMTP egress.
|
||||||
|
- `internal/rules`
|
||||||
|
- External rules pipeline, whitelist/blocklist rules và rule metadata dùng cho dispatch.
|
||||||
|
- `internal/ai_client`
|
||||||
|
- HTTP client gọi OpenClaw và gửi metadata/callback information ra ngoài.
|
||||||
|
- `internal/api`
|
||||||
|
- HTTP router cho `healthz`, `readyz` và `POST /callback`.
|
||||||
|
- `internal/logging`
|
||||||
|
- Helper tạo structured logger theo `task_uuid`, `thread_id`, `message_id`.
|
||||||
|
|
||||||
|
## Task state machine
|
||||||
|
|
||||||
|
Task được lưu trong SQLite và đi qua các trạng thái sau:
|
||||||
|
|
||||||
|
```text
|
||||||
|
RECEIVED → AI_PROCESSING → CALLBACK_DONE → COMPLETED
|
||||||
|
↓ ↓ ↓
|
||||||
|
IGNORED FAILED SMTP_RETRYING → FAILED
|
||||||
|
```
|
||||||
|
|
||||||
|
- `IGNORED`
|
||||||
|
- Mail bị anti-loop, duplicate, hoặc bị external rules reject.
|
||||||
|
- `RECEIVED`
|
||||||
|
- Task đã được lưu và sẵn sàng dispatch.
|
||||||
|
- `AI_PROCESSING`
|
||||||
|
- Request đã được gửi sang OpenClaw.
|
||||||
|
- `CALLBACK_DONE`
|
||||||
|
- Callback hợp lệ đã cập nhật `AIResponse`.
|
||||||
|
- `SMTP_RETRYING`
|
||||||
|
- Đang retry gửi email phản hồi.
|
||||||
|
- `COMPLETED`
|
||||||
|
- Toàn bộ pipeline kết thúc thành công.
|
||||||
|
- `FAILED`
|
||||||
|
- Hết retry hoặc gặp lỗi không recoverable.
|
||||||
|
|
||||||
|
## HTTP và health behavior
|
||||||
|
|
||||||
|
- `GET /healthz`
|
||||||
|
- Trả `200 {"status":"ok"}` nếu process đang sống.
|
||||||
|
- `GET /readyz`
|
||||||
|
- Trả `200` khi DB writable và `BRIDGE_CALLBACK_TOKEN` có mặt.
|
||||||
|
- Trả `503` nếu DB không writable hoặc config bắt buộc cho callback chưa sẵn sàng.
|
||||||
|
- `POST /callback`
|
||||||
|
- Yêu cầu header `X-Bridge-Token`.
|
||||||
|
- Nhận payload callback từ OpenClaw, cập nhật task và kích hoạt SMTP egress bất đồng bộ.
|
||||||
|
|
||||||
|
## Công nghệ chính
|
||||||
|
|
||||||
|
- Go
|
||||||
|
- Runtime chính, phù hợp với service nhỏ gọn và dễ deploy.
|
||||||
|
- SQLite + GORM
|
||||||
|
- Giữ state cục bộ đơn giản, không cần service DB riêng cho v1.
|
||||||
|
- `github.com/emersion/go-imap/v2`
|
||||||
|
- Hỗ trợ IMAP IDLE và xử lý mailbox theo flow hiện tại.
|
||||||
|
- `gin-gonic/gin`
|
||||||
|
- Cung cấp HTTP router tối giản cho health endpoints và callback.
|
||||||
|
- `log/slog`
|
||||||
|
- Structured logging chuẩn thư viện chuẩn của Go.
|
||||||
|
|
||||||
|
## ADR liên quan
|
||||||
|
|
||||||
|
- [ADR 0001: IMAP thread resolution prefers In-Reply-To and falls back to References](../adr/0001-imap-thread-resolution.md)
|
||||||
|
- [ADR 0002: Ingress uses a configurable external rules pipeline before dispatch](../adr/0002-external-rules-pipeline.md)
|
||||||
|
- [ADR index](../adr/README.md)
|
||||||
|
|
||||||
|
## Tài liệu lịch sử
|
||||||
|
|
||||||
|
- Historical design input: [docs/specs/2026-04-24-email-openclaw-bridge-design.md](../specs/2026-04-24-email-openclaw-bridge-design.md)
|
||||||
Reference in New Issue
Block a user