The best GTK email client (for me at least :p)
- Joined Inbox across multiple accounts, adaptive three-pane layout.
- Gmail-style vim keybindings (
j/k,o,e,#,s, …). - HTML mail rendered with WebKitGTK.
- Compose in markdown with live inline styling and a rendered preview.
- Recipient autocomplete from people you have sent to and your GNOME address book.
- GOA integration + custom IMAP support.
-
Flatpak — for the sandboxed build, or
-
A local toolchain: Rust, plus GTK4, libadwaita, and WebKitGTK development files. On Fedora:
sudo dnf install gtk4-devel libadwaita-devel webkitgtk6.0-devel \ javascriptcoregtk6.0-devel libsoup3-devel
make flatpak # build + install
make run # ...or run the cargo crate
flatpak run tech.jptr.jmailmake flatpak runs the equivalent of:
flatpak-builder --user --install --force-clean --assumeyes \
--disable-rofiles-fuse --state-dir=.flatpak-builder build-dir tech.jptr.jmail.yamlmake run # = cargo run -p jmail-uiOther targets: make test, make mock, make clean, make help.
The cache lives at ~/.local/share/jmail/cache.db (local runs) or
~/.var/app/tech.jptr.jmail/data/jmail/cache.db (Flatpak).
Useful environment variables:
| Variable | Effect |
|---|---|
JMAIL_DEV_PLAINTEXT=1 |
Store passwords in the DB instead of the system keyring (dev). |
JMAIL_SEED=1 |
Insert demo accounts/messages on first launch. |
RUST_LOG=debug |
Verbose sync-engine and IMAP connect/auth logging. |
A mock IMAP server ships in the workspace (crates/jmail-mock-imap) with a
canned mailbox and live IDLE push — perfect for trying the app without a real
account. It also runs a companion SMTP server that captures anything the app
sends, so you can exercise compose/reply/drafts locally.
Start it from the repo root (plaintext, default IMAP port 1143):
cargo run -p jmail-mock-imapIt prints both listeners, e.g. Mock IMAP listening on 127.0.0.1:1143 and
Mock SMTP listening on 127.0.0.1:2525. The SMTP port is stable by default
(2525) so the account setting survives restarts — use it when adding the
account (see below).
cargo run -p jmail-mock-imap -- [--port N] [--smtp-port N] [--tls] [--push-after N]| Flag | Meaning |
|---|---|
--port N |
IMAP listen port N (default 1143). |
--smtp-port N |
SMTP listen port N (default 2525; 0 picks a free port). |
--tls |
Enable implicit TLS / STARTTLS with a self-signed cert. |
--push-after N |
After N seconds, inject a new Inbox message to exercise IDLE push. |
The demo mailbox has the folders INBOX, Sent, Drafts, Archive, Trash, Spam, Projects, with sample messages (including an HTML one) and reply messages.
Jmail does not run its own OAuth flow. It picks up the mail accounts already
configured in GNOME Online Accounts (the org.gnome.OnlineAccounts session
service, usually driven from Settings → Online Accounts):
- On every launch — and whenever the window regains focus — the system accounts are reconciled into the local cache. Newly discovered accounts are enabled and synced automatically; a user's enable/disable choice is preserved.
- OAuth2 accounts (e.g. Google) authenticate with SASL XOAUTH2 using an
access token fetched from
goa-daemon; password accounts (the GOA IMAP/SMTP provider) read their password the same way. Jmail never stores those secrets. - Each GOA account has a switch in Settings → Accounts to disable it: its folders and mail are hidden and syncing pauses, without touching the system account (re-enabling restores them).
Jmail never modifies GOA accounts. The first-run welcome dialog offers a button that opens the system Online Accounts settings when nothing is configured yet.
GOA is officially aimed at GNOME core applications; third-party access works today but is not a guaranteed interface.
The To/Cc/Bcc fields suggest addresses from two places:
- People you have sent mail to — read from the cached Sent folders and ranked by how often and how recently you used them.
- GNOME address books — read (read-only) from Evolution Data Server over D-Bus. Only cards with an email address appear; this can be switched off in Settings → Composing.
Suggestions update as you type. Use ↑/↓ and Enter/Tab to pick one, or
Escape to dismiss. Opening a composer asks the sync engine to check the Sent
folder for new headers (at most every two minutes), so mail sent from another
device shows up without restarting Jmail. Contact data stays in memory and is
never written to the mail cache or logs.
In the Flatpak sandbox this needs the EDS Sources5, AddressBook10 and
Subprocess.Backend.* talk-name permissions, which are already part of the
manifest.
-
Launch the app.
-
Open Settings (
Shift+,) → Accounts → Add. -
With the mock server running, fill in:
Field Value Name Mock(anything)Email you@example.comIMAP server 127.0.0.1Port 1143Security NoneUsername you@example.comPassword hunter2SMTP server 127.0.0.1SMTP port 2525(the mock's default; change if you passed--smtp-port)SMTP security None -
Click Add Account. The dialog first checks that IMAP (and SMTP, if you filled in an SMTP server) accepts the settings; only then is the account saved. The engine syncs folders and the Joined Inbox fills. Select a message to preview it; the body is fetched on demand.
Test runs the same check without saving. Save refuses to persist an account whose servers reject the connection. If a server presents a certificate that cannot be verified, you are asked to confirm before it is accepted for that account (stored as accept invalid certificates, only for that account).
Custom accounts added this way can be revised later with Edit on the account row (GOA accounts instead have an enable switch).
In the Flatpak sandbox
127.0.0.1is the host loopback, so the mock server running on your machine is reachable.
To verify live push, start the server with --push-after 15; a new Inbox
message ("Live push while you idled") arrives without any interaction.
If mail looks stale — or after changing the mock demo data — open
Settings → Advanced → Force resync. This deletes the cached mail for every
account and re-fetches all folders from the server (SyncCommand::Rebuild).
Message bodies are cached, so this is also how to pull an updated body for a
message you have already opened.
| Key | Action |
|---|---|
j / k |
Next / previous message |
o / Enter |
Open conversation in a new window |
click |
Preview in the reading pane |
c |
Compose |
r / a / f |
Reply / reply all / forward (inline, at the bottom of the conversation) |
e |
Archive |
# |
Delete |
s |
Star |
Shift+I / Shift+U |
Mark read / unread |
/ |
Search |
g then i/t/d/a |
Jump to Inbox / Sent / Drafts / All |
Shift+, |
Settings |
? |
Keyboard shortcuts |
cargo test -p jmail-core # unit + integration tests (uses the mock server)
cargo build -p jmail-uiSee TODO.md for the roadmap and current status.