Mail access: IMAP + app password (IPv4 only), not Gmail API

This commit is contained in:
2026-10-11 18:40:16 +11:00
parent a69aaa3f80
commit 93f61d9aef
18 changed files with 1229 additions and 6 deletions

View File

@@ -114,7 +114,7 @@ size-capped.
| System | Use |
|---|---|
| **Gmail API** | Read mail; apply labels; send replies ("Send mail as"). |
| **Gmail IMAP + SMTP** | Read mail, move labels, send replies. App password (`GMAIL_USER`, `GMAIL_APP_PASSWORD`). **Force IPv4** — see section 9. |
| **PurelyMail** | Source of the forwarding. Read-only reference. Not required for v1. |
| **Amazon SES** | App/website mail only. Not for personal replies in v1. |
| **JEV** | Classification (typed category + confidence). HTTP API. |
@@ -133,11 +133,14 @@ Build to it. `/ask` never changes state.
| Backend | **Go** |
| UI | **HTMX** + server-rendered HTML |
| Database | **SQLite** |
| Mail read | **IMAP** `imap.gmail.com:993` (SSL), **IPv4 only** |
| Mail send | **SMTP** `smtp.gmail.com:587` (STARTTLS), **IPv4 only** |
| Mail auth | **Gmail app password** from `environment.d`. No OAuth, no console. |
| Design | Family Home Lab `tokens.css` |
| Host | `.13`, Docker |
| Container | **This project's own** image and compose file. Not shared with any other project. |
| Folder | `/home/sam/paseo/projects/email_agent/` |
| Port | Allocate one (suggest **8790**). Record it here once chosen. |
| Port | **8790** (chosen; container listens on 8790, published as `${EMAIL_AGENT_PORT:-8790}`). Confirm against infra-facts [AUD-60](/AUD/issues/AUD-60). |
| URL | `mail.lab.audasmedia.com.au` via Caddy on `.35` |
| Auth | **Separate session login.** Not the console SSO. |
@@ -165,8 +168,10 @@ Go service, SQLite, config, session login, Dockerfile, compose, Caddy route.
*DoD:* the app runs on `.13`, login works, an empty dashboard renders, `/health` returns ok.
**Phase 2 — Read mail**
Gmail OAuth (one manual consent). Fetch, store, and list real messages.
*DoD:* the inbox shows real mail, with the source address from FR-2.
Connect to Gmail over **IMAP** with the app password. **Force IPv4.** Fetch, store,
and list real messages.
*DoD:* the inbox shows real mail. Confirm the source address from FR-2 against a
real forwarded message (see section 13).
**Phase 3 — Classify**
JEV classification plus the rules table.
@@ -213,6 +218,24 @@ Resolved:
3. **Spam:** recommend and confirm. Never auto-delete.
4. **Daily summary:** by email.
5. **Retention:** one month of message bodies.
6. **Gmail OAuth:** the agent chooses the moment during the build.
6. **Mail access is IMAP + app password** — no console, no OAuth. Working on `.13`
and `.51`.
Remaining: none that block. Add new ones here as they appear.
Remaining:
1. **No domain mail is arriving yet.** All 617 inbox messages are addressed to
`samuelrolfe@gmail.com`. None to `where-woof.com`, `audasmedia.com.au`, or
`kontra.day`. Confirm the PurelyMail forwarding, then send a test message.
2. **FR-2 header:** Gmail sets `Delivered-To` to the Gmail address. The original
domain address must come from the forwarding headers (`X-Original-To`,
`Delivered-To`, or the envelope). Confirm with a real forwarded sample.
3. **Send-as:** sending as a domain address needs Gmail "Send mail as" set up for
that address.
### Infrastructure notes (found during setup)
- **IPv6 to Gmail is broken from `.13`.** The first IMAP attempt failed with a
socket EOF over IPv6. Forcing IPv4 works. **The agent must force IPv4** for IMAP
and SMTP.
- Credentials live in `~/.config/environment.d/10-secrets.conf` on `.13` and `.51`,
as `GMAIL_USER` and `GMAIL_APP_PASSWORD`.