github maathimself/mailflow v4.0.0

2 hours ago

MailFlow v4.0.0

Dark email bodies, remote images loaded through MailFlow so senders no longer see your address, a Snoozed view, rules that can still notify you, mailbox icons, CardDAV that contact apps can actually reach, and a long list of security and privacy fixes. Update when you can. Thanks to @Monkey7539, @mvalkier, @lawyer61, @Doezer and @salmonumbrella.

Security

  • Remote images could load while blocked. With remote images blocked (the default), protocol-relative URLs, URLs inside image-set() and some quoted inline-style URLs still loaded, so a tracking pixel could fire. They are now blocked, and the email frame and print window also forbid remote images, fonts and media in their Content Security Policy, which catches anything a pattern misses. Replying to or forwarding an email whose image addresses were disguised (a line break inside https, a CSS escape) also loaded them from the sender; the composer now loads images only through MailFlow.
  • Style blocks could let markup through the sanitizer. Removing dark-mode CSS from an email's <style> could join the text around it into a closing tag, so links, forms and tags written inside the CSS reached the stored body. The email frame kept them inert; they no longer get through.
  • A crafted email could freeze the server. A <style> built to make remote-image blocking slow held the backend for close to a minute per view, for every user. Blocking now reads the CSS once, in linear time.
  • A sender's name could carry markup into your reply. The header above a quoted reply or forward was built from the sender's name and the subject as written, so an image in a display name loaded when you pressed Reply and went out in your reply. Those values are now escaped.
  • CardDAV ignored the sign-in policies. Under "SSO only" or "Two-factor required", a password alone could still read and change a user's contacts over CardDAV. CardDAV now refuses password sign-in under either policy, and a right password no longer gets past the shared login rate limit after the guess budget is spent.
  • Contact photos could be served as pages. A vCard photo that declared itself text/html was served as HTML on MailFlow's own origin. Photos are now served only as JPEG, PNG, GIF or WebP, with their own nosniff and sandbox headers.
  • The private-address guard accepted other spellings. Hosts such as 2130706433, 0x7f000001, 127.1, full-width digits, ::ffff:7f00:1 and localhost. reached loopback or private networks, and so did names only the server's /etc/hosts knows (ip6-localhost). They are now refused, whatever the spelling.
  • The next user could see the last one's mail. After a session expired in a tab, whoever signed in next briefly saw the previous user's open compose, message list and some settings, and could save the previous user's favorite folders into their own. Signing out now clears them.
  • An AI provider could send MailFlow's requests elsewhere. The AI provider's address is checked against the private-address guard when an admin saves it, but MailFlow followed redirects from it, so a provider could send the request, with some redirects the email text it carried too, to an address the guard forbids. A redirect now fails the request with an error saying so.
  • Attachment names could hide their real extension. A single right-to-left override in a name was not stripped, so invoice<U+202E>fdp.exe showed as invoiceexe.pdf.

New

  • Dark email bodies (#228). In a dark theme, MailFlow can show message bodies dark: plain text, email that ships its own dark design, and any other HTML, recolored with its hues kept. Before showing a body dark, MailFlow checks that every piece of text that read as sent still reads; if it would not, the email stays as sent and the toggle says why. Email whose sender asks to stay light is recolored too (Intercom's template, for one, marks its email that way, against Apple Mail's blunt inversion), and a sender's own dark design that leaves much of the email light gives way to MailFlow's recoloring. It is on by default in dark themes and never applies in a light one; turn it off under Settings → Appearance → Theme → "Dark email bodies". Each message also has its own toggle in the reading pane and on each conversation card, and an email shown dark is dark from the moment it opens.
  • Remote images load through MailFlow. Images you allow (a trusted sender, or "Load images") are fetched by your MailFlow server instead of your browser, so the sender sees MailFlow, not your IP address, device or location, including when you reply to or forward the email. Gmail, Outlook.com and Proton do the same. It fetches only images the message actually contains, for its own user, and serves only real raster images. Oversized photos are scaled down on the way (a 6 MB newsletter photo arrives as about 100 KB), and open-tracking images are never fetched at all, so senders don't learn when you opened their email; the reading pane says how many were blocked.
  • A Snoozed view (#269). While anything is snoozed, a Snoozed entry in the sidebar lists it from every account, in the order it comes back, with when each message returns. Its menu changes the snooze time or brings a message back now, as it was (still read if you had read it).
  • Rules that still notify you (#588). A new "Notify me" rule action keeps the new-mail alert (push, toast, sound) for mail a rule files away or marks read. It is off unless you add it; muted senders stay muted, and mail a rule deletes never alerts.
  • Mailbox icons (#376). Give an account an emoji under Settings → Accounts; it replaces the account's color dot in the sidebar, the message list, the reading pane and the command palette.
  • Tidier settings. The settings menu is grouped by purpose (Mail, Preferences, AI & Extensions, Administration), and a new Behavior tab holds reading, writing and sync settings that used to sit under Appearance → Layout.
  • Open the next message after deleting or archiving (#572). Removing the open message from the reading pane now moves on, as the list already did. Settings → Behavior → "After deleting or archiving" picks the next message, the previous one, or the list.
  • Swipe between messages on a phone (#229). Swipe left or right anywhere on an open email, the body included, to move to the next or previous message in the list, in the conversation view too; swipe right from the left edge to go back to the list.
  • Discard button in the composer (#573). Throws the draft away after a confirmation, including one that already autosaved.
  • Clean up several senders at once (#602). Mailbox Cleanup can tick several senders, or all of them, and archive or trash them with one confirmation.
  • Bcc shown on mail you send (#585). The reading pane shows the Bcc of your own sent mail and drafts.

Faster

  • The app and email load faster, most of all on a phone. MailFlow's own web server now speaks HTTP/2 and compresses what it sends, and the app loads only the language in use. On a slow mobile connection the app opened in 3 s instead of 12 s.
  • Images are fitted to the email and kept. Images through MailFlow arrive at the size the email shows them (a 26-image newsletter: 611 KB instead of 1.3 MB), are kept on the server so another device or a later view shows them at once (about 0.1 s instead of 3 s), and further down an email they load as you scroll toward them. Large photos embedded in an email are fitted the same way; forwarding one still sends the original.
  • Opening messages. The next and previous messages load ahead on a desktop too, so moving through mail with j and k shows each at once; the email's frame is set up once per open instead of twice.

Fixes

  • CardDAV works with contact apps. The bundled nginx had no route for /carddav, so no contacts app could reach it, and DAVx5 found no address book. Both are fixed.
  • Threads. Your own replies in Sent now count in the Inbox thread badge (#576), drafts never do, and archiving, deleting or moving a conversation never takes its drafts with it, nor its copies already in Trash or Spam (deleting one from the Inbox used to delete those for good). Archiving a conversation from the conversation pane moves only the copies in the folder you are viewing, as the list does.
  • Windows at other font sizes (#591). At a font size other than 100%, clicking a message or compose window's title bar moved and grew it until it left the screen. Both now stay put and follow the pointer. The resize grip also works in Firefox again.
  • Dates in your language (#593). Month names, AM/PM and "Yesterday" follow MailFlow's language, not the browser's.
  • Searching (#592). The list shows "Searching…" while a search runs instead of "No results", also while a new search replaces earlier results, and a cleared search can no longer fill the list with a late answer.
  • Fewer refetches (#595). A message with an inline image reference that can never resolve no longer downloads its whole body from the mail server on every view.
  • Drafts keep their quoted images. Reopening a saved reply and saving it again replaced the quoted email's images with placeholders for good.
  • Attachments. A message forwarded as an attachment is listed as one .eml you can download, and inline images the body never shows are listed so you can still open them.
  • Sync. New mail that arrives while a sync is already running is no longer left for the next minute's check; MailFlow syncs again straight away. A move that met a message another client had already moved could be recorded against a different message in the destination folder; it is now reported as failed and left for the next sync. Messages with a sender name over 500 characters now import (#584). An account whose OAuth refresh or server address check fails no longer stays stuck "connecting" until a restart; it shows the error. An IPv6-only server address no longer crashes the backend (#579).
  • Snoozing on servers that keep folders under INBOX. On servers such as Dovecot as cPanel sets it up, every snoozed message showed twice in a search across folders and could not be snoozed again once moved out. Renaming the Snoozed folder, or the folder a message was snoozed from, no longer strands those messages.
  • Todoist and ChatGPT no longer sign you out. When Todoist rejected the saved token, opening the Create Todoist Task dialog signed you out of MailFlow, and so did Test connection when the ChatGPT authorization had stopped working. Both now say what to reconnect.
  • Live updates back off. A tab whose live connection the server refuses (one opened at an address other than MailFlow's configured one) retried every second or two, reloading the message list each time; it now waits longer between tries, up to 30 seconds.
  • Safari. Keyboard shortcuts keep working after clicking into an email.
  • Starring is instant. The star in the reading pane and the conversation view fills as you click; on Gmail it waited seconds for the server.
  • Desktop and Android apps. The Delete and Star buttons on new-mail notifications work; the server refused them. Desktop notifications also stay clickable after a few seconds (#587).
  • iOS home-screen app. Tapping a new-mail push opens the message (#589), the layout stays on screen after rotating at a font size other than 100%, and the top bars no longer sit in the blur iOS 27 draws under the status bar.
  • Email styling. An email whose CSS had filter: invert() without a trailing semicolon no longer loses the styles after it.

Upgrading

ghcr.io/maathimself/mailflow-backend:latest points at 4.0.0, published for amd64 and arm64.

  • One database migration (0066, the mailbox icon column), applied automatically when the backend starts.
  • A new Docker volume, image_cache, holds images fitted by the image proxy; docker compose up creates it. Its size is capped by IMAGE_CACHE_MAX_MB in .env (512 by default). Without Docker Compose the cache lives in the temporary directory, or set IMAGE_CACHE_DIR.
  • Running your own nginx? contrib/nginx.conf now shows http2 on; and gzip; add them to yours for the same speed-up. The backend image now includes sharp for resizing images, with native builds for amd64 and arm64.
  • Your MailFlow server now fetches remote images that readers allow, over HTTPS, so it needs outbound HTTPS to the senders' image hosts. Private and reserved addresses are refused, whatever the private-hosts setting, and images served only over plain HTTP do not load, as browsers already refuse them on an HTTPS page.
  • Running your own nginx in front of MailFlow? Add the /carddav and /.well-known/carddav locations from contrib/nginx.conf, or contacts apps cannot reach CardDAV. The Docker image's nginx already has them.
  • CardDAV and sign-in policies: if password sign-in is turned off for SSO, or two-factor is required, contacts apps that sign in with a password are now refused until app-specific passwords exist.
  • In a dark theme, email bodies turn dark after the update unless you turn it off under Settings → Appearance → Theme. Email opened before the update is recolored by MailFlow; a sender's own dark design is used once its body is fetched again.
  • Tabs opened on 3.8.0 or later reload into the new version by themselves; reload any older ones.

Don't miss a new mailflow release

NewReleases is sending notifications on new releases.