English | 简体中文
There is no good open-source Gmail client for macOS. The web client lacks native notifications and a Dock badge. Mimestream is paid and closed. Mail.app does not feel like Gmail. Electron clients are heavy.
This app does one thing: tells you when new mail arrives. Click the notification to open the message in your browser. That is it.
- Menu bar only —
LSUIElement=true, no Dock icon, no main window - Native notifications — UNUserNotificationCenter, click to open in browser
- Incremental polling —
users.history.listkeeps steady-state at ~1-3 quota units per poll - Status-aware icon — auth
⚠️ yellow, network grey, API⚠️ red, normal black (priority resolved) - Quad empty states — signed-out, needs reauthorization, inbox zero, error with retry
- Configurable polling — 60s default, 120s / 5min / 10min via Settings
- Launch at login — SMAppService toggle in Settings
- Multi-account-safe URLs — notification clicks open the right inbox even with multiple Google sessions
- macOS 14 (Sonoma) or newer
- Xcode 15+ (
xcode-select --install) - A Google Cloud OAuth 2.0 Client ID (Desktop app type)
⚠️ v1.0.0-beta — source build only. The.dmgand Homebrew cask will follow once Google OAuth verification clears.
- Open the Google Cloud Console — Credentials page.
- Pick an existing project or create a new one.
- Enable Gmail API: APIs & Services → Library → Gmail API → Enable.
- Configure the OAuth consent screen (User Type = External, Publishing status = Testing).
- Create Credentials → OAuth client ID → Application type = Desktop app.
- Copy both the Client ID (
123-abc.apps.googleusercontent.com) and Client Secret (GOCSPX-...).
Testing-status caveats (Google rules, not ours):
- Only Google accounts added to the consent screen's Test users list can sign in.
- Refresh tokens expire after 7 days. The app will prompt you to sign in again.
Submit OAuth verification (privacy policy URL required, ~4 weeks) to remove these limits.
git clone https://github.com/pezy/gmail.git
cd gmail
OAUTH_CLIENT_ID="123-abc.apps.googleusercontent.com" \
OAUTH_CLIENT_SECRET="GOCSPX-..." \
./scripts/build.shThe script writes Gmail.app to the repo root.
xattr -d com.apple.quarantine Gmail.app # bypass Gatekeeper for unsigned binary
open Gmail.appThe menu bar shows ✉. Click → Connect Gmail → finish the OAuth flow in Safari → unread mail appears within seconds.
- Click ✉ in the menu bar to toggle the popover.
- Click a row to open the message in your default browser.
- ⚙ icon in the popover footer opens Settings.
- Sign-out icon in the footer clears tokens and resets state. Use this if anything ever feels stuck.
swift test67 unit tests covering OAuth state machine, Keychain round-trip, Gmail API parsing, polling state machine, notification dedup, status bar presenter, and settings persistence.
See TODOS.md for deferred work, including:
- Multi-account support
- Quick Look message preview (spacebar)
.dmgdistribution + Homebrew cask- Sparkle auto-update
- Mac App Store distribution
- Language: Swift 6 (strict concurrency)
- UI: SwiftUI + AppKit (
NSStatusItem,NSPopover,NSPanel,NSWindow) - OAuth: AppAuth-iOS (the only third-party dependency)
- Networking:
URLSession - Notifications:
UNUserNotificationCenter - Token storage: Security framework (Keychain),
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly - Auto-start:
SMAppService - Polling:
NSBackgroundActivityScheduler - Network monitoring:
NWPathMonitor
Ten focused modules behind a single @MainActor @Observable AppState:
AuthService -- AppAuthAuthorizer -- KeychainService
GmailAPIClient -- HTTPS to gmail.googleapis.com
PollingCoordinator (state machine) -- NetworkMonitor
NotificationManager (UNUserNotificationCenter)
StatusBarController + PopoverView + SettingsView (UI)
LoginItemsManager (SMAppService)
See the design document for the full architecture diagram and decision log.
- AppAuth-iOS by Google for handling OAuth correctly so we did not have to.
- MiaoYan for the README format inspiration.