A local-first desktop email client for Gmail, Microsoft 365 and IMAP.
Built with Tauri 2 — fast, native, and your mail stays on your machine.
Most email clients either hold your credentials hostage in the cloud or feel like a web page in a frame. Emailer is a real desktop app: your messages, credentials and settings live in a local SQLite database, search and reading work offline, and sync runs quietly in the background when you're online.
Captured from the app running in browser mock mode (bun run dev:mock) —
the amber pill in some shots marks demo data.
Composer · Docked AI assistant with cited sources
Adding an account — provider detected from the address
- Gmail, Microsoft 365 and every major IMAP provider — Gmail over its REST API with OAuth; Microsoft 365 / Outlook.com over Graph with modern sign-in; IMAP/SMTP with server auto-discovery for Outlook, Yahoo, iCloud, Fastmail, GMX, Zoho and AOL — each with its brand icon across the app
- Local-first storage — everything lives on this machine; messages, search and drafts work offline and sync resumes when you're back. Settings → Storage breaks down the disk usage, and a two-step reset deletes all local data — your mail servers are never touched
- Choose how much history downloads — a per-account first-sync window (last month, 3 or 6 months, a year, or everything) keeps a big mailbox from arriving all at once; widening it later offers to backfill the newly covered range in the background
- Unified inbox — combine all accounts into one list (with per-account color attribution) or work per folder; priority inbox included. Profiles give groups of accounts a shared color that marks threads in cross-account lists
- Search that keeps up — full-text search with operators:
from:,to:,label:,is:starred,larger:5m,before:2026-01-01— and negations like-from:newsletter@or-has:attachment. Accent folding means "be don dep" still finds "Bé Dọn Dẹp", and when a plain query finds nothing, a clearly flagged relaxed retry surfaces near-misses - Find and inspect —
Cmd/Ctrl+Fsearches inside the open thread with a live match count, and View source shows the untouched RFC 822 original, read-only with exact copy - Printing — the reading pane's printer action prints the open message (or the whole thread) through a clean print view and the system print dialog — saving a PDF included
- Reply tracking — nudges resurface threads you haven't answered; follow-up reminders resurface threads that weren't answered to you
- Todos & tasks — pull any thread into the sidebar task list (or let AI suggest tasks from an open message) with due dates, recurrence and a one-click jump back to the thread
- Calendar — a month/week/day view fed by connected Microsoft 365
calendars; AI event extraction turns an open thread into a prefilled
event, and
.icsattachments get an Add to calendar shortcut. Meeting invitations render an RSVP card: Accept, Tentative or Decline writes back to the calendar and replies to the organizer, while cancellations and join links are handled; an optional per-account reminder nudges you before the meeting starts - Local automation — rules (built by hand or from a plain-language description), junk filter, blocked senders and auto-archive run locally on every sync
- A composer that gets out of the way — rich text, snippets, attachments, per-account signatures, and an undo-send window
- Voice dictation & your writing voice — the composer's mic turns speech into text entirely on-device (a one-time ~148 MB model download, always cancellable), and an optionally learned writing voice — distilled from your sent mail — lets drafts, proofreads and smart replies sound like you
- Optional AI on your terms — off until you enable it, then summaries, smart replies, Ask My Inbox, task/event extraction, translation and a catch-me-up folder digest — through the provider you configure, including a fully local Ollama. A docked assistant panel answers questions about your mailbox with read-only lookups and inline sources, and an optional local semantic index (a one-time ~128 MB model download) lets it find threads by meaning. Per-surface model tiers, quick replies that never send by themselves, and a token usage meter kept on this machine
- CardDAV contacts — connect a Nextcloud, Radicale or provider address book; synced contacts autocomplete just like local ones, and the app password is sealed on the device
- Backup & restore — export account metadata and settings, profiles,
rules, snippets, quick steps, signatures, saved searches and a
snapshot of your mail to one checksummed
.emailer-backupfile — passwords are never in it. Restoring verifies first, then replaces or merges, with a quick sign-in per account afterwards - Encryption — per-account OpenPGP keys with encrypt/decrypt in both the composer and the reader
- Attachment security — optional VirusTotal hash lookup before an attachment's first open (only the SHA-256 hash leaves the machine)
- Keyboard-first — command palette, full shortcut coverage and customizable bindings
- Yours to theme — light/dark, seven accent colors, density presets, reading-pane options
Installers for Windows (installer + portable exe), macOS (Apple Silicon + Intel DMG) and Linux (AppImage + deb) are on the Releases page. Two channels, switchable in the app under Settings → Updates:
- Stable — tagged releases only (
vX.Y.Z) - Beta — prereleases (
vX.Y.Z-beta.N) as soon as they build
The packaged app checks the channel's signed update manifest; release engineering details live in docs/releases.md.
- Frontend: React 19 + TypeScript + Vite, Tailwind CSS 4, shadcn-style components on Base UI, Zustand, Tiptap (composer)
- Backend (Rust):
async-imap,lettre,tokio— connections are stateless: each command connects, works, and logs out - Storage: SQLite (tauri-plugin-sql), OS keychain-backed credential encryption, Rust-managed attachment cache
bun install
bun run tauri dev # run the desktop app in dev mode
bun run test # vitest (frontend unit tests)
cargo test # run inside src-tauri/ (Rust unit tests)
bun run build # typecheck + production frontend buildGmail uses Google's OAuth flow with your own free API client — no keys are bundled with the app, and nothing is shared with third parties:
- Open the Google Cloud Console and create (or pick) a project.
- Enable the Gmail API for that project (APIs & Services → Library).
- Configure the OAuth consent screen (APIs & Services → OAuth consent screen): user type External, add yourself as a test user.
- Create credentials: OAuth client ID → application type Desktop app.
- In Emailer: Add account → Gmail, paste the client ID, and sign in in the browser window that opens.
The app requests the https://mail.google.com/ and email scopes and
receives the OAuth callback on a local loopback listener
(http://127.0.0.1:17248). Tokens are stored encrypted on this machine
and never leave it except to talk to Google's API directly.
Microsoft 365 / Outlook.com accounts (work, school or personal — Outlook, Hotmail, Live) go through Microsoft Entra sign-in with your own free app registration — Emailer ships no bundled Microsoft app:
- In the Azure portal, register an app
(type "Accounts in any organizational directory and personal Microsoft
accounts") and add
http://localhost:17248as a redirect URI under the Mobile and desktop applications platform. No client secret is needed. - In Emailer: Add account → Microsoft 365 / Outlook.com, paste the Application (client) ID, and sign in in the browser window that opens.
- Work or school accounts may require admin approval for the registration — if sign-in reports that admin approval is needed, ask your IT administrator to grant it.
Tokens are sealed on this machine and auto-refreshed there; Outlook calendars connect separately from calendar settings through a second, calendar-scoped sign-in.
bun run dev:mock # http://localhost:3000Serves the UI in a plain browser against an in-memory SQLite (official
SQLite WASM) seeded with a realistic two-account mailbox — threads,
labels, drafts, contacts, search all work. Tauri-only surfaces are
stubbed: account add/OAuth flows and attachment downloads are disabled,
sync commands report healthy empty results, and sends file locally only.
An amber "MOCK DATA" pill marks the mode. The desktop app and production
build are unaffected (the mock wiring only activates in --mode mock).
UI conventions, design tokens, and the email-content style-isolation rules
live in docs/ui-guide.md. In-progress change plans and
task breakdowns live in openspec/ (local only, not committed).
The CSP keeps script-src 'unsafe-inline' deliberately: besides the resize
reporter inside the sandboxed email frame, next-themes (the theme provider)
injects a runtime inline script whose bytes come from minified library
internals — they cannot be pinned by a stable sha256 hash, and CSP3 ignores
'unsafe-inline' wherever a hash is present. Revisit if the theme provider is
ever replaced. See SECURITY.md for reporting vulnerabilities.




