feat(remote): add email (IMAP/SMTP) channel - #316
Conversation
Adds email as a first-class remote channel alongside Feishu and Slack. Users can drive the agent by email; the agent replies as a correctly threaded message (In-Reply-To/References), mapping one mail thread to one agent session. - IMAP receive via imapflow (inbox polling for unseen mail) - SMTP reply via nodemailer, MIME parsing via mailparser - Provider presets: Gmail, Outlook/Microsoft 365, Yahoo, iCloud, GMX, WEB.DE, Zoho, plus custom IMAP/SMTP - Credentials stored via the existing encrypted remote config store and never logged (error redaction included) - Secure by default: dm.policy 'allowlist' synced into gateway auth as email:<address> - Full wiring: types, config store, remote-manager (updateEmailConfig), IPC remote.updateEmailConfig, preload, shared ipc-types - UI: EmailConfigStep wired into RemoteControlPanel + ConfigStepNav, en/zh i18n - Tests: src/tests/remote/email-channel.test.ts (presets + threading) - Docs: docs/email-integration.md (German step-by-step guide) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Review mode: initial
Findings
-
[Major] Global auth mode override from email DM policy could affect other channels
src/main/remote/remote-manager.ts:438-441
When email DM policy is set to'open'or'pairing', the code overwrites the entire gateway auth mode (currentAuth.mode) to that value. This overrides any existing allowlist or pairing configuration that other channels (Feishu, Slack) might rely on. For example, if Feishu is configured withallowlist, setting email to'open'opens the gateway to all senders across all channels. The email channel should enforce its DM policy internally rather than modifying the global auth, or at least only apply changes when no other channel has a stricter mode.
Suggested fix:// Instead of overwriting, the email channel should check its own DM policy // during message processing, separate from gateway auth. // Or, merge policies conservatively: only allow upgrade to stricter mode.
-
[Minor] Messages marked as Seen before agent processes them, risking message loss on failure
src/main/remote/channels/email/email-channel.ts:246-248
After receiving a message, the code immediately marks it as\Seenon the server. If the agent fails to process the message (e.g., crash before sending reply), the message is already marked Seen and will not be re-fetched on the next poll. This could lead to lost requests.
Suggested fix:// mark as Seen only after successful emission to the gateway // or implement a separate persistent cursor (e.g., UIDNEXT) // await client.messageFlagsAdd(msg.uid, ['\\Seen'], { uid: true });
-
[Minor] Missing test for SMTP verification failure path
src/tests/remote/email-channel.test.ts
The mockverifyMockalways returnstrue. There is no test covering the case where SMTP server rejects credentials or is unreachable, which is a common deployment issue.
Suggested fix: Add test case whereverifyMockrejects, expectingstart()to throw. -
[Nit] Unused i18n key
emailSecure
src/renderer/i18n/locales/en.json:841andzh.json:841
The keyremote.emailSecureis defined but never used in any component. Consider using it as a label for a TLS toggle in the custom email configuration UI, or remove it. -
[Nit] No explicit TLS toggle for custom email configuration; relies on port heuristic
src/renderer/components/RemoteControlPanel.tsx:217-224
For custom providers, thesecureproperty is derived from the port number (993 → secure, otherwise false). This may be incorrect for non-standard ports with implicit TLS (e.g., port 26). Consider adding a checkbox forsecurein the custom fields, using theemailSecurei18n key.
Questions
None.
Summary
Review mode: initial
Review policy: advisory — the check reflects automation health/completion only; it does not approve the PR or resolve findings.
The PR introduces a complete email channel (IMAP receive + SMTP send) with provider presets, configuration UI, and tests. Security-conscious features include encrypted credential storage, error redaction, and self-loop prevention. The main concerns are the global auth mode override (Major) and the early message marking (Minor). Test coverage is good but could include failure paths. No regressions detected.
Testing
Passes 6/6 tests (provider presets + threading). Not run (automation).
Open Cowork Bot
Summary
Adds email as a first-class remote channel alongside Feishu and Slack. Users can drive the agent by email; the agent replies as a correctly threaded message (
In-Reply-To/References), mapping one mail thread to one agent session.imapflownodemailer, MIME parsing viamailparserdm.policy: 'allowlist'synced into gateway auth asemail:<address>What's included
src/main/remote/channels/email/(channel + provider presets)remote-manager(updateEmailConfig), IPCremote.updateEmailConfig, preload, shared ipc-typesEmailConfigStepwired intoRemoteControlPanel+ConfigStepNav, en/zh i18nsrc/tests/remote/email-channel.test.ts(presets + threading)docs/email-integration.md(step-by-step guide)Verification
npm run typecheck(0 errors), the new vitest suite (6/6), and ESLint on new files all pass. The libraries (nodemailer,imapflow) build into the main-process bundle; a local macOS package was produced successfully.Notes / scope
IDLEis a possible follow-up.🤖 Generated with Claude Code