PigeonPost
High concept: email that stays out of your way. A calm, local-first desktop client that does the
Thunderbird workflows people actually use, on a clean Go core with a small React shell, and nothing
phoning home. Your mail lives on your machine. Your passwords live in the OS keychain. One small
signed binary per platform.
0.4.0 — "Dialog crosses and brand polish"
Native-feeling polish on top of the 0.3.0 feature set.
New
- Close cross on every dialog. A window-style close cross sits in the top-right of every dialog
(About, Licence, Compose, Tags, Account setup and the confirmations), turning red on hover like the
Windows title-bar button. It complements the existing Cancel/Close buttons and click-outside-to-
dismiss. Implemented once as a sharedModalClosecomponent. - Brand mark on the primary background. A scaled-up PigeonPost icon now sits at the top-left of the
welcome screen (shown before any account is added) and at the top of the sidebar, so the empty
primary background is branded rather than blank. - Landing page screenshot. The GitHub Pages site (
docs/) now shows a real screenshot of the
account-setup screen in place of the placeholder.
Under the hood
- The UI's
Messagetype is decoupled from the generated WailsMessageDTO(data-only shape), so the
optimistic message updates keep compiling after awails generateregenerates the bindings with the
nested To/Cc converter. No behaviour change; it stops a recurring build break.
0.3.0 — "Drafts, offline, and safer reading"
The compose loop is finished, the client survives losing its connection, and the reader stops leaking
that you opened a message. All green: gofmt, vet, go test ./..., the 100% domain+application gate
(./test.ps1), and the full wails/frontend build.
New
- Save draft. Compose > Save draft appends the in-progress message to the account's Drafts mailbox
(IMAP APPEND, flagged\Draft \Seen). A draft may be incomplete (no recipients, empty body) since
you are still writing it. - Offline outbox. When the server is unreachable, sends and save-drafts are queued locally instead
of failing, and replayed oldest-first on the next sync. A header pill shows "N queued". Connection
failures are classified with anErrOfflinesentinel wrapped at the IMAP/SMTP dial; everything else
still surfaces as a real error. (Scoped to outgoing mail: mark/flag/delete/move are NOT queued
offline, see "Deliberately not done".) - Reply all. Addresses the sender plus everyone on the original To and Cc, dropping your own
address and any duplicates. Needed To/Cc stored on the cached message summary. - Remote image blocking. Remote
<img>sources are parked in a data attribute at fetch time so
images do not auto-load (auto-loading leaks that you opened the mail, plus your IP). A "Load images"
bar in the reader restores them on request; the block resets when you change message.
Under the hood
- Extracted the RFC 5322 MIME builder into a shared
internal/infrastructure/messagepackage so SMTP
send and IMAP draft-append use one builder instead of coupling the two adapters (100% covered). - New ports:
DraftSaver(IMAP APPEND) andOutboxStore(queue persistence). - Schema v5 adds the
outboxtable; schema v6 adds To/Cc columns to cached message summaries.
Migrations apply incrementally from the recordeduser_version. - Domain gained
NewDraftMessage(lenient),OutboxItem/OutboxKind, and To/Cc onMessageSummary. - 100% gate on domain + application held throughout; new infra covered by real-SQLite and mapping
tests.
0.2.0 — "You can actually use it" (developed; folded into the 0.3.0 release, never separately tagged)
The batch that turned the 0.1.0 skeleton into a real client. All on the working tree, all green.
New
- Account setup wizard. Two-step: provider grid (Outlook, iCloud, Yahoo, Fastmail, StartMail) plus
"set up manually", then a details form (server fields collapse when a provider is chosen). Add, edit
and remove accounts; per-account edit/delete in the sidebar. Verify-FIRST: credentials are proved
against the incoming server before anything is written, so a bad password leaves the keychain and DB
untouched. Edit with a blank password re-verifies with the existing keychain secret. - Message bodies. The full body is fetched on first open and cached (schema v3
message_body), so
a message reads offline after its first open. - Sanitized HTML rendering. The IMAP adapter parses MIME into plain + HTML and sanitises the HTML
(bluemonday UGCPolicy) so only safe markup enters the cache; HTML-only mail gets a derived
plain-text rendering. The reader renders the sanitised HTML and opens links in the external browser
(http/https/mailto only), never the app's own webview. - Coloured tags. Create/edit/delete tags with a fixed 10-colour palette; assign/unassign per
message; tag chips in the reader (schema v2tag+message_tag). Local to the cache for now. - Full-text search. A queryable FTS5 index (schema v4) kept in step with the message table;
debounced search box; ranked results replace the folder listing. Instant and offline. - Server-synced actions. Mark read/unread, star/flag, delete (move to Trash, else
\Deleted+
expunge) and move to another folder. Server-FIRST then cache, so a later sync preserves the change
rather than overwriting a local-only flag. Every destructive action confirms in a modal. - Rich-text compose. TipTap composer (bold, italic, strike, H2, lists, quote, link). Send builds a
multipart/alternativemessage (plain text first, HTML second) when an HTML body is present. - Reply and forward. Pre-fill the compose window with the recipient, a
Re:/Fwd:subject and the
quoted original, then the identical send path runs.
0.1.0 — Foundation
The foundation and the delivery shell. Not yet a daily driver (no account wizard), but the spine is in
and green.
Works
- IMAP sync: folders and message summaries pulled into a local SQLite cache, read offline.
- Three-pane UI: folder tree, message list, reader. Unread shows bold.
- Compose and send over SMTP (plain text, address validation).
- Mark read / unread.
- Dark theme by default, light mode toggle.
- Help menu: About (icon, author, copyright, OSS credits), Licence (full GPL-3.0), Check for Updates.
- Launch splash: icon, by Oliver Ernster, version.
- Passwords in the OS keychain, never in the DB.
Under the hood
- Clean architecture (domain / application / infrastructure / UI), enforced by structural tests.
- 100% coverage gate on domain + application.
- Bespoke per-user Go installer (Wails app: install/repair/upgrade/uninstall), plus wails build for the
exe. - GitHub Pages landing site drafted.