README.md

spark-rs

A personal, Spark-style email client with a Rust core. First target: Windows on ARM (aarch64-pc-windows-msvc).

Created in T3 Code.

Accounts

Settings (Ctrl+,) → Accounts → Add an account. Until the first account is added the app shows a demo mailbox.

Mail is stored in mail.sqlite in the app's local data folder (%LOCALAPPDATA%\dev.sparkrs.desktop on Windows). Passwords and Microsoft sign-ins are kept in Windows Credential Manager under spark-rs, never in files. Removing an account deletes its local mail and saved sign-in; nothing is deleted on the server.

Gmail. Google requires an app password for mail apps: turn on 2-Step Verification, create one at https://myaccount.google.com/apppasswords, then choose Gmail and enter your address and the 16 letters. spark-rs uses imap.gmail.com:993 and smtp.gmail.com:465 and checks the login before saving.

Microsoft 365 (work or school). This needs an app registration in your organization's Microsoft Entra tenant (https://entra.microsoft.com → App registrations → New registration). If you can't register apps, ask IT:

  • Supported account types: this organizational directory only.
  • Platform: Mobile and desktop applications, redirect URI http://localhost (any port matches; spark-rs picks a free one).
  • API permissions, Microsoft Graph, delegated: User.Read, Mail.ReadWrite, Mail.Send, offline_access. If your tenant requires admin consent, IT has to grant it.
  • No client secret: desktop apps are public clients.

Then choose Microsoft 365 and enter the Application (client) ID and the Directory (tenant) ID, or your domain such as contoso.onmicrosoft.com. Your browser opens Microsoft's sign-in; when it's done the account appears. Check your company's rules first: using your own client on work mail, and sending work mail to an AI provider for summaries, may not be allowed.

Other IMAP servers. Choose Other (IMAP) and enter the servers. Ports 993 and 465 use TLS from the start; 143 and 587 use STARTTLS.

What syncs: the inbox (the newest 300 messages on Gmail/IMAP, the last 30 days on Microsoft 365), checked every two minutes and on demand. Done, Delete, read and pinned go back to the server after the 6-second undo window; Done archives (All Mail on Gmail). Snooze, Set Aside, Priority and new-sender screening stay on this computer.

Attachments download when you open or save them, also from archived mail. Program files (.exe, .js, .lnk and the like) can only be saved, not opened, and downloaded files are marked as coming from the internet, so Office opens them in Protected View. Attach files with the paperclip, Ctrl+Shift+A, or by dropping them on the window; forwards keep the original's attachments. Messages over 10 MB are stored without their body or file list.

Notifications and the tray

Closing the window leaves spark-rs running in the notification area, still syncing; click its icon to bring the window back, or right-click it to check for mail or quit. New mail shows a Windows notification with the New Mail sound, and clicking one opens the message. By default only mail from people notifies (Spark's smart notifications); newsletters, notifications, mail from new senders waiting in the Gatekeeper, and an account's first sync stay quiet, as does anything arriving while the window is in front. Settings → Notifications changes this, turns the sound off, stops closing to the tray, or opens spark-rs in the background when you sign in to Windows.

Starting spark-rs again while it runs brings the running window forward.

Layout

1crates/store SQLite storage: accounts, messages, outbox (bundled SQLite with FTS5)
2crates/mail IMAP/SMTP and Microsoft Graph: sync, sending, Microsoft sign-in
3crates/ai bring-your-own-key AI client (Anthropic, OpenAI-compatible)
4apps/cli spark-cli, the headless dev tool
5apps/desktop desktop app UI: React + Tailwind + daisyUI (Vite)
6apps/desktop/src-tauri desktop app shell (Tauri 2): accounts, sync workers, demo mailbox
7tools/cross Docker image for building Windows binaries on Linux

Building

Everything builds in a Docker image, so the host needs nothing besides Docker. The first run builds the image (a few minutes). On the first Windows build, cargo-xwin downloads the MSVC CRT and Windows SDK (about 5 GB, cached in ~/.cache/spark-rs-cross); using those means accepting Microsoft's license terms for them.

sh
1# Desktop UI first (Node on the host): spark-desktop embeds apps/desktop/dist
2# and doesn't compile without it
3(cd apps/desktop && npm install && npm run build)
4(cd apps/desktop && npm run dev) # UI alone in a browser at localhost:1420, demo data
5
6# Linux: lint, test, run
7tools/cross/run.sh cargo clippy --workspace --all-targets -- -D warnings
8tools/cross/run.sh cargo test --workspace
9tools/cross/run.sh cargo run -p spark-cli -- doctor
10
11# IMAP/SMTP end-to-end test against GreenMail (setup in crates/mail/tests/greenmail.rs)
12SPARK_CROSS_DOCKER_ARGS='--network spark-test -e SPARK_TEST_GREENMAIL=spark-greenmail' \
13 tools/cross/run.sh cargo test -p spark-mail --test greenmail
14
15# Windows on ARM
16tools/cross/run.sh cargo xwin build --release --target aarch64-pc-windows-msvc -p spark-desktop -p spark-cli
17# → target/aarch64-pc-windows-msvc/release/{spark-desktop,spark-cli}.exe

spark-desktop.exe is a single file with the UI embedded; it needs the WebView2 runtime, which Windows 11 includes. On the Windows machine, spark-cli.exe doctor checks that SQLite, TLS and networking work there.

Natively on Windows ARM64

On an ARM64 Windows machine you can skip Docker. You need rustup, Node, Visual Studio Build Tools 2022 with the MSVC ARM64 build tools, and clang-cl: aws-lc-sys won't build with MSVC's cl on ARM64. Either install LLVM (winget install LLVM.LLVM) or add the C++ Clang Compiler for Windows component to the Build Tools. tools\win-arm64\cargo.cmd runs cargo in the ARM64 build environment with clang-cl; it finds cargo in %USERPROFILE%\.cargo\bin and LLVM in its default folder when they aren't on PATH.

From the repo root, in cmd or PowerShell:

1cd apps\desktop
2npm install
3npm run build
4cd ..\..
5tools\win-arm64\cargo.cmd clippy --workspace --all-targets -- -D warnings
6tools\win-arm64\cargo.cmd test --workspace
7tools\win-arm64\cargo.cmd build --release -p spark-desktop -p spark-cli

The binaries land in target\release\.

For the GreenMail test without Docker, run the standalone jar with Java 17+ (java -Dgreenmail.setup.test.all -Dgreenmail.hostname=127.0.0.1 -Dgreenmail.auth.disabled -jar greenmail-standalone-2.1.5.jar, from Maven Central) and set SPARK_TEST_GREENMAIL=127.0.0.1 before cargo.cmd test.

TLS uses rustls with the aws-lc-rs backend. Don't switch it to ring: ring's build forces plain clang on ARM64 Windows, which fails with cargo-xwin's MSVC-style flags.