Run the desktop app
A native desktop client for reading, searching, and managing your local archive. Built with Tauri 2 + Svelte 5; runs on macOS, Linux, and Windows.
How the pieces fit together
The desktop app does not talk to Postgres directly.
It talks HTTPS to a localmail serve process that you run
locally (or on a LAN host). That gives you:
- A clean network boundary you could expose to a phone over Tailscale.
- Per-user account ACLs — give your spouse an account that only sees the shared family inbox, for example.
- The same HTTPS API other clients speak — including the
MCP server for AI agents, mounted in
the very same
localmail serveprocess.
┌─────────────┐ HTTPS ┌─────────────────┐ pg ┌─────────┐
│ Desktop app │ ─────► │ localmail serve │ ───► │ Postgres│
└─────────────┘ └─────────────────┘ └─────────┘
▲
│ same DB, separately
│
┌──────┴──────┐
│ localmail │ IMAP IDLE / poll
│ run (daemon)│ ────► your mail providers
└─────────────┘
Set up the server
-
Generate a TLS cert.
The server speaks HTTPS by default. For localhost / LAN use a self-signed cert is fine — the app supports a trust-on-first-use pinning flow.
localmail rotate-tls \ --cert ~/.config/localmail/tls.crt \ --key ~/.config/localmail/tls.keyLocalhost-only?If you'll only ever connect from the same machine, you can run with
--no-tls --bind 127.0.0.1and skip the cert step. TLS is refused for any non-loopback bind without a cert. -
Create an API user.
The desktop app authenticates with a username + password (which the server stores as an argon2id hash). The password is yours to pick; there's no link to your IMAP credentials.
localmail add-api-user alice -
Grant the user access to one or more accounts.
By default, a new API user has access to no accounts and every API call returns empty lists. You explicitly grant access per (user, account) pair:
localmail grant-account alice horst-gmail localmail grant-account alice work-fastmail localmail list-api-users --with-grants -
Start the server.
localmail serve \ --bind 127.0.0.1 --port 8443 \ --tls-cert ~/.config/localmail/tls.crt \ --tls-key ~/.config/localmail/tls.keyFor an always-on setup, wrap this in a systemd / launchd unit the same way you did the daemon — see the Daemon page for templates. The two processes are independent:
localmail runmirrors mail;localmail serveserves it.
Install and run the desktop app
Pre-built bundles are produced from the gui/ directory
of the repository. Until the project ships signed installers, the
quickest path is to build from source.
Build prerequisites
| Platform | What you need |
|---|---|
| macOS | Xcode command-line tools (xcode-select --install);
WebView ships with the system. |
| Linux | sudo apt install libwebkit2gtk-4.1-dev build-essential
curl wget file libssl-dev libayatana-appindicator3-dev
librsvg2-dev (Debian/Ubuntu) or distro equivalents. |
| Windows | WebView2 (pre-installed on Windows 11; runtime installer on older). |
| All | Node.js 20+, npm, Rust 1.80+ via rustup. |
Build & run
git clone https://github.com/hherb/localmail
cd localmail/gui
npm install
npm run tauri dev # development window with hot reload
# Or build a release bundle:
npm run tauri build
# Output in src-tauri/target/release/bundle/
First-run flow inside the app
-
Connect.
The app opens to a Connect screen pre-filled with
https://localhost:8443. Adjust if your server is elsewhere, then click Connect. -
Trust the certificate (once).
For a self-signed cert, the app shows you the SHA-256 fingerprint of the cert it just saw. Compare it with the fingerprint
localmail rotate-tlsprinted, then click Trust this certificate. The app pins it; future connects don't ask again unless the cert changes.Fingerprint mismatchIf you ever see the trust dialog when you weren't expecting it, the cert changed. Either you regenerated it (fine — re-trust), or someone has interposed themselves between the app and the server. Verify out-of-band before clicking trust.
-
Sign in.
Enter the username and password you set with
add-api-user. The app gets back a bearer token, stores it locally, and uses it on every subsequent request. -
Browse and search.
The header shows the accounts you've been granted access to. The search bar talks to the same hybrid retriever the
localmail searchCLI uses, with the same DSL — operators, dates, languages, attachments.
What the app can do today
- List accounts and folders.
- List, read, and full-text search messages.
- Inspect headers, decoded body (plain and HTML), and the
messages.attachmentsJSONB metadata. - Download attachments by SHA-256.
- Tail recent changes via the
/v1/changesstream.
What the app does not do
- Send mail. localmail is read-only with respect to upstream.
- Delete or modify messages on the IMAP server.
- Manage accounts or users — that's the job of the admin web UI and the CLI. The desktop app is a read-only mail client.
Connecting from another machine
For phone, tablet, or another laptop on your LAN:
- Re-issue the TLS cert with a hostname covering the other
machine —
localmail rotate-tls --cert … --key … --hostname localmail.local --force. - Run
localmail servebound to a reachable address —--bind 0.0.0.0, or a Tailscale / WireGuard IP. - From the client device, point the app at
https://localmail.local:8443and trust the new fingerprint.
There's no native mobile app yet. The HTTPS API is documented and stable, so a third-party client is possible. Watch the project repository for updates.