Released June 27, 2026 — downloads for this release
Two options are available for v0.7.7:
| Download | When to use |
|---|---|
quickmail-v0.7.7-setup.exe — Windows
installer |
Recommended for most users. Installs per-user with no elevation required, checks for the WebView2 Runtime, and registers an uninstaller. |
QuickMail.exe — standalone portable
executable |
No installation required. Copy it anywhere and run. |
Both downloads include the .NET 8 runtime — you do not need to install .NET separately.
QuickMail now checks for a newer release on startup, and an update entry is always present at the top of the Help menu so you have a reliable way to check.
The startup check runs quietly in the background; it never delays startup, and when you are already on the latest version it stays silent rather than announcing on every launch. This is what will let you know when fixes like the connection improvement below are available, without having to check manually.
Accounts were frequently dropping their connections with a “Server shutting down” response from the server, then reconnecting, then dropping again — repeating every minute or two. This affected all accounts simultaneously, including accounts on different servers.
The root cause was the startup sync introduced in v0.7.6, which parallelized syncing across all accounts at once. When two or more accounts share the same IMAP server — common when multiple addresses are hosted on the same provider — the parallel sync opened simultaneous connections to that server and exceeded its per-IP connection limit. The server responded by terminating connections, which also took down the IDLE watchers responsible for new-mail notification.
Accounts on the same IMAP server now sync sequentially, so only one sync connection at a time is active per server. Accounts on different servers continue to sync in parallel, preserving the startup speed improvement from v0.7.6.
This release also adds several resilience measures around the same area, so a brief server hiccup no longer turns into a repeating disconnect cycle:
On the very first Shift+F10 keypress after launching QuickMail, the Windows system menu (Restore, Move, Size, Minimize, Maximize, Close) may appear instead of the QuickMail context menu. All subsequent presses in the same session work correctly.
Workaround: Press Shift+F10 a second time. After the first press, the behaviour is correct for the remainder of the session.
The root cause is a startup-timing issue: WebView2 initialization can
claim Win32 focus before WPF’s first focus-restoration pass completes.
When Shift+F10 arrives while Keyboard.FocusedElement is
null, WPF has no element to route ContextMenuOpening from
and falls through to DefWindowProc, which shows the system
menu. (#148)
When sending from an iCloud account, two identical copies of each sent message may appear in the Sent Messages folder. iCloud’s SMTP server saves a copy automatically when relaying the message; QuickMail also appends a copy after a successful send.
Impact: Cosmetic only. Both copies are identical and no mail is lost.
Planned fix: Before appending, search the Sent
folder for a matching Message-ID and skip the append if a
copy already exists. (#150)
Thank you to everyone who has contributed to QuickMail through code, bug reports, feature suggestions, and other feedback. Your contributions make the project better for everyone.
When an IDLE watcher loses its connection, the log now includes the
full exception chain — type, message, and (for socket-level failures)
the SocketError code and native error code. Previously only
ex.Message was logged, which collapsed the chain and
omitted the socket error code needed to distinguish a server-initiated
disconnect from a network timeout. The account username now appears in
error lines instead of the internal account GUID. Session elapsed time
is also recorded in debug mode, making it straightforward to correlate
how long a connection was alive before it failed.
(LogService.FormatException,
ImapMailService.RunIdleWatcherAsync)
A review of the connection code following the disconnect fix produced several hardening changes beyond the sync-ordering fix:
ImapMailService.RunIdleWatcherAsync) and the
startup connection retry backoff
(MainViewModel.ConnectOneAccountAsync) apply ±30% jitter.
When a server terminates every connection at once, retries previously
fired on the identical schedule and reconnected in lockstep, which could
re-trip the per-IP connection limit that disconnected them.MainViewModel.ConnectAllAccountsAsync now groups accounts
by IMAP host so same-host accounts connect sequentially, matching the
grouping SyncService.SyncAllAccountsAsync applies during
sync.GoogleOAuthService’s in-memory credential cache is now a
ConcurrentDictionary; it is read and written concurrently
by IDLE watcher threads and pooled IMAP/SMTP operations, where the
previous plain Dictionary could race under
read-during-write.delaySeconds
declaration in ConnectOneAccountAsync; corrected the
periodic-NOOP heartbeat comment to describe its actual behavior.A larger structural follow-up — a per-host connection cap that also accounts for IDLE watcher connections — is tracked in #152 for a future release.
The startup update notification is implemented by
UpdateCheckService (IUpdateCheckService),
which queries the GitHub Releases API with HttpClient +
System.Text.Json (no new dependencies, 10-second timeout,
debug-level logging on failure). It holds an internal
CancellationTokenSource that is cancelled before disposal
so an in-flight request on app exit is cancelled cleanly rather than
relying on the HTTP timeout or throwing
ObjectDisposedException. The reflected assembly version is
cached in a static field. (#151)
The Help-menu entry is always present:
UpdateAvailableText defaults to “No updates available” and
the entry binds to OpenUpdatePageCommand, which opens the
specific release when one is known (UpdateReleaseUrl
non-empty) or the general releases page otherwise. The startup check
(CheckForUpdateInBackgroundAsync) updates the entry’s text
and stays silent when up to date (announcing only a found update). The
status-bar update button’s visibility tracks
UpdateReleaseUrl so it appears only when an update actually
exists.