Skip to content

feat: IMAP Spectrum TCP transport for native clients #57

@ssilvius

Description

@ssilvius

Goal

Add native IMAP (TCP port 993) support via Cloudflare Spectrum, so standard email clients (Thunderbird, Apple Mail, Outlook) connect without a local proxy.

Requirements

Interface

// TCP-to-WebSocket bridge inside the Worker
// Spectrum terminates TLS and proxies raw TCP to the Worker
// Worker bridges TCP stream to DO WebSocket

interface TcpBridge {
  handleTcpConnection(socket: Socket): Promise<void>;
}

Behavior

  • Cloudflare Spectrum proxies IMAPS (port 993) TCP connections to the Worker
  • Worker receives raw TCP stream, bridges to DO via WebSocket
  • IMAP protocol is the same -- parser and handlers are transport-agnostic
  • TLS terminated by Spectrum (client sees valid cert for the domain)
  • Bidirectional: TCP bytes from client -> parse as IMAP commands -> dispatch to DO -> IMAP responses -> TCP bytes back to client
  • Connection lifecycle matches DO session lifecycle
  • Standard email clients work out of the box (Thunderbird, Apple Mail, Outlook, K-9 Mail)

Error Handling

  • TCP connection failures: clean close
  • Spectrum unavailable: WebSocket transport still works as fallback
  • Malformed TCP data: send IMAP BAD response, close connection
  • TLS handshake failure: handled by Spectrum, never reaches Worker

Out of Scope

  • STARTTLS (not applicable -- Spectrum terminates TLS)
  • Plain text IMAP on port 143 (never supported)
  • Custom local proxy for WebSocket-only mode (separate tool if needed)

File Locations

  • Implementation: packages/imap/src/transport/tcp-bridge.ts
  • Tests: packages/imap/tests/transport/tcp-bridge.test.ts
  • Spectrum config: packages/imap/wrangler.toml (spectrum section)

Dev Workflow

Each step is mandatory. Do not skip steps or combine them.

  1. Build -- Implement the feature. Write tests alongside code. Run pnpm test, pnpm check (oxlint + oxc-format). All must pass.
  2. Simplify -- Run /simplify on all changed files. Accept structural improvements, flatten unnecessary abstractions, remove dead code.
  3. Review -- Run /review-pr which launches parallel review agents (code review, silent failure hunter, type design analysis). Do not create the PR yet.
  4. Fix -- Address every issue the review found. Re-run tests after fixes.
  5. PR -- Create the PR. Reference this issue number.

Mail Rules

  • No any -- use unknown and narrow
  • No emoji in code, comments, or commits
  • UUIDv7 for all identifiers
  • Zod is source of truth for schemas (types inferred via z.infer<>)
  • Zero vendor dependencies in core -- all external concerns are adapters
  • pnpm only (never npm/yarn)
  • oxlint for linting, oxfmt for formatting (no Biome)
  • TypeScript 5.9, Vitest 4, Zod 4
  • No barrel files -- use subpath exports in package.json
  • Tests in tests/ mirroring source tree, never colocated

Done When

  • All tests pass
  • Simplify pass completed
  • Review pass completed and issues fixed
  • PR created and linked to this issue

This issue is complete when: Thunderbird, Apple Mail, and Outlook can connect to the IMAP server on port 993 via Spectrum and perform standard operations (list folders, read messages, flag messages, IDLE for push).

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions