QuickMail v0.7.0 Release
Notes
Released June 8, 2026 — downloads for this release
Download
Two options are available for v0.7.0:
quickmail-v0.7.0-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.
New Features
Tabs and windows
Messages can now be opened in three ways, controlled by a new
Reading mode setting in Settings →
Windowing:
Reading Pane (default) — the original behavior. One
message at a time in the reading pane on the right. Nothing changes for
users who keep this setting.
Tab — each message you open gets its own tab in a
strip below the toolbar. Multiple messages can be open at the same
time.
Ctrl+Tab / Ctrl+Shift+Tab cycle through
open tabs.
Ctrl+1 through Ctrl+8 jump to tab N;
Ctrl+9 jumps to the last tab.
Ctrl+W closes the active tab.
Ctrl+Shift+`` (backtick) opens a tab list
overlay — a navigable list of all open tabs, similar to the
Alt+Tab switcher.
Ctrl+Shift+T focuses the tab strip itself for arrow-key
navigation.
- The Move Tab to New Window command (command
palette) detaches the active tab into a standalone window.
Window — each message opens in its own standalone
window. Useful when you want messages on a second monitor or open
side-by-side.
Regardless of the setting, Ctrl+Enter on any message always
opens a new window.
Message windows
Standalone message windows have a full set of navigation
controls:
- A Previous / Next toolbar moves through the
messages in the originating folder without going back to the main
window.
- F6 / Shift+F6 cycles focus through the toolbar,
header fields, and message body.
- Ctrl+Shift+P opens a command palette scoped to the
window: Previous Message, Next Message, Move to Main Window, Close
Window.
- Move to Main Window opens the message as a tab in
the main window’s tab strip and closes the standalone window.
- When a message window closes, focus returns to the originating row
in the main window’s message list.
- A loading indicator is shown while the message body
is fetching from the server.
Pane navigation refinement
With Ctrl+1–8 now doing double duty (pane
focus when no tabs are open; tab N when tabs are open), three new
always-reliable alternatives are registered:
Ctrl+Alt+1 |
Focus account list (works whether or not tabs are open) |
Ctrl+Alt+2 |
Focus folder tree (always) |
Ctrl+Alt+3 |
Focus message list (always) |
Ctrl+Shift+T |
Focus tab strip (when visible) |
Ctrl+1–3 continue to focus the panes when
no tabs are open, so existing muscle memory is preserved.
Accessibility
- Tab strip
AutomationProperties.Name is a short
label only. The previous value included the keyboard shortcut
instructions, violating the CLAUDE.md rule against embedding
instructions in names. The name is now "Open message tabs".
Shortcut instructions are delivered as a Hint-category
announcement the first time the tab strip receives keyboard focus.
- Message-open-mode radio buttons in the Settings
dialog now form a single tab stop with arrow-key navigation between
options, matching standard radio group behavior. Previously each radio
button was independently reachable with Tab.
- Role names removed from Settings tab labels. The
tab items in the Settings dialog previously appended “tab” to their
names (e.g., “General settings tab”), which caused screen readers to
announce “General settings tab tab.” The names are now “General
settings”, “Advanced settings”, “Keyboard shortcuts”, and “Windowing
settings”.
- Message window loading indicator uses
AutomationProperties.LiveSetting="Polite" so the “Loading…”
text is announced when the indicator appears.
- Message window F6 cycle is fully implemented:
toolbar → header fields → message body, with F6 relayed from inside the
WebView2 message body via the same postMessage mechanism used in the
main window.
- Message window command palette
(
Ctrl+Shift+P) surfaces all window-scoped actions for users
who prefer not to remember individual shortcuts.
- Tab strip close buttons are now
keyboard-accessible. When the tab strip has focus, Left/Right
arrows navigate between tab headers and their individual close buttons
(✕). Pressing Right from a tab header moves to that tab’s close button;
pressing Right again moves to the next tab header. Previously the close
buttons were only reachable with a pointing device.
Ctrl+W works from inside the message
body. The shortcut is now relayed from the WebView2 message
body back to WPF in both Tab mode (closes the active tab) and Window
mode (closes the window), so it is not necessary to move focus out of
the message to close.
Ctrl+W in Reading Pane mode closes the reading
pane. A new Close Message command
(Ctrl+W default) is registered for Reading Pane mode,
giving it consistent behavior across all three reading modes.
- Radio button selections in Settings are announced.
When the selected option changes in the Message Open Mode or Log Format
radio groups, the newly selected option is announced to screen readers.
WPF’s built-in
SelectionItemPatternOnElementSelected event
fires correctly but screen readers require a parent
ISelectionProvider container — which a plain StackPanel
does not provide — so the announcement is supplemented via the
AccessibilityHelper.Announce pathway.
- Log Format radio group on the Advanced tab now uses
single-tab-stop / arrow-key navigation, consistent with the Message Open
Mode group and standard radio group behavior.
- Tutorial overlay is hidden from the accessibility tree while
inactive. The overlay is placed over the main content area;
when not in use it was still reachable by screen reader virtual cursor
navigation. Setting
Visibility=Collapsed when inactive
removes it from the tree entirely.
Bug Fixes
Tabs and windows
- Message window Previous/Next navigation was always
disabled. The message list was not being populated when a
window opened, so the navigation buttons had nothing to navigate. The
window now receives the full message list from the originating
folder.
- Message window re-fetched the message body even when it was
already loaded. Opening a window from the main reading pane now
reuses the already-loaded message detail instead of making a redundant
IMAP request.
- Message window did not cancel in-flight IMAP loads when
closed or navigated. A
CancellationTokenSource now
cancels any active fetch when the window closes or when the user
navigates to a different message.
- Blank message tab when using Move to Main Window.
Using “Move to Main Window” in Window mode opened a tab that appeared
empty. Fixed by correcting the condition that gates message rendering in
tabs.
- Arrow keys in the tab strip activated a message
load. Moving between tabs with the keyboard triggered
OnActiveTabChangedAsync, which loaded the message body and
moved focus away from the tab strip. Arrow-key navigation now only
highlights tabs; the message loads when Enter or Space is pressed.
- Rapid tab switching could show stale message
content. A version stamp on tab activation prevents a slower
IMAP load started for an earlier tab from overwriting the content of a
tab the user has already moved on from.
Ctrl+Tab could land on the permanent Messages
tab. Cycling through tabs now skips the non-closeable Messages
sentinel and wraps through message tabs only.
- Switching from Tab mode left orphaned tabs visible.
Changing Reading mode to Reading Pane or Window now clears all open
message tabs, not just the sentinel, preventing a visible tab strip with
unrenderable entries.
- Focus was not restored to the message list when a message
window closed. The main window now scrolls back to the row that
was selected when the window opened.
- Sync guards and address-grab availability did not account
for messages open in windows. Commands that should remain
available while reading a message (
Grab Addresses,
sync-related guards) now check whether a message is open in a window,
not only whether the reading pane is visible.
- MessageListTabViewModel sentinel tab was missing.
In Tab mode, the tab strip was hidden when no message tabs were open,
stranding keyboard focus. A non-closeable “Messages” sentinel tab is now
always present in Tab mode so the strip stays visible and the focus
cycle remains intact.
- Reading pane stayed visible when a message opened in Window
mode. When Reading mode was set to Window, the reading pane was
not always cleared before the new window opened, leaving the previous
message visible in the background.
- Deferred selection update could reopen the reading pane in
Window mode. A background
SelectMessageAsync
completion could arrive after a Window-mode open was already in progress
and re-show the reading pane. Async version stamps now discard these
stale completions.
- Closing a tab moved focus to the reading pane instead of the
tab strip. After the active tab closed, focus jumped to the
message list or reading pane. Focus now stays on the tab strip, landing
on the next logical tab.
IMAP compatibility
- Delete and Empty Trash now work on Courier IMAP.
Special-use folder attributes (
\Trash, \Sent,
etc.) are not advertised by all IMAP servers. A name-based fallback now
classifies folders named “Trash”, “Sent”, etc. correctly without the
attributes, fixing folder detection, All Mail exclusion, delete, and
Empty Trash on Courier and other servers that omit these
attributes.
- Messages with malformed MIME parts now open. HTML
and plain-text body fetches now use separate try/catch scopes so a
message with malformed MIME entity headers opens with whatever body
parts could be fetched rather than failing to open entirely.
Startup
- Default saved view now appears at startup, not after
sync. When a default saved view is set, the app previously
loaded all mail into the All Mail view first, then switched to the
default view only after the full background sync completed (~20–40
seconds). The default view is now applied as soon as connections are
established (~4 seconds), so the correct view is shown throughout the
sync period.
Thank You to Contributors
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.
Code contributions: - CityDweller — Microsoft Graph
backend groundwork: IMailService refactoring, string MessageId
migration, backend router and feature gate scaffolding - Menelion — Windows installer
(Inno Setup) - serrebidev —
Pooled IMAP connections, virtualized folder picker, HTML rendering
improvements
Issues and feedback: - CityDweller - Dennisl123 - jaybird110127 - KE8UPE - paoscripts - serrebidev - slannon97 - sofquipeut - taylorarndt
Note: Others have made contributions through various social media
platforms that are not listed here yet.
Internal
MessageBodyHtmlBuilder — new shared static class
extracts all HTML rendering helpers (reader-mode detection,
sanitization, plain-text auto-linking, heavy-HTML stripping) from both
MainWindow.xaml.cs and MessageWindow.xaml.cs.
Previously the ~150-line render pipeline was duplicated verbatim in both
files.
MessageListTabViewModel — new sentinel VM for the
non-closeable “Messages” tab in Tab mode; extends
TabSessionViewModel with
CanClose = false.
TabSessionModel.TabKind gains a
MessageList variant for the sentinel tab.
MainViewModel.IsMessageOpenInWindow — new observable
property set when one or more standalone message windows are open;
guards that previously checked only IsMessageOpen now check
both.
- 449 tests, all green (one pre-existing clipboard-API failure in the
test runner environment is unrelated to this change).