The approved real test reply was sent and the thread updated (same
X-GM-THRID as the original). The live test exposed one bug: the thread
check hardcoded Gmail's sent mailbox as "[Gmail]/Sent Mail", but this
account exposes it as "[Google Mail]/Sent Mail".
- internal/mailfetch: LIST parser, ListMailboxes, and SentMailbox that
finds the mailbox flagged \Sent (RFC 6154) with name fallbacks.
- internal/mailops: VerifyThreadUpdated selects the discovered \Sent
mailbox instead of a hardcoded name.
- cmd/email-agent: -check-thread <id> exercises the check against real
Gmail without sending mail.
- Tests for LIST parsing, sent-mailbox discovery, and the discovery
error path.
- docs/phase5-replies.md: record send-as verification, the sent reply's
thread id, the app confirmation (sent_reply_in_thread=true), and the
fix.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Implements Phase 5 of AGENTS.md §11 (FR-8, FR-15):
- Message detail pane (GET /partials/message) with body, recommended
action, reply identity, template picker, editable draft, and history.
- internal/reply: OmniRoute (OpenAI-compatible) chat client and a
template-based draft generator. All non-JEV models go through
OmniRoute (§10).
- internal/mailops: SMTP send over smtp.gmail.com:587 with STARTTLS and
the app password, forcing IPv4 (§9); FR-15 reply identity (send as the
arrived-at X-Pm-Original-To address, else "Sam Rolfe"); threading via
In-Reply-To/References; -check-smtp safe verification; and a
[Gmail]/Sent Mail thread check.
- Migration v5 stores messages.message_id_header and drafts.sent_at;
mailfetch parses Message-ID.
- Send is user-triggered only: CSRF + UI confirm + confirm=yes guard,
no auto-send, duplicate-send refused. A sent reply files the original
under Replied-to/<address> and logs every step (FR-13).
- Tests for reply, mailops SMTP/identity/thread check, store drafts and
migration v5, and the server draft/edit/send guards.
- docs/phase5-replies.md, README, .env.example, docker-compose updated.
Co-Authored-By: Paperclip <noreply@paperclip.ing>