A native macOS Proton Mail client built with pure Swift and SwiftUI. No Proton Bridge required, no paid subscription needed.
ProtonKit directly interfaces with the Proton REST API, implementing SRP-6a authentication (Proton's non-standard variant), PGP encryption/decryption, and token-based key hierarchy from scratch in Swift.
- SRP-6a Authentication - Full Proton SRP variant (little-endian, 4xSHA512 expandHash, bcrypt password hashing)
- TOTP 2FA support
- PGP Encryption/Decryption - Email encryption via ObjectivePGP with per-key passphrase mapping, supports both RSA and Curve25519 (ECDH) keys
- Token-based Key Hierarchy - User key -> address key via encrypted token
- Multi-Account - Outlook-style sidebar with per-account folder trees, independent sessions
- macOS Notifications - Background polling with native notifications, click-to-navigate, dock badge
- Session Persistence - macOS Keychain with namespace isolation per account, automatic restore on launch
- Three-Pane Layout - NavigationSplitView (folders / message list / message detail)
- Infinite Scroll - Paginated message loading (50 per page)
- HTML Rendering - WKWebView with sanitization, auto-height, link interception
- Message Actions - Trash, star, archive, move to folder, mark spam/not spam, permanent delete, empty Trash/Spam, block sender, mark all as read — via context menu, swipe, hover quick actions, toolbar, or keyboard
- Labels - Proton's dual folder/label system: colored labels in the sidebar with counts, apply/remove from the context menu, colored chips in the reading pane; custom folders use their API colors and nest with indentation
- Batch Select - Cmd+Click / Shift+Click multi-select with batch trash, archive, and mark read/unread
- Double-Click to Open - Double-click a message to open it in a separate window
- Thread View - Detail view lists the other messages in the same conversation
- Attachment Download - Download and decrypt PGP-encrypted attachments with save dialog
- Attachment Upload - PGP-encrypted attachment upload with per-recipient session key management (RSA + ECDH)
- Inline Images -
cid:inline images rendered via a custom WKURLSchemeHandler with on-demand decryption - Privacy Hardening - Viewer JavaScript disabled; remote images blocked by default (WKContentRuleList) with per-message "Load Images"; HTML sanitization
- Dark Mode - Adaptive rendering for both the message viewer and the compose editor
- Search - Keyword search across messages via Proton API
- Keyboard Shortcuts - Cmd+R reply, Shift+Cmd+R reply all, Shift+Cmd+F forward, Shift+Cmd+N refresh, Cmd+E archive, Delete trash, Cmd+Shift+U toggle read/unread, Cmd+D save draft
- Compose Windows - Reply / Reply All / Forward / New in separate windows with Bcc, From-address selector, signature, and discard confirmation
- Send Controls - Undo send (0–20s delay), schedule send, message expiration, plain-text mode — mirroring the official client
- Reading Tools - Print, view raw headers, QuickLook attachment preview, PGP signature verification with a lock badge
- mailto: Handler - Registers as a system mail client; "Set as Default Email Client" in Settings
- Save & Edit Drafts - Save drafts (Cmd+D), edit and send from Drafts folder with attachment preservation
- Event Sync Engine - Incremental event polling applies creates/updates/deletes/counts to the UI, recovers from stale event IDs, and drives notifications
- Offline & Cache - Accounts restore offline from disk snapshots; folder lists and message bodies (still PGP-encrypted at rest) cached for instant startup and offline reading
- Settings - Poll interval, notification toggle, remote-image policy, signature (Cmd+,)
- Error Feedback - Failed operations surface as toasts instead of silently diverging local state
Coming soon
- macOS 14+ (Sonoma)
- Apple Silicon (arm64)
- Xcode Command Line Tools (
xcode-select --install)
git clone https://github.com/JulianHunag/ProtonKit.git
cd ProtonKit
# Debug build + package
bash scripts/build-app.sh
open /Applications/ProtonKit.appFor release DMG:
bash scripts/build-dmg.sh
# Output: build/ProtonKit.dmgSince the app is ad-hoc signed (no Apple Developer certificate), you may need:
xattr -cr /Applications/ProtonKit.app| Component | Choice | Notes |
|---|---|---|
| Language | Swift 5.9+ | Pure Swift, no ObjC |
| UI | SwiftUI (macOS 14+) | NavigationSplitView |
| PGP | ObjectivePGP 0.99.4 | BSD, SPM via xcframework |
| SRP BigNum | BigInt 5.3+ | MIT, pure Swift |
| Crypto | CryptoKit | X25519 ECDH, built-in |
| Build | SPM + bash scripts | No Xcode GUI required |
| Signing | Ad-hoc | No Apple Developer cert |
ProtonKit/
├── Sources/ProtonCore/ # Core library (SRP, API, crypto, session)
│ ├── ProtonSRP/ # SRP-6a authentication (Proton variant)
│ ├── ProtonAPI/ # REST API client (actor-based)
│ ├── ProtonCrypto/ # PGP encryption/decryption, attachment crypto, key passphrase
│ ├── Models/ # API response models
│ └── Session/ # Multi-account session management + Keychain
├── Sources/ProtonKit/ # SwiftUI application layer
│ ├── App/ # App entry, ContentView
│ ├── Services/ # Notification polling service
│ └── Views/ # Auth, Sidebar, MessageList, MessageDetail, Compose
└── scripts/ # Build & packaging scripts
Key design decisions:
- Each account has its own
ProtonClient(actor) andMessageDecryptor- fully isolated - Keychain credentials namespaced by account UID (
{uid}.accessToken) - Attachment encryption uses self-managed session keys with per-recipient key packets (RSA + ECDH)
- SRP implementation ported from go-srp and hydroxide
- ProtonMail/go-srp - SRP reference implementation (Go)
- emersion/hydroxide - Open-source Proton Mail Bridge (Go)
- ObjectivePGP - PGP library
- Proton API behavior reverse-engineered from hydroxide source + network inspection
MIT