# ProtonMail Mini-Bridge A minimal ProtonMail Bridge implementation in Rust that exposes local IMAP and SMTP servers, allowing `skim` (and any other standard email client) to connect without code changes. The full ProtonMail Bridge is ~50,000 lines of Go. This mini-bridge targets only the subset of functionality that `skim` needs: one account, INBOX only, one concurrent client. ## Components ### 1. Project scaffold New binary crate with `Cargo.toml` dependencies (`tokio`, `reqwest`, `proton-srp`, `rpgp`, `serde`, `toml`). Config file format covering ProtonMail credentials and local bind ports. ### 2. ProtonMail authentication SRP 6a login flow against the Proton API: - POST `/auth/info` with username → receive modulus, server ephemeral, salt - Compute SRP proof locally using `proton-srp` - POST `/auth/login` with client proof → receive access token + encrypted private keys - Handle optional TOTP 2FA interactively on first run - Persist session (access token + refresh token) to disk to avoid re-authenticating on restart ### 3. ProtonMail API client Thin `reqwest`-based HTTP wrapper around the endpoints the bridge needs: - List messages (with pagination) - Fetch single message (metadata + encrypted body) - Delete message - Fetch recipient public key (for outbound encryption) - Send message (modelled from the open-source `ProtonMail/proton-bridge` Go implementation) ### 4. Crypto layer Using `rpgp` or `proton-crypto-rs`: - Decrypt the user's private key (delivered encrypted by the API, unlocked with the mailbox password) - Decrypt incoming message bodies with the private key - Encrypt outbound messages to recipient public keys ### 5. Message store In-memory (optionally persisted) mapping between IMAP sequence numbers and Proton message IDs. IMAP uses stable sequential integers; Proton uses opaque string IDs. The store must: - Assign sequence numbers to messages in order - Renumber correctly after deletes - Survive restarts without breaking existing client state ### 6. IMAP server TCP listener on `localhost:143` (configurable). Implements the nine commands `skim` uses: | Command | Purpose | |---------|---------| | `LOGIN` | Accept local credentials (no real auth needed) | | `NOOP` | Keepalive / connection check | | `SELECT INBOX` | Open mailbox, report message count | | `FETCH range BODY.PEEK[HEADER.FIELDS (SUBJECT FROM DATE)]` | List emails | | `FETCH seq BODY.PEEK[]` | Fetch full message body | | `SEARCH OR SUBJECT "..." FROM "..."` | Search by subject or sender | | `STORE seq +FLAGS (\Deleted)` | Mark for deletion | | `EXPUNGE` | Delete marked messages | | `LOGOUT` | Disconnect | Each command translates to API client + crypto layer calls via the message store. ### 7. SMTP server TCP listener on `localhost:587` (configurable). Minimal implementation: - EHLO, AUTH, MAIL FROM, RCPT TO, DATA, QUIT - On DATA completion: hand the message to the crypto layer to encrypt, then POST via API client ## Build order Components 2 → 3 → 4 can be built and tested with a simple CLI harness before any network server exists. Component 5 is pure logic with no I/O. Components 6 and 7 are the final pieces and can be validated by pointing `skim` at localhost. ## References - [ProtonMail/proton-bridge](https://github.com/ProtonMail/proton-bridge) — official Bridge (Go, open source) - [ProtonMail/go-proton-api](https://github.com/ProtonMail/go-proton-api) — official Go API client - [ProtonMail/proton-crypto-rs](https://github.com/ProtonMail/proton-crypto-rs) — official Rust crypto crates - [ProtonMail/proton-srp](https://github.com/ProtonMail/proton-srp) — official Rust SRP implementation - [rpgp](https://github.com/rpgp/rpgp) — pure Rust OpenPGP implementation