Repository navigation
Releases
v1.1.2
Added
- Link safety. unoMail can download a list of known phishing domains
(Phishing Army by default), refresh it in the background and keep it on
disk. The built-in filter scores incoming mail that links to a listed
domain, and the web client marks such links and asks before opening them.
Link hosts are checked through your own server only. - Tracking parameter removal. Tracking parameters are stripped from links
in shown, quoted and forwarded messages, using clean-url's parameter list
by default. - Both features are configured under Server settings > Link safety.
Security
- Fair connection limits. Before, the web listener refused everyone once
512 connections were open (128 per network), so four addresses holding idle
connections could lock out the web client, JMAP, DAV and ACME HTTP-01. The
mail ports had the same weakness at 1024 connections (20 per IPv6 /64).
Each listener now has its own slots. When a listener is full, a new
connection takes the oldest connection of the group holding the most slots,
as long as that group holds clearly more than the newcomer's group. Groups
are IPv4 addresses and IPv6 /48s. A session whose slot is given away ends. - Summary cards only from authenticated senders. Cards were made from the
From domain without checking it, so a forged bill from a domain without
DMARC enforcement could show a "Pay bill" card with the forger's link. A
card now needs one of: a DMARC pass, a DKIM signature aligned with the From
domain, a signed-in local sender, or a source the operator trusts. Mail from
trusted networks and relays is marked on arrival with
X-Unomail-Trusted-Source, a header only the server may write. Mail that
users store themselves (imports, APPEND) makes no cards. /metricsbehind an untrusted proxy. When a reverse proxy on the same
host was not listed inUNOMAIL_TRUSTED_PROXIES, every client looked like
loopback. As a result,/metricswas open to the internet without a token
and all clients shared one login limit. Requests relayed by such a proxy no
longer reach/metrics, and the server logs the misconfiguration at startup
and on the first relayed request.- SSO account linking. With "Only accept addresses the provider reports as
verified" turned off, the first identity naming an address claimed its
mailbox, including an administrator's mailbox. An administrator mailbox is
now linked only through a verified address. Every unverified link is
recorded in the audit log, and the setting shows a warning when it is turned
off.
Deployment
- Base images in the
Dockerfileare pinned by digest, so a re-pushed tag
can't change a build. Renovate updates the digests. - The example
docker-compose.ymlfollows the1.1release line instead of
latest, so moving to a new minor version is a deliberate step. - Releases are documented as signed annotated tags, and the release workflow
warns about unsigned tags. - Changes to CI, the container and dependency files now require maintainer
review (.github/CODEOWNERS).
v1.1.1
⚠️ Upgrade notes
- Building from source needs more tools. DKIM and ARC now use
aws-lc-rs, which needs a C toolchain, and CMake and NASM on Windows. Node 26 replaces Node 24 for building the web client. Nothing changes if you run the published image or a release archive. - Authentication results can read differently. Bounces (mail with an empty sender) now report their SPF result as
smtp.helo. Anything that parsesAuthentication-Resultsheaders may need to allow for this. - The database gains a table for IMAP metadata. The migration runs by itself at startup.
New
- IMAP METADATA (RFC 5464). Private and shared entries on mailboxes and on the server.
- IMAP NOTIFY (RFC 5465). Mail programs are told between commands about changes to the selected mailbox, other mailboxes, mailbox names, subscriptions and metadata.
- IMAP REPLACE (RFC 8508). Swaps one message for a new one in a single step.
- SMTP LIMITS (RFC 9422). EHLO announces the
MAILMAXandRCPTMAXlimits.
Security
- Token logins respect second factors, and sign-in limiter counts survive a repeated password.
- DANE checks each certificate against its own bytes.
- NOTIFY sessions recheck the sign-in.
- Forged
Authentication-Resultsheaders are stripped in every spelling. - Parts added after an S/MIME signature end the verification.
- Admin-only plug-ins get no mail access, suspended fail-closed plug-ins still hold mail, and plug-in hosts need a saved setting.
- The Cloudflare token is sealed.
- IMAP and ManageSieve limit how much one command may hold in memory.
Fixed
Crashes
- Header names, Sieve captures, notify addresses, dates, calendar durations and stored rules no longer crash the server on multibyte or extreme input.
Lost or misdirected mail
- Queued mail survives storage errors, and lost content is reported.
- Redirects and held mail to local recipients are delivered here.
- Temporary AUTH failures are retried, and a refused session tries the next MX host.
- Junk under a redirect-only script stays in Junk.
- A partial failure no longer makes senders redeliver to everyone.
Webmail
- Folder actions apply to the current folder only, so "Delete forever" no longer destroys a whole conversation.
- Drafts can be reopened, aren't lost on a failed save or a new composer, and autosave while you type.
- Encryption survives Undo and replies.
- Decrypted attachments keep working when a conversation reloads, so running downloads are no longer cancelled, and their previews now open.
- Names with commas, forwarded attachments, multi-part bodies and files with a Content-ID work.
- Offline sends keep their schedule, and only one tab replays the outbox.
- Labelled conversations stay listed, and lists keep their rows on refresh.
Everything else
- Single-occurrence calendar invitations keep the series.
- Imports report lost connections, and a restore touches nothing until it can finish.
- An invalid old setting no longer affects other settings.
- JMAP state covers shared mailboxes.
- Further IMAP, Sieve, calendar and admin fixes, Docker corrections, and documentation that matches the code.
Improved
- Mail parsing. The parser moves to
mail-parser1.0, which follows RFC 8621 for message structure. Some inline images no longer count as attachments, MIME boundaries are matched strictly, and damaged messages are read more reliably. Existing attachment and blob links keep working. - DKIM. Relaxed body canonicalization now ignores whitespace-only lines at the end of the body, which had produced signatures that other servers rejected.
Under the hood
- Dependencies updated to their latest major versions:
mail-auth0.15,mail-parser1.0,mail-builder2,parking_lot0.13,sysinfo0.40 and Node 26. The RustCrypto crates stay untilrsa0.10 andcms0.3 are released. mail-authdropped its report code, so DMARC, ARF and TLS-RPT reports now live in this project, and fourzipadvisory exceptions are gone.- Much faster tests: a full server run drops from 156 s to 25 s, a rebuild after a library change from 213 s to 16 s, and the build cache from 38 GB to 3.7 GB.
v1.1.0
⚠️ Upgrade notes
- Server settings are no longer read from the environment. Message limits, greylisting, blocklists, the AbuseIPDB threshold, required TLS, Rspamd fail-open, the virus action, the outbound relay and the hourly sending limits can now be changed only in Server settings. If one of the old variables is still set, its value is copied into Server settings once at startup, unless that setting was already changed. A warning then asks you to remove the variable.
docker-compose.ymlnow runs the publishedghcr.io/rikodev/unomailimage instead of building one locally.
New
- Thunderbird for Android QR setup. Settings › Security can show a QR code in Thunderbird's "Export for Mobile" format, covering IMAP (993, TLS) and SMTP (465, TLS). Without 2-step verification, the code carries the account password after you confirm it. With 2-step verification on, the code is offered when you create a new app password with mail access. The code is drawn in the browser and never stored.
- More AbuseIPDB reports.
- SMTP, IMAP, POP3 and ManageSieve connections dropped for too many errors before sign-in are reported as port scan and hacking.
- Mail refused for phishing, or filed as junk by the AI phishing check from an unverified sender, is reported as phishing rather than spam.
- Three requests within ten minutes for paths of software this server doesn't run (
/wp-login.php,/.env,*.php…) are reported as a web app attack.
Improved
- Admin tables and tabs stay usable on narrow screens.
- The masked addresses admin page is grouped into titled sections.
v1.0.10
Privacy
- The server no longer tells other servers its version. DMARC/DKIM/SPF failure reports and the update check send the User-Agent
unoMailwithout a version. - The public API description (
/api/openapi.json, readable without signing in) shows a fixed API version instead of the server's. - Sieve's
environment "version"now reports the real release version, as the dashboard does.
- Undo: moving, archiving, deleting and reporting spam can be undone from the notice that confirms it. This works for one conversation, a selection, and drag-and-drop to a folder, including in search results and All mail.
- Archive and Junk: in Archive, the reader, the list's quick actions, the row menu and the selection toolbar offer Move to inbox instead of Archive. In Junk they offer Not spam instead of Report spam. The choice follows the folder a conversation is actually in, so search results and All mail show the right one.
- Quick actions: the actions shown when hovering a row now include Report spam / Not spam.
- Delete forever: the selection toolbar says Delete forever in Trash.
- Selection toolbar, laid out like Gmail's:
- archive, spam and delete;
- one button for read or unread (whichever the selection is not yet), and Snooze;
- Move to and Label;
- a menu with Add star, Remove star and the other read state.
- New selection actions: a selection can now be snoozed and starred.
- Sender card: hovering or clicking a sender's picture or name opens a card with Send email, Find emails from the sender, Copy address and Add to contacts. The message details (from, to, date, mailed-by, signed-by, security) moved behind a small arrow next to the recipients.
- Attachments: clicking a file that can be shown (text, PDF, images, HTML as source) opens the preview, which has its own Download button. The separate preview (eye) button is gone. Other risky files still ask before downloading.
- Notices for a single conversation use the same wording as for a selection, e.g. "1 conversation archived".
Mobile layout
- Taps near the left edge of the screen reach the checkbox or button there. Before, the strip that opens the menu caught them.
- Touching the edge no longer flashes the menu or its backdrop. Swiping still opens it.
- The current folder's name is shown above the list. In the Inbox it is shown only when categories are off, since the category tabs already say where you are.
- The menu shows the unoMail logo instead of a Compose button; Compose stays as the floating button.
- Unsubscribe moved into the message's ⋮ menu.
Appearance
- Tooltips and notices: readable in the light theme. They were grey on near-black.
- Contrast with the page: menus, pop-ups, the sender card and the search box now stand out from the page background.
- Colour mode picker: the Light / System / Dark names stay on one line in every language.
- Installed app: the title bar (and the mobile browser's toolbar) follows the chosen accent colour instead of always being purple.
- Built-in themes:
- In Classic, Paper, Midnight and High contrast, the logo's envelope shows again, and text on the accent colour is readable.
- In High contrast, the selected folder, its count and its ⋮ button, and the Compose button are yellow with black text.
- "Mark all as read" has its icon.
Reliability
- When the server cannot be reached, the app says so on a full page instead of showing the sign-in page or a bare error bar. It checks again every few seconds and reloads by itself once the server is back.
- A page that fails to show offers Try again and Go to the inbox.
Dependencies
- tokio 1.54.1, webpki-roots 1.0.11, stylis 4.4.0.
v1.0.9
Highlights
-
Plug-ins and themes as packages
Install plug-ins and themes from pinned git commits. Web plug-ins run in
sandboxed frames with permissioned access to layout slots, pages, settings,
storage and the composer. Server plug-ins run as WebAssembly with mail hooks,
API routes and scheduled jobs. Themes can now carry background images and
per-part styles. See docs/plugins.md, docs/plugin-development.md and
docs/theme-development.md, plus working examples in docs/examples/. -
14 new interface languages
Spanish, Portuguese, Italian, Dutch, Swedish, Hungarian, Romanian, Turkish,
Russian, Ukrainian, Arabic, Chinese (Simplified), Japanese and Korean.
Arabic uses a mirrored right-to-left layout. All of them are also available
for AI translation and spell checking. -
Protocol extensions
- Sieve: duplicate, notify, editheader, mime and more.
- IMAP: UIDONLY, UTF8, MULTIAPPEND, SAVEDATE, UIDBATCHES, UNAUTHENTICATE,
OBJECTID search and more. - POP3: AUTH and UTF8.
- SMTP: FUTURERELEASE, DELIVERBY, MT-PRIORITY and NO-SOLICITING.
- JMAP: blobs and principals.
- WebDAV: quota, byte ranges and extended MKCOL.
-
Phishing protection
The built-in filter now scores traces that only a forged message leaves:- a "not spam" verdict the sender wrote itself, before any server could
have scanned the message - a message claiming to come from Thunderbird that Thunderbird could not
have made (a script's Message-ID, Outlook-only headers) - links through Google's notification redirect in mail not sent by Google
- footer links (privacy, contact, unsubscribe) that lead nowhere around a
single real link
An optional AI check (off by default) asks one of your AI models about mail
the filter already finds doubtful. The model can only add points, never
clear a message, and is protected against messages that try to talk it
round.
- a "not spam" verdict the sender wrote itself, before any server could
-
DMARC feedback
Complaint and failure reports (ARF) sent to hosted domains are stored and
shown under DMARC insights. Optionally, unoMail sends DMARC/DKIM/SPF failure
reports, with recipients redacted and at most one per domain per hour.
Web mail
- An address can now have several sender identities, each with its own
signature. Every account has a fixed primary identity that can't be removed.
The identity dialog offers the addresses the account can send from (own
address, aliases, masked addresses) or another address with its own SMTP
server. - AI summary, translation and reply suggestions moved into compact buttons in
the message header and beside the reply actions. Results appear only when
you ask for them. - The composer stands out from the page in dark themes.
- Server error messages are shown in the interface language.
- Phones: taps near the left edge (back button, list checkboxes) no longer open
the sidebar instead of reaching the button or checkbox. - Phones: the message list keeps its scroll position after you close a message.
- In a narrow expanded list, the star sits under the checkbox to leave more
room for the text. - Fixed folders and other entries being duplicated in the collapsed sidebar.
- A note is shown when JavaScript is disabled.
Administration
- AI model settings are tested when you save them. A failed test explains why
and offers "Save anyway". - DNS health texts are translated. SPF is now checked the way receiving servers
check it (a, mx, include, redirect, for IPv4 and IPv6), and the server's
public addresses are looked up over public DNS, so a container's /etc/hosts
no longer hides them. - The SMTP blacklist and whitelist tables load without waiting on reverse-DNS
lookups, and show a spinner instead of an empty message while loading. - The address column of the Remote IPs table on the dashboard is wider.
- New settings under Server settings -> Built-in spam filter for the AI
phishing check: on/off, model, the score from which the model is asked,
and the points for a phishing verdict.
Security
- Medium, SSO: a mailbox is now linked to the provider identity (sub) that
first signed in to it, and a different identity with the same e-mail address
is refused. If a user's provider account is replaced, reset the mailbox's
2-step verification in its dialog; that also removes the link. - Low, 2-step verification: a code try is counted before the code is checked,
so parallel guesses no longer get extra tries. - Low, CalDAV/CardDAV: remembered sign-ins end as soon as the domain or the
mailbox's DAV access is switched off.
v1.0.8
unoMail 1.0.8
Highlights
- Install unoMail as an app. The web mail is now an installable Progressive Web App with its own icon, and it opens offline from the cached copy of the interface. Mail, calendar and contacts data is never cached by the service worker.
- Update check in the admin dashboard. The dashboard shows the running version and whether a newer release is out, with a link to the release notes. The server asks GitHub a few times a day; switch it off under Server settings → Privacy → Check for updates.
- Keyboard shortcuts at a glance. Press
?in the mail view to see every shortcut.
- Trash and Junk say how long they keep mail: "Messages that have been in Trash more than 30 days will be automatically deleted." The number follows the server's retention settings, and the notice is hidden when retention is off.
- Empty folders, tabs, labels and searches show an illustration and a line on what belongs there, instead of "Nothing here yet."
- The mail list no longer jumps while it loads.
- The first conversation is no longer highlighted when a list opens; the keyboard cursor appears once
j,korxis used, and a mouse click hides it again. - The folder menu (⋮ in the sidebar) has icons.
- Summary cards for a single parcel show Track package together with the other card actions.
- Local translation no longer spins forever when a language download stalls, and starting another translation cancels the running one.
- On phones, swiping from a little further in from the left edge opens the menu instead of triggering the browser's back gesture, and the menu button stays tappable.
Look and feel
- Progress bars follow the Material 3 Expressive style: a wavy indicator beside a flat track with a stop dot. Very small values, such as a nearly empty mailbox quota, stay visible.
- Notifications, the home-screen icon and install prompts use PNG icons, so they show correctly on Android and iOS.
- The interface moves to Material UI 9.
Administration
- New setting
update_check_enabled(on by default). - New endpoints:
GET /api/admin/update-check(super admins) andGET /api/me/retention(any signed-in user). - Release binaries and Docker images now report their real version. Earlier releases all reported 1.0.0, in the dashboard, the API description, backups and telemetry.
Security and dependencies
ctutils0.4.5 fixes RUSTSEC-2026-0385 (non-constant-time mask generation andu128comparisons).postal-mimeupdated for a security advisory.- Other updates: React 19.3.1, Vite 8.3.5, i18next 26.5,
arc-swap1.9.3,zip9.0.5 and smaller packages.
v1.0.7
Security
- Mailing lists no longer pass on forged senders. A post whose author could not be verified now goes out as "Name via List" from the list's own address. The original address is kept in
X-Original-From. Before, a list member proven only by SPF, or anyone posting to an open list, could send as another address on your domain with a valid DKIM signature. Posts approved by a moderator are always sent this way. - Users are told when a filter starts forwarding their mail. If a Sieve filter starts redirecting mail to a new outside address, a notice goes straight to the user's inbox, and the filter cannot hide it. Hidden forwarding is how an attacker keeps reading mail after the victim changes their password.
- New server setting: "Allow forwarding by mail filters" (
sieve_external_redirect, on by default). Turn it off to stop filters from sending mail outside the server. - Invitations can no longer remove or replace your own events. Answering an invitation no longer overwrites or deletes an event with the same ID that someone else organized.
- Authentication results can no longer be faked in mail from colleagues. Results headers in the server's own name are now stripped from mail sent by signed-in users, as they already were for all other incoming mail.
- Out-of-office replies only go to verified senders, meaning senders that passed SPF or DMARC. A forged return address can no longer make the server send signed mail with a subject chosen by a stranger.
- Optional captcha on the web sign-in page. Choose hCaptcha, Cloudflare Turnstile, Google reCAPTCHA or the self-hosted ALTCHA in the server settings. The captcha is checked before the password, so unsolved captchas don't count against login limits.
Behaviour change: senders whose domain has no SPF record and whose mail fails DMARC no longer get out-of-office replies.
Web client
- New Material 3 Expressive design. Coccent colour, with new motion, buttonshapes and a split send button. The interface uses the bundled Roboto Flex font.
- New unoMail logo in the app, favicon
- Gmail-style inbox categories. Tabs now have icons and "N new" badges, plus a preview of the newest unread
senders. - Message list header with a selection menu, "Mark all as read" and a range count.
- Manage subscriptions page. It lists ers one-click unsubscribe, so you can unsubscribe sender by sender. Existing mail is included.
- Sidebar: folders are now links, so a new tab, and they show custom tooltips.
- On-device translation of foreign-language messages using the browser's built-in translator (Chrome and Edge
on desktop) when no AI model is set up. - Masked addresses: administrators now choose closed mask domains from the hosted domains instead of typing them.
[NEW] Summary cards
Fixes
- Phones: the message list no longer scrol.
- Admin models: choosing local-only extraction for purchase cards works again.
- Removed a stray space in the Content-Sec
v1.0.6
Changes
- Document that failed mask creations do not count toward the hourly limit
- Distinct masked address icon and spacing in webmail settings
- Show hourly sending usage in webmail account settings
- Add virtual All mail folder to webmail
- Show message counts next to webmail folders
- Open and close side menus by swipe on mobile
- Compact dashboard metrics and chart legend on mobile
- Masked mails implementation fix
- Bump deps
- Add masked address management and reply identities to webmail
- Add masked address lifecycle, routing and scoped JMAP APIs
- Add contextual AI reply suggestions
- Add purchase summary cards with optional AI extraction
- Add AI models, summaries and language-aware translations
- Fix diagnostic ip, redesign dns health
- Add pagination to SMTP access-rule tables
- UI/UX fix, prevent -> copy between record name and value
- Improve domain self-diagnostic
- Improve spam filter table: pagination, search
v1.0.5
Changes
- Bump node from 24-alpine to 25-alpine
- Bump i18next from 26.4.4 to 26.4.5 in /web in the web group
- Persist metrics, login limiter and in-memory state across restarts
- Show container memory split by service in the capacity chart
- Stop trying other MX hosts when the recipient is deferred
- Show attempts as count/max in delivery queue
- Silence rustls warnings in default log filter
- Treat DS answers without NSEC proof as insecure for DANE
- Fix rwd in tables
- Per mailbox quotas
- Fix dnssec resolver
- Increase app password size from 16 to 24
- Make login rate limits configurable and list blocked logins with unblock