Releases: maathimself/mailflow
Release list
v2.1.0
What's new in v2.1.0
Features
- OIDC group claim → admin role mapping (#190) — SSO providers can now grant or revoke admin access automatically via a group claim in the JWT. Configure the claim name and expected value in Settings → SSO.
- Custom CSS (#191) — Inject your own CSS from Settings → Appearance to personalise the interface beyond the built-in themes.
- Mark-as-read behaviour (#195) — Choose when messages are marked as read: immediately on open, after a configurable delay (1–10 seconds), or never automatically. Configurable in Settings → Appearance → Layout.
- Sender avatars (#197) — Contact photos from CardDAV-synced contacts now appear as avatars in the message list, falling back to the existing initials circle when no photo is available.
Fixes
- Select button on desktop (#194) — The bulk-select button was missing from the message list header on desktop; it now appears alongside the other header controls.
- Inbox refresh delays — Deleting a message now immediately broadcasts a folder update, eliminating the lag before the list refreshed. iOS warm-start stale state is also resolved via a visibility change listener.
- AI private IP hint (#192) — A clearer hint is shown when the AI base URL points to a private IP that requires
ALLOW_PRIVATE_HOSTS=true.
v2.0.2
Bug Fixes
-
Drafts: Clicking "Save Draft" now keeps the compose window open and shows a confirmation toast instead of closing. The window only closes when saving from the discard dialog.
-
Drafts: Sent and discarded drafts are now removed from the Drafts folder immediately. Previously the stale entry lingered until the next background sync (up to 10 minutes).
-
Drafts: Closing compose after a keep-open save no longer re-prompts to save. The dirty state now correctly resets after each save, including for CC/BCC fields, forwarded attachments, and uncommitted recipient input.
-
Message list: Preview snippets no longer show `[image: alt text]` placeholders for image-heavy emails. The plain-text alternative body is stripped of these placeholders, with fallback to the HTML body if the entire text part consists of image tags.
-
Unsubscribe: One-click unsubscribe state is now persisted to the database so the unsubscribe banner does not reappear after reloading. Failures are surfaced to the user rather than silently ignored. A "Move to trash" action is offered in the confirmation toast.
-
Mobile: Wide HTML emails no longer overflow the message pane on small screens.
-
Sync: Eliminated a spurious "Message sync phase 2 skipped" log warning caused by a stale sequence range when a move or delete arrived concurrently during an IDLE sync."
v2.0.1
What's new in v2.0.1
This is a patch release with mobile UI fixes.
Mobile fixes
- Settings tab bar now shows a gradient overflow indicator when there are more tabs to the right, and hides it automatically when scrolled to the last tab (#185)
- Sidebar bottom section (profile, settings, sign out) is now collapsible on mobile — tap your name to expand or collapse, keeping the sidebar compact by default (#186)
Security
window.opencalls for mailto: links now consistently passnoopener,noreferrerto prevent the opened tab from holding a reference back to the app
Upgrading from v2.0.0: pull the new image and restart — no database migrations or configuration changes required.
Upgrading from v1.x: four additive database migrations run automatically on first startup (spam training log, password reset tokens, message categories, and list-unsubscribe columns). All are idempotent and non-breaking. See the v2.0.0 release notes for the full list of changes since v1.x.
v2.0.0
What's new in v2.0.0
Email categorization
- New inbox tabs: Primary, Newsletters, Social, Notifications, and Other automatically sort incoming mail by type using header detection and sender heuristics
- Unified inbox view shows all mail across tabs
- AI-powered classify button reclassifies a message when the automatic detection gets it wrong
- Unsubscribe button appears directly in the message pane for detected newsletters — one click sends the unsubscribe request or opens the unsubscribe URL
AI assistant
- Integrated AI assistant powered by any OpenAI-compatible provider (configure your own endpoint and API key in admin settings)
- Summarize long email threads, draft replies, and ask questions about a message
- AI assist button added to the mobile compose toolbar
- AI tab in admin settings is clearly marked Beta
Spam feedback (v0.1)
- Mark any message as spam or not spam from the context menu, message pane toolbar, or bulk actions
- Feedback is stored and will feed into automated filtering in a future release
- Available in all 7 supported languages
Password recovery
- Users can now recover their account via a recovery email address set in profile settings
- Three-tier SMTP fallback ensures delivery even when the primary sending account is misconfigured (#176)
Compose improvements
- Image resize handles in the rich-text editor (#182)
- Pasting Excel tables now converts them to HTML tables (#182)
Todoist integration
- Tasks created from emails now include a deep link back to the original message (#180)
Mark as unread
- Mark messages as unread from the message pane toolbar and the mobile action menu (#183)
Security hardening
- TOTP replay prevention: one-time codes can no longer be reused within their validity window
- SSRF improvements: IMAP host validation now resolves DNS and blocks 6to4 and Teredo IPv6 tunnel addresses that embed private IPv4 ranges
- CSS exfiltration prevention: external
url()references in email<style>blocks are stripped at sanitization time - Password reset race condition: the token is now consumed atomically so two concurrent reset requests cannot both succeed
- Signature sanitization: edited signatures are sanitized on send and draft save, not only at storage time
- AI and subscription URL validation: custom AI base URLs and category subscription URLs are now validated through the same SSRF-safe host validator used for IMAP
- Encryption key guard: the server now refuses to start and throws on encrypt rather than silently storing plaintext if
ENCRYPTION_KEYis missing - Microsoft 365 id_token issuer validation: multi-tenant OAuth flows now verify the
issclaim matches the tenant in the token - Trusted device cookie cleared on logout
- Security headers:
X-Frame-Options: DENYandReferrer-Policy: same-originadded to all responses - Double-send prevention: idempotency key support on the send endpoint prevents duplicate emails on network retry
Reliability improvements
- Database migrations: all migrations are now idempotent (
IF NOT EXISTS) and run without a statement timeout so large deployments don't fail mid-migration - IMAP connection leak fix: failed sync attempts now correctly close and remove the stale connection instead of leaving zombie TCP sockets
- WebSocket broadcast isolation: a failing client socket no longer aborts delivery to other connected clients
- Inbox rules N+1 fix: folder resolution for delete and archive rules is now cached across the message batch instead of re-queried per message
- Shared Redis client: session store, TOTP replay prevention, and send idempotency now share a single Redis connection
Upgrade notes
- No manual migration steps required. All schema changes apply automatically on first startup.
- If you are running without
ENCRYPTION_KEYset, the server will now refuse to start rather than silently degrading. SetENCRYPTION_KEYto a 64-character hex string (openssl rand -hex 32) before upgrading.
v1.9.2
Bug fixes
- Todoist: due date not saved — Dates selected in the date picker were silently ignored. The backend was not updated when the frontend switched from the free-text
due_stringfield todue_date; the fix passes the ISO date through to the Todoist API correctly. - Todoist: "Open in Todoist" opened a blank tab — The Todoist REST API v1 does not include a task URL in its response. The URL is now constructed from the task ID (
https://app.todoist.com/app/task/<id>) and returned alongside the task, so the notification link opens the correct task directly.
v1.9.1
Bug fixes
- Todoist:
crypto.randomUUIDerror on task creation — Fixed a JavaScript exception thrown after successfully creating a Todoist task when MailFlow is served over HTTP (non-secure context). The task was created successfully but the error was surfaced to the user. A safe fallback is now used in environments wherecrypto.randomUUIDis unavailable. - Todoist: due date field replaced with date picker — The due date input was previously a free-form text field. It is now a native date picker, consistent with user expectations.
- Todoist: integration icon updated — The toolbar and modal now display the recognisable Todoist logo instead of a generic checkmark icon, making the button immediately identifiable.
v1.9.0
New features
- Two-factor authentication — TOTP (authenticator app), email OTP, and persistent device trust. Admins can set enforcement policy (off / required) and trust duration (7 days, 30 days, permanent, or never) in the admin panel.
- Todoist integration — link a Todoist account from the admin Apps tab. Create tasks directly from emails via the message toolbar.
- Composer font groups and email priority — choose font family groups in the composer and set message priority (low / normal / high / urgent).
- Improved mobile compose UX — cleaner field layout and simplified toolbar for composing on mobile.
Fixes
- Wide fixed-layout HTML emails no longer clip on mobile — content is scaled to fit the viewport.
- Mark-as-read now fires immediately on tap rather than waiting for the synthesized click event, closing the window where a fast back-swipe could race against the state update.
- Mark-as-read is retried once on network failure before reverting, reducing spurious "still unread" appearances on unreliable mobile connections.
- Resolved ghost touches and scrambled gesture recognition in the mobile message list after rapid swiping.
- Fixed an edge case where thread resolution could overwrite the optimistic mark-as-read update before the API call completed.
- Back swipe no longer exits the PWA context on iOS standalone mode.
- Todoist connection status now syncs correctly on app load.
- Message toolbar cleaned up — icon-only buttons with tighter spacing.
Performance
- Div-renderer utilities (PostCSS, CSS scoping) are now lazy-loaded and excluded from the main bundle when the div renderer is disabled.
Upgrade notes
- Two database migrations run automatically on startup (
0019_user_integrations,0020_mfa_device_trust). No manual steps required. - 2FA is off by default. Existing users are not affected unless an admin enables enforcement under Settings → Security.
- One new optional environment variable:
VITE_EMAIL_DIV_RENDER(defaultfalse). The div-based renderer is experimental — do not enable in production.
v1.8.0
What's new in 1.8.0
Contacts
MailFlow now has a full contacts manager, accessible from the sidebar.
- Create, edit, and delete contacts with name, email addresses, phone numbers, organization, and notes
- Search across all contact fields including secondary emails and phone numbers
- Contacts are automatically learned from people you send mail to and from inbound senders, and ranked by how frequently you correspond with them
- Auto-learned contacts are promoted to full contacts when you edit them
- Type labels (work, home, mobile, etc.) are localized in all supported languages
CardDAV sync
MailFlow now includes a CardDAV server compatible with Apple Contacts, Thunderbird, DAVx⁵, and other CardDAV clients.
- Sync URL:
https://your-instance/carddav/ - Auto-discovery supported via
/.well-known/carddav - Full vCard 3.0 support with ETag-based conflict detection
Settings
- New search function in the settings panel to quickly find any setting
- Settings sidebar reorganized into logical groups
- Search labels are now fully translated
Other improvements
- Bulk and newsletter senders are excluded from autocomplete so frequent senders stay at the top (#168)
- Thread read state now syncs to the parent row in real time when individual messages within a thread are marked read (#162)
- Selecting multiple messages and marking them read now works correctly (#174)
- Manual reindex now runs
refreshBulkFlagsas a background job so it does not block the response (#168)
Bug fixes
- Contact display names are no longer overwritten on every send for manually edited contacts
- Contacts panel correctly closes when navigating to an account or folder
- Stale error banners no longer appear when switching between contacts
- Contacts page state is preserved when navigating away and back
- CardDAV well-known redirect upgraded from 301 to 308 to preserve request methods
Upgrade notes
Managed PostgreSQL users: Migration 0018 enables the
pg_trgmextension for faster contact search. If your database user does not have superuser privileges (e.g. RDS, Supabase, Neon), runCREATE EXTENSION IF NOT EXISTS pg_trgm;as a superuser before upgrading, or the migration will fail.
v1.7.3
New Features
- Text highlight color — The compose toolbar now has a highlight color picker (distinct from text color) for marking up email content with background colors. Includes a "remove highlight" swatch to clear applied colors. (#172)
- Sent replies in threads — Replies you send now appear inline in conversation threads and update live without a page refresh.
- Smart contact autocomplete — Recipients you send mail to are automatically learned and ranked higher in autocomplete suggestions. (#168)
Bug Fixes
- Mobile: Cc/Bcc toggle buttons — The Cc and Bcc toggle buttons were cramped inside the To field row on mobile; they now appear in their own dedicated row below it. (#171)
- Mobile: message headers screen — The View Headers screen is now a full-screen overlay on mobile with headers broken out into individual labeled rows, making them readable on narrow displays. (#173)
- Mobile toolbar — Print and View Headers are now tucked into the overflow menu on mobile to avoid crowding the toolbar. (#170)
- Sidebar: INBOX subfolder nesting — Subfolders of INBOX now nest correctly in the sidebar when the INBOX row is not yet present. (#169)
v1.7.2
Bug Fixes
- Email preview snippets: Fixed a regression where snippet text in the message list could show garbled content — raw HTML entities (
&,…, etc.) or Markdown link syntax ([label](url)) from ESPs like Klaviyo that generatetext/plainby converting HTML anchors to Markdown. All snippet-building paths now share a single canonical function with consistent entity decoding and link stripping. - Message deletion: Fixed missing undo timer bar when deleting a message from the reading pane (the bar was only showing when deleting from the list).
- IMAP sync: Fixed an unhandled error when the server rejects an invalid message-set during sync phases 1 and 2; these are now caught and logged via
extractImapErrorrather than crashing the sync.
Documentation
- Added
ROADMAP.mdand updated README navigation links - Updated Contributing and Roadmap links to point to mailflow.sh