QuickMail v0.7.0 Release Notes
Download
Two options are available for v0.7.0:
| Download | When to use |
|---|---|
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+Tabcycle through open tabs.Ctrl+1throughCtrl+8jump to tab N;Ctrl+9jumps to the last tab.Ctrl+Wcloses 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+Tfocuses 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:
| Shortcut | Action |
|---|---|
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.Nameis 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 aHint-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+Wworks 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+Win Reading Pane mode closes the reading pane. A new Close Message command (Ctrl+Wdefault) 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
SelectionItemPatternOnElementSelectedevent fires correctly but screen readers require a parentISelectionProvidercontainer — which a plain StackPanel does not provide — so the announcement is supplemented via theAccessibilityHelper.Announcepathway. - 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=Collapsedwhen 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
CancellationTokenSourcenow 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+Tabcould 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
SelectMessageAsynccompletion 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:
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 bothMainWindow.xaml.csandMessageWindow.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; extendsTabSessionViewModelwithCanClose = false.TabSessionModel.TabKindgains aMessageListvariant for the sentinel tab.MainViewModel.IsMessageOpenInWindow— new observable property set when one or more standalone message windows are open; guards that previously checked onlyIsMessageOpennow check both.- 449 tests, all green (one pre-existing clipboard-API failure in the test runner environment is unrelated to this change).