refactor: modularize IMAP server with dual login, STARTTLS, and test suite (#859)

refactor: modularize IMAP server with fixes and E2E tests

- Modularize IMAP server into imap_server, imap_mailbox, imap_message,
  imap_http_client, parse_email, config, models
- Support dual login: JWT token and address+password via backend
- Add STARTTLS support with configurable TLS cert/key
- Fix FETCH/STORE returning UID instead of sequence number (RFC 3501)
- Implement IMessageFile.open() for correct BODY[] raw MIME delivery
- Add UIDNEXT to SELECT response via _cbSelectWork override
- Use per-restart UIDVALIDITY to force client resync
- Pass raw MIME to SimpleMessage for accurate RFC822.SIZE
- Fix SENT mailbox returning empty source
- Handle CREATE command gracefully for Thunderbird compatibility
- Add IMAP E2E tests: auth, LIST, SELECT, STATUS, FETCH, SEARCH,
  STORE, UID FETCH, BODY[] integrity, size, seq numbers, SENT mailbox
- Add SMTP E2E tests using nodemailer: send plain/HTML, auth failure,
  sendbox verification
- Add sendTestMail helper using admin/send_mail

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dream Hunter
2026-03-06 11:08:10 +08:00
committed by GitHub
co-authored by Claude Opus 4.6
parent e38015a5b6
commit 2a52fd35d5
21 changed files with 1546 additions and 298 deletions
@@ -51,10 +51,53 @@ services:
- imap_port=11143
```
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `proxy_url` | `http://localhost:8787` | Worker backend URL |
| `port` | `8025` | SMTP port |
| `imap_port` | `11143` | IMAP port |
| `imap_tls_cert` | empty | TLS certificate file path (PEM), enables STARTTLS when configured |
| `imap_tls_key` | empty | TLS private key file path (PEM) |
| `imap_cache_size` | `500` | Max cached messages per mailbox |
| `imap_http_timeout` | `30.0` | Backend HTTP request timeout (seconds) |
## Enabling STARTTLS
Configure `imap_tls_cert` and `imap_tls_key` environment variables to enable STARTTLS support for the IMAP server.
```bash
# .env example
imap_tls_cert=/path/to/cert.pem
imap_tls_key=/path/to/key.pem
```
In Docker Compose:
```yaml
environment:
- imap_tls_cert=/certs/cert.pem
- imap_tls_key=/certs/key.pem
volumes:
- ./certs:/certs:ro
```
## IMAP Login Methods
Two login methods are supported:
| Method | Username | Password | Description |
|--------|----------|----------|-------------|
| JWT Credential | Email address | JWT token | Address credential from frontend, direct authentication |
| Address+Password | Email address | Address password | Verified via backend `/api/address_login` |
The system automatically detects the password format: a three-segment string starting with `eyJ` is treated as a JWT; otherwise it is treated as a password and verified via the backend.
## Using Thunderbird to Login
Download [Thunderbird](https://www.thunderbird.net/en-US/)
For password, enter the `email address credential`
For password, enter the `email address credential` or `email address password`
![imap](/feature/imap.png)
@@ -51,10 +51,53 @@ services:
- imap_port=11143
```
## 环境变量
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `proxy_url` | `http://localhost:8787` | Worker 后端 URL |
| `port` | `8025` | SMTP 端口 |
| `imap_port` | `11143` | IMAP 端口 |
| `imap_tls_cert` | 空 | TLS 证书文件路径(PEM),配置后启用 STARTTLS |
| `imap_tls_key` | 空 | TLS 私钥文件路径(PEM |
| `imap_cache_size` | `500` | 每个邮箱的消息缓存上限 |
| `imap_http_timeout` | `30.0` | 后端 HTTP 请求超时时间(秒) |
## 启用 STARTTLS
配置 `imap_tls_cert``imap_tls_key` 环境变量后,IMAP 服务会自动支持 STARTTLS。
```bash
# .env 示例
imap_tls_cert=/path/to/cert.pem
imap_tls_key=/path/to/key.pem
```
Docker Compose 中配置:
```yaml
environment:
- imap_tls_cert=/certs/cert.pem
- imap_tls_key=/certs/key.pem
volumes:
- ./certs:/certs:ro
```
## IMAP 登录方式
支持两种登录方式:
| 方式 | 用户名 | 密码 | 说明 |
|------|--------|------|------|
| JWT 凭证 | 邮箱地址 | JWT token | 从前端获取的地址凭证,直接认证 |
| 地址+密码 | 邮箱地址 | 地址密码 | 通过后端 `/api/address_login` 验证 |
系统会自动识别密码格式:以 `eyJ` 开头的三段式字符串视为 JWT,其他视为密码并调用后端验证。
## 使用 Thunderbird 登录
下载 [Thunderbird](https://www.thunderbird.net/en-US/)
密码填写 `邮箱地址凭证`
密码填写 `邮箱地址凭证``邮箱地址密码`
![imap](/feature/imap.png)