Skip to content

feat(remote): add email (IMAP/SMTP) channel - #316

Open
lanciafulvia wants to merge 1 commit into
OpenCoworkAI:mainfrom
lanciafulvia:feat/email-channel
Open

feat(remote): add email (IMAP/SMTP) channel#316
lanciafulvia wants to merge 1 commit into
OpenCoworkAI:mainfrom
lanciafulvia:feat/email-channel

Conversation

@lanciafulvia

Copy link
Copy Markdown

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.

  • Receive: IMAP inbox polling via imapflow
  • Reply: SMTP via nodemailer, MIME parsing via mailparser
  • Providers: presets for Gmail, Outlook/Microsoft 365, Yahoo, iCloud, GMX, WEB.DE, Zoho — plus custom IMAP/SMTP
  • Credentials: stored via the existing encrypted remote config store; never logged (error redaction included)
  • Secure by default: dm.policy: 'allowlist' synced into gateway auth as email:<address>

What's included

  • Channel: src/main/remote/channels/email/ (channel + provider presets)
  • 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 (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

  • Receive uses polling (default 30s); IMAP IDLE is a possible follow-up.
  • Incoming attachments are not yet forwarded to the agent (text/HTML body only).

🤖 Generated with Claude Code

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>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 with allowlist, 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 \Seen on 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 mock verifyMock always returns true. 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 where verifyMock rejects, expecting start() to throw.

  • [Nit] Unused i18n key emailSecure
    src/renderer/i18n/locales/en.json:841 and zh.json:841
    The key remote.emailSecure is 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, the secure property 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 for secure in the custom fields, using the emailSecure i18n 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant