Skip to content

Giorgio089/suave-mail

Repository files navigation

📬 Suave Mail

A native macOS email client that doesn't think it's a browser.

Suave Mail is an open-source, privacy-first Gmail client for macOS built entirely with SwiftUI and SwiftData. No Electron. No Chromium embedded inside a trench coat pretending to be a desktop app. Just pure, native Swift talking directly to the Gmail API — the way it should be.


✨ Why Another Email Client?

Because:

  • Electron email clients use more RAM than your entire development environment
  • The built-in Mail app has a complicated relationship with Gmail labels
  • Web Gmail is fine until you want keyboard shortcuts that actually make sense
  • You believe that a 2024 Apple Silicon Mac should open an email in under 50ms

If you nodded at any of the above, welcome home.


🎨 Design Philosophy: Zen

Suave Mail follows a "Lean & Calm" design principle:

  • OLED-black backgrounds — easier on the eyes, easier on the soul
  • Floating sidebar with translucent .thinMaterial — no harsh borders, just layers of depth
  • Generous whitespace — because your inbox is already stressful enough
  • Apple serif fonts (New York) in reading pane with 1.8× line height — emails should be readable, not a wall of Arial 13pt
  • Inbox Zero celebration — a breathing animation greets you when you've actually made it. Take a deep breath. You earned it.

🔒 Privacy First

Suave Mail is built around the assumption that your emails are none of anyone else's business — including the app itself.

  • Zero data leaves your device. All emails are fetched, sanitized and stored locally via SwiftData. No telemetry, no analytics, no "improving your experience."
  • HTML Sanitizer strips tracking pixels, analytics scripts and malicious code before rendering — at the Swift layer, before it even reaches WebKit.
  • WKContentRuleList blocks external trackers directly at the WebKit engine level.
  • Privacy Dashboard in the sidebar shows you exactly how many spy pixels tried to phone home today. (Spoiler: it's more than you think.)
  • Keychain-only token storage. OAuth tokens live in the macOS Keychain. If Google revokes your token, the app wipes the session immediately instead of endlessly retrying in a broken refresh loop.

🏗️ Architecture

SuaveMail (macOS App)
├── SuaveMailCore          — Business logic, no UI dependencies
│   ├── Auth/              — OAuth2 via AppAuth, Keychain storage
│   ├── Gmail/             — Gmail REST API client + sync engine
│   │   └── DTOs/          — Codable response models
│   ├── Models/            — SwiftData models (MailThread, Message, Account…)
│   ├── Persistence/       — MailRepository, PersistenceController
│   └── MailRendering/     — HTMLSanitizer, CSS injection
│
└── SuaveMailUI            — SwiftUI views, no direct API calls
    ├── Auth/              — LoginView
    ├── Shell/             — AppShell, AppShellModel (paginated)
    ├── Sidebar/           — Labels, Privacy Dashboard
    ├── ThreadList/        — Paginated thread list
    └── Detail/            — MailWebView (WKWebView + sanitizer)

Tech Stack

Layer Technology
Language Swift 6.x (strict concurrency)
UI SwiftUI (macOS 14+)
Persistence SwiftData + SQLite
Authentication AppAuth + macOS Keychain
Email API Gmail REST API (not IMAP)
Rendering WKWebView + custom HTMLSanitizer
Privacy WKContentRuleList (WebKit-level blocking)

🚀 Getting Started

Requirements

  • macOS 14.0+
  • Xcode 16+
  • A Google Cloud project with the Gmail API enabled
  • An OAuth 2.0 Client ID that matches com.gs.SuaveMail
  • A tester account added to the Google OAuth consent screen when the app is in testing mode

Setup

# 1. Clone
git clone https://github.com/Giorgio089/suave-mail.git
cd suave-mail

# 2. Open in Xcode
open SuaveMail.xcodeproj

Configure OAuth

  1. Go to Google Cloud Console
  2. Create a project → Enable the Gmail API
  3. Create an OAuth 2.0 Client ID that exports a Google client plist
  4. Confirm the exported values match the repo config: CLIENT_ID REVERSED_CLIENT_ID BUNDLE_ID = com.gs.SuaveMail
  5. If you rotate projects again later, update these keys in Info.plist: GMAIL_OAUTH_CLIENT_ID GMAIL_OAUTH_REDIRECT_URI CFBundleURLSchemes
  6. Ensure the OAuth consent screen is in testing or production as intended and add the testers who should be able to log in
  7. Ensure the configured Gmail scopes cover the current app feature set: https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/gmail.send https://www.googleapis.com/auth/gmail.modify
  8. Build & Run (Cmd+R)

Note: The repo now versions a working tester-ready OAuth client configuration. The client ID is not a secret. Secrets still stay out of the repo.


⌨️ Keyboard Shortcuts

Shortcut Action
Cmd+N New message
Cmd+R Refresh
Cmd+K Search

🧪 Running Tests & CI

# Run all tests
./Scripts/test.sh

# Check formatting
./Scripts/format.sh --check

# Lint
./Scripts/lint.sh

CI runs automatically on every push and pull request via GitHub Actions (.github/workflows/ci.yml). It builds, tests, lints and formats on macOS 15.


📁 Project Structure

suave-mail/
├── Sources/
│   ├── SuaveMailApp/      — App entry point, scene setup
│   ├── SuaveMailCore/     — Core logic (no UIKit/SwiftUI)
│   └── SuaveMailUI/       — All SwiftUI views
├── Tests/
│   ├── SuaveMailCoreTests/
│   └── SuaveMailUITests/
├── Assets.xcassets/
├── Scripts/               — build, test, lint, format helpers
├── Package.swift          — Swift Package Manager manifest
├── Info.plist             — versioned Gmail OAuth/tester config
├── DESIGN.md              — Original design document & motivation
└── ARCHITECTURE.md        — Current architecture & roadmap

🗺️ Roadmap

  • OAuth2 login + Keychain storage
  • Gmail API sync engine (threads, labels, history delta)
  • Paginated thread list (no full-load crashes on large inboxes)
  • HTML email rendering with sanitization & tracking protection
  • Privacy Dashboard
  • Zen UI: floating sidebar, OLED dark mode, New York typography
  • Keyboard shortcuts
  • Background sync via NSBackgroundActivityScheduler
  • Full-text search via SwiftData predicates (Cmd+K)
  • Composer / Send
  • CloudRelayService — real-time push without breaking the zero-data promise

🤝 Contributing

PRs welcome! The codebase is split cleanly between SuaveMailCore (zero UI dependencies) and SuaveMailUI — making it easy to add features or tests without touching unrelated code.

If you find a tracking pixel that slips through the sanitizer, please open an issue. We take that personally.


📄 License

MIT — build on it, learn from it, ship your own mail client. The world needs more native apps.


Built for people who believe their inbox deserves better than a 400MB Electron bundle.

About

Native macOS Gmail client. SwiftUI + SwiftData. Privacy-first. Zero Electron. Zero apologies.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages