If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
System for Cross-domain Identity Management (SCIM) v2 (Enterprise):
JMAP: CalendarEvent/set support for updating and deleting synthetic ids (#2925).
Calendar:
Conference links in calendar invites and email alarms.
Translations for Arabic, Brazilian Portuguese, Bulgarian, Chinese Simplified, Chinese Traditional, Croatian, Czech, Finnish, Hebrew, Hindi, Hungarian, Indonesian, Japanese, Korean, Lithuanian, Norwegian BokmΓ₯l, Persian, Romanian, Russian, Slovak, Slovenian, Thai, Turkish, Ukrainian and Vietnamese.
Changed
Calendar: Updated HTTP RSVP page.
Fixed
DANE:
TLSA records are looked up whenever the MX RRset is signed, even when the MX host's own zone is not.
Mandatory DANE failures are permanent rather than temporary, bouncing messages that should be delayed.
Valid but unusable TLSA records fall back to the configured TLS strategy, permitting cleartext delivery where TLS is required.
S3: Fix outdated upstream af-south-1 region configuration.
Setup wizard: SQL directories set to use the main data store are now validated against the data store being configured.
CardDAV: Delete default address book id when deleting the default address book.
Redis: Sentinel deployments configured with rediss:// URLs now connect to the master over TLS instead of silently falling back to cleartext.
Email: Generated Message-ID headers use the hostname of the node that built the message instead of the configured server hostname.
MTA:
Do not send DMARC reports to local domains.
Messages addressed to an inboundReportAddresses match are only discarded when they actually contain a report (#1088).
Directory: Impersonation using the recovery admin fails when the impersonated account has not logged in before (LDAP and SQL directories).
WebUI: Failed logins open the browser's native credential prompt.
Cluster: Expired node id leases are released periodically rather than only during startup, so entries for removed nodes no longer remain Stale or Inactive indefinitely.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
WebUI: oauthClientId setting in Application, which allows the WebUI to use a different OAuth client than the default.
Sieve: env.spam.score and env.spam.is_spam variables, which expose the spam filter result to system scripts running at the DATA stage.
CalDAV: vCardVersion setting in AddressBook, which allows the default vCard version to be specified when the client does not request a specific version.
Changed
MySQL & MariaDB: Key columns are now VARBINARY(255) with a full-length primary key instead of TINYBLOB. Note: Existing deployments should run, once per table, for each of the tables a, d, e, f, g, h, j, k, l, m, n, o, p, q, r, s, t, u, w, x and y the command ALTER TABLE a MODIFY k VARBINARY(255) NOT NULL;.
Fixed
ACME:
Order and authorization failures are never logged, so an order rejected by the CA.
An order rejected by the CA marks the renewal task as permanently failed.
CalDAV:
Attendee addresses whose mailto: URI percent-encodes a full name-addr are silently dropped from the scheduling snapshot.
Attendees whose calendar user address cannot be parsed should be flagged with SCHEDULE-STATUS=3.7.
The RSVP link in an iMIP invitation stamps PARTSTAT on the organizer's copy of the event only, leaving a local attendee's own copy at NEEDS-ACTION and sending the organizer no reply.
MKCALENDAR, MKCOL and PROPPATCH store the display name, description, time zone and the other per-user properties under the authenticated account rather than the account that owns the collection.
Directory:
An empty column, attribute or claim returned by an external directory is synchronized as an empty string rather than a missing value.
/api/discover splits the account name on @ without accounting for the % master user separator or the recovery administrator.
FoundationDB: Older chunked entries are not deleted.
IMAP: SETACL and DELETEACL fail to resolve an identifier spelled with uppercase characters.
iMIP: Invitations, replies and cancellations reference a TZID parameter with no matching VTIMEZONE component whenever the event was stored without one.
JMAP:
AddressBook/get: A new account's default address book is never recorded.
Email/get and Email/parse with fetchAllBodyValues return body values only for the parts listed in textBody or htmlBody, omitting every other text/* part in bodyStructure.
Email/set writes display names as an RFC 2047 encoded-word wrapped in a quoted-string, which RFC 2047 forbids.
Mailbox/set, AddressBook/set and Calendar/set store isSubscribed and the other per-user properties under the authenticated account rather than the account named in the request.
Principal/query returns no results when the name or email filter is spelled with uppercase characters.
FileNode/set: File nodes created over JMAP are returned with a <D:href> holding the raw name over WebDAV.
Meilisearch:
Queries return at most 1000 results, as the maxTotalHits pagination setting is left at the Meilisearch default.
Searches combining several terms return documents that match only some of them.
A task confirmation timeout is reported as a success when failOnTimeout is disabled.
Import: --import always aborts with the target database already containing data in the key range being imported.
MTA:
A domain catchAllAddress pointing to a mailing list or a sub-addressed mailbox is accepted at RCPT TO and then rejected at local delivery with 550 5.5.0 Mailbox not found.
is_local_address() and is_local_domain() expression functions do not match an address or domain spelled with uppercase characters.
Relay routes are rejected with host resolves loopback address, which prevents relaying through a local proxy or tunnel.
MySQL, MariaDB & PostgreSQL: Range scans, range deletions and store purges run as a single unbounded statement, so on servers that enforce a statement timeout they abort on large accounts and tasks such as account deletion can never complete.
Network: local_port and local_ip report the address Stalwart is bound to rather than the address the client connected to when the connection arrives through a trusted proxy.
Task manager:
totalDeadline is not enforced on tasks that fail with a specific retry time.
Indexing tasks are dropped after maxAttempts failures, so a search store that is unavailable or overloaded leaves messages permanently missing from the index.
Indexing tasks are dropped when the document metadata read returns no data, which can happen on SQL read replicas that have not yet caught up with the primary.
The DNS management task republishes the DKIM records of retired keys that the DKIM rotation task had already removed from the zone.
Sieve: spamtest returns only 1 or 10 (and spamtest :percent only 0 or 100), so scripts cannot act on intermediate spam scores.
Spam filter: MIME_BAD is tagged whenever the declared Content-Type of an attachment is not byte identical to the type detected from its magic bytes.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
Reporting: inboundReportMaxSize setting, which bounds the size of a decompressed inbound DMARC or TLS report (default 25MB).
RocksDB: cacheSize setting, which bounds the total memory shared by the block caches of every column family (default 128MB).
Changed
ASN & GeoIP: Default data source URLs now point at the ip-location-db GitHub releases, as the previously used npm packages are no longer updated. Existing installations keep their configured URLs and should update them following the ASN and GeoIP documentation.
JMAP: Identity/get keeps identities in sync with the account's e-mail addresses.
MTA: Queue scheduler no longer rescans the queue from the earliest pending event and coalesces bursts of delivery completions into a single scan.
RocksDB:
Column families are tuned for the access pattern of the data they hold.
Range iteration uses bounded iterators and no longer reads values when only keys were requested.
Fixed
JMAP:
Setting uploadTtl to 1ms triggers panic.
CalendarEvent/set does not assign organizerCalendarAddress nor send scheduling messages when an event is created with participants.
CalendarEvent/get omits isOrigin when it is listed explicitly in properties.
CalendarEventNotification/changes and FileNode/changes reject with cannotCalculateChanges the state that /get returned for an account with no change history.
CalendarEvent/set and ContactCard/set do not write a vanished tombstone for the previous CalDAV/CardDAV href when calendarIds or addressBookIds moves an item between collections.
CalDAV: Attendee addresses that percent-encode a display name into the mailto: URI are queued verbatim.
Calendar: Recurring events disappear from CalDAV time-range REPORTs and JMAP CalendarEvent/query results a few years after their first occurrence.
WebDAV:
When a file node references a parent folder that no longer exists, any request on a file collection panics.
MOVE on a folder honors a Depth header of 0 or 1 instead of always moving the whole subtree.
MTA:
DSN bounces are emitted with a malformed Message-ID wrapped in doubled angle brackets.
Delivery to any MX host whose name is an IDN A-label fails permanently.
Queue strategy and quota expressions that branch on source never match at enqueue.
MTA-STS:
Policies in testing mode are enforced, turning any TLS error into a permanent failure.
mx patterns published as U-labels never authorize the MX host they name.
DMARC:
Alignment compares identifiers in their A-label form.
External reporting addresses published as U-labels are rejected as unauthorized.
Spam filter:
Some rules misfire on internationalized addresses when the envelope and the headers spell the same domain in different label forms.
Punycode labels that do not re-encode to the label they came from are no longer decoded.
WebPush: Validate push URL and use application/octet-stream as Content-Type for encrypted payloads.
Directory:
Local group membership is cleared when the external directory is configured with a group claim or attribute that it does not return.
LDAP: Directories that store aliases as additional values of the primary address attribute provision no aliases.
Mail addressed to a domain alias is rejected with 550 Relay not allowed, unless the domain's primary name happened to be resolved earlier and is still cached.
RocksDB: bufferSize setting was applied to the unused default column family and had no effect.
Sieve: include statements fail to find system and user global scripts whose name contains uppercase characters.
Task manager: totalDeadline is measured from the time a task was created instead of its first failed attempt.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
WebDAV: Range and If-Range header support on file downloads (RFC 7233) (#2377).
Spam filter: url_original expression variable for Url rules.
Changed
Memory allocator: Replaced the unmaintained jemallocator crate with tikv-jemallocator (contributed by @checkraisefold).
ACME registry: Use description as label property.
Fixed
MTA:
Certificates for domains publishing an enforcing MTA-STS policy are always validated, even in the fallback TLS strategy.
DSN delivery date uses wrong timestamp.
FUTURERELEASE HOLDUNTIL uses Unix timestamps instead of RFC 3339 date-times.
JMAP:
EmailSubmission/query filtering on undoStatus contradicts EmailSubmission/get, reporting held FUTURERELEASE submissions as final instead of pending.
EmailSubmission/get requests without an ids argument iterates the wrong index.
CardDAV: Accept: text/vcard version negotiation is ignored whenever another parameter such as q or charset follows version=.
Calendar: Server-side scheduling messages place the text/calendar part outside the multipart/alternative and disposed as an attachment.
Sharing: Accounts holding the impersonate permission never have their ACL grants collected, so shared items are never listed in JMAP sessions, CalDAV/CardDAV discovery or IMAP.
IMAP:
COPY/MOVE into a shared folder fails with NO [ALREADYEXISTS] when the destination account already holds the message, leaving the message in the source mailbox and clients in a retry loop.
BODYSTRUCTURE and ENVELOPE return MIME parameters, Content-Description, subjects and display names as raw UTF-8 even to sessions that never enabled UTF8=ACCEPT.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
MTA: Allow System Sieve scripts to access orcpt during the DATA stage.
Changed
S3: accessKey can now be read from an environment variable or file.
Fixed
Meilisearch: Verify index existence using GET instead of creating a new task which times out on busy servers.
Branding: Stalwart logo flashes before the per-tenant logo is loaded on the login page.
Calendar: iMIP and alarm notification messages embed the default logo using bare LF line endings, producing a single 4247 octet line that strict SMTP relays reject with line too long.
DMARC: Failure reports state Identity-Alignment: none when a mechanism authenticated successfully but against an identity that is not aligned with the From domain.
Redis: Task and queue locks are never released after a worker dies, because failed lock attempts refresh the lock expiry.
Recovery mode: Download WebUI if missing.
Logging: The systemd journal tracer omits the parent span's fields.
MTA:
BDAT chunks sent without a valid MAIL FROM are answered with 552 5.3.4 Message too big for system instead of 503 5.5.1.
A maxMessageSize of 0 rejects every message with 552 5.3.4 Message too big for system instead of disabling the size limit.
Windows: Listeners bound to the unspecified IPv6 address ([::]), including all defaults, refuse IPv4 connections such as 127.0.0.1, since IPV6_V6ONLY is enabled by default on Windows.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
Changed
Fixed
JMAP:
Email/copy should return alreadyExists when copying a message to a mailbox that already contains it.
Email/copy with onSuccessDestroyOriginal destroys the copy's creation id instead of the source Email id.
CalendarEvent/set does not generate a uid on create when the client omits it.
CalendarEvent/set does not refresh the updated property (iCalendar DTSTAMP) on create or update.
EmailSubmission/set rejects valid recipients whose domain is itself a public suffix (e.g. gov.in, co.uk).
Requests are rejected with notRequest when a method name contains a JSON-escaped solidus (e.g. Core\/echo).
MTA: Panic when MTA-STS is disabled and a remote MTA fetched /.well-known/mta-sts.txt.
Auth: Scoped credentials with SysApiKeyCreate or SysApiKeyUpdate permissions can regain its own account's full rights.
Web Push: Valid VAPID keys are rejected when PEM-encoded with explicit EC parameters, in SEC1 (EC PRIVATE KEY) format, or with a leading byte-order mark.
Encryption at rest: Appended messages are encrypted for accounts that did not opt in to encryptOnAppend.
Cache: Account caches silently discard entries larger than a single quick-cache shard, causing constant database rebuilds.
Registry: Id references (e.g. #certificate-...) fail to resolve on defaultCertificateId, defaultAdminRoleIds, listenerIds and publicKey.
Search: reindex drops calendar and contact index tasks for accounts with fewer than a full batch of items.
Migration: Abort --import when the target already contains data in the key range being imported.
Cluster: Broadcast subscriber re-subscribes after every message, losing bursts of cluster broadcasts during the reconnect window.
Enterprise: Per-tenant logo is not shown on the OAuth login password and OTP screens, which are served from the server's canonical host rather than the tenant domain.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
Use of Voluntary Application Server Identification (VAPID) in JMAP Web Push (RFC 9749).
Changed
Fixed
IMAP:
Mailbox object-quota only enforced in JMAP.
Pipelined STORE and EXPUNGE can execute out of order.
JMAP:
Read-only sharee cannot set isSubscribed on a shared mailbox.
Web Push payloads with Content-Encoding: aes128gcm should not be base64-encoded but sent as raw bytes.
Stale push subscription can block verification of a new one.
PushSubscription/set rejects the unpadded base64url keys the W3C Push API produces.
Email/import does not send push notifications for imported messages.
CalendarEvent/set silently ignores ifInState.
CalDAV: calendar-query REPORT returns empty calendar-data for JMAP-created events.
MTA:
DMARC is skipped when MAIL FROM SPF is unavailable.
queue_name variable not available in rate limiter expressions.
Calendar:
No expanded occurrences are returned for a daily recurrences crossing DST.
Uppercase MAILTO calendar addresses become invalid SMTP recipients.
Scheduling invitations on a shared, non-owned calendar fail with MAIL FROM unauthorized.
HTTP: Disable allowedEndpoints expression in recovery mode.
Telemetry: Tasks are serialized to the wrong store when using separate stores for telemetry and data.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
FreeBSD support.
Changed
Fixed
OAuth resource indicators: Accept imap, smtp, pop3 and sieve as valid resource indicators for OAuth access tokens.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
Encryption-at-rest: Support for AES-256-GCM and ChaCha20-Poly1305 for S/MIME (#161).
S3: Support for allowInvalidCerts option to allow connecting to S3 endpoints with invalid TLS certificates.
Redis Sentinel support as an in-memory store and cluster coordinator backend (#2430).
Changed
Fixed
DANE: Verify DNSSEC is supported by the resolver before attempting to validate TLSA records.
TLS: Update search index when file-backed certificates are refreshed.
JMAP: Principal/query returns broad results when a name or email filter cannot be resolved.
Webhooks: event IDs collide for same event type emitted in the same second.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
ACME: Allow specifying a preferred certificate chain.
Changed
Fixed
JMAP: */changes methods leak ids of non-shared objects (reported by @5ud0er).
Sieve: Do not allow invalid certs in http_header function.
FoundationDB: Fix read version cache expiration logic.
MTA: Re-scheduling or editing a queued message reports success but persists nothing for recipients in a non-default virtual queue.
CardDAV: Version requests included in address-data are ignored.
ACME: Add freshness check when renewing certificates.
Autodiscover v2: Read email address from query parameters.
Sieve: Do not keep copies of redirected messages when keep is not specified.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
Changed
OAuth: Rework access tokens to an AES-256-GCM-SIV AEAD format that carries the account name for proxy routing.
Added more internal TLDs to the domain validation.
Fixed
MTA:
Sub-addressing with external directories returns 550 Mailbox not found.
Disabled aliases continue receiving messages.
JMAP for File Storage: FileNode/get returns a stale state string.
Make SieveSystemInterpreter.defaultReturnPath and MtaQueueQuota.match optional expressions.
Rate limiter panics when periods under 1 second are used.
CalDAV/CardDAV: Calendar events, contacts, calendars and address books deleted via JMAP do not write a vanished tombstone.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
Added 58 new DNS provider integrations (see dns-update crate for details).
DNS updater: Log DNS record types and values.
Sieve: Allow User Sieve scripts to access orcpt.
MTA: Log when messages are rejected or discarded by the spam classifier.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
is_ip_in_cidr expression function for CIDR matching.
Changed
Bump mail-auth to 0.9 (which bumps hickory-resolver to 0.26).
Deprecated RFC2136 SIG(0) support as it is no longer supported by hickory.
Fixed
JMAP:
Patching ids containing digits in JSON Pointers fails.
Patching nested objects with null values fails.
External directories:
SQL: Return Failed instead of Error when the query returns no results.
LDAP: Impersonation fails when the user has not logged in before.
Network: Attempt binding to IPv4 when binding to IPv6 fails with EAFNOSUPPORT error.
Bootstrap: Timeout after 30 seconds when probing the data store.
HTTP: Use permissive CORS headers for .well-known endpoints.
ACME:
Include apex domains when requesting certificates for subdomains.
Use the public suffix list to determine the zone name when no origin is provided.
MTA:
Allow rescheduling recipients with permanent failures.
Process reports using original RCPT before rewriting.
Autodiscover v2 endpoint unreachable.
DNS update (via dns-update crate):
OVH + Google Cloud DNS: Fix FQDN handling for MX and SRV records.
Route53: Fix changeset error resolution.
deSEC: Use empty subname for apex records instead of @, which the API rejects.
Cloudflare: Wrap TXT record content in double quotes (RFC 1035) to suppress dashboard warnings.
iCalendar/JSCalendar (via calcard crate):
Support STATUS:CANCELLED mapping from VTODO to JSCalendar.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
Changed
Fixed
Live tracing in community and OSS versions.
Timezone changes from the AccountSettings object return invalidProperties.
mail-parser panic with certain messages containing corrupted attachments.
Pagination by anchor for queued messages, tasks and metrics.
Spam filter: Use original instead of rewritten RCPT on checks.
JMAP:
References in nested objects not resolved.
AddressBook/query fetches wrong resources.
Import tool fails to restore registry entries.
FDB: Allow multiple FoundationDB instances in the same process.
Autoconfig: Return %EMAILADDRESS% when no email address is provided.
Quota: Include Sieve scripts in quota recalculations.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
Changed
Replaced STALWART_HTTPS_PORT with STALWART_PUBLIC_URL.
App Passwords now begin with app_ instead of app to avoid issues with some clients that do not support spaces in passwords.
Fixed
Directory:
Invalidate caches when group memberships change on an external directory.
If you are upgrading from v0.16.x, replace the binary (or run docker pull). If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
OIDC: Fallback to userinfo endpoint when JWT token does not contain an email claim.
S3: verifyAfterWrite option to verify that objects have persisted after writing.
Changed
Allow HTTP to be used for configuring the server.
Fixed
LDAP: Generate valid credentialId when there are password changes.
This version includes multiple breaking changes. If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
OIDC: Extract username from JWT token.
system('node_hostname') and system('node_role') expression variables to retrieve the local node hostname and cluster role respectively.
Changed
Fixed
JMAP:
Invalid receivedAt headers after importing (#2939).
Sorting order issues when emails lack receivedAt headers.
This version includes multiple breaking changes. If you are upgrading from v0.15.x and below, please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
Web UI rewritten from the ground up using the JMAP management API, featuring a refreshed design and addressing 76 enhancement requests and bug fixes.
CLI rewritten from the ground up to use the JMAP management API.
Security enhancements:
Password strength enforcement using the zxcvbn algorithm
Password expiration, rotation policies and IP address restrictions for user accounts
App Passwords with limited access (#1609), labels (#2255), IP address restrictions and expiration dates
API keys with limited access, labels, IP address restrictions and expiration dates
Auto-ban comments and details about the triggering event (#1321)
Auto-ban expiration after a configurable time period (#964)
If you are upgrading from v0.14.x and below, this version includes multiple breaking changes. Please read the upgrading documentation for more information on how to upgrade from previous versions.
If you are upgrading from v0.15.x, replace the binary and update the webadmin.
Added
Changed
Fixed
IMAP/JMAP: OOM when mail-parser returns cyclical MIME structures (CVE-2026-26312).
Tracing: Fix tracing indexing when using separate stores.
JMAP: Fix upToId computation in */queryChanges.
JMAP: Include createdIds when the property is present.
JMAP: Respect query arguments in Email/queryChanges.
JMAP: Return the correct container/item change id when there are no changes.
If you are upgrading from v0.14.x and below, this version includes multiple breaking changes. Please read the upgrading documentation for more information on how to upgrade from previous versions.
If you are upgrading from v0.15.x, replace the binary and update the webadmin.
Added
IMAP: Map HEADER SUBJECT/FROM/TO searches to SUBJECT/FROM/TO queries.
Sieve: Update spam status on user scripts.
Changed
Fixed
Search: Return all document ids when no filters are provided.
Search: Filters not applied when a single message is in the account.
IMAP: Return ALREADYEXISTS code when creating existing mailboxes.
IMAP: Do not return quota resources if no quota is set.
JMAP/changes: Update newState with last changeId if an invalid fromChangeId is provided.
JMAP/CalendarIdentity: Do not update invalid calendar identities.
AI API: Include request error details if available.
If you are upgrading from v0.14.x and below, this version includes multiple breaking changes. Please read the upgrading documentation for more information on how to upgrade from previous versions.
If you are upgrading from v0.15.x, replace the binary and update the webadmin.
Added
Polish locale support (contributed by @mrxkp) (#2480)
Changed
Fixed
Meilisearch: Return correct error messages when failing to create indexes (#2574)
PostgreSQL search: Truncate emails to 650kb for full-text search indexing.
FoundationDB search: Batch large transactions (#2567).
Spam filter: Fix training sample size checks
IMAP: Fix UTF7 encoding with Emojis (contributed by @dojiong) (#2564).
If you are upgrading from v0.14.x and below, this version includes multiple breaking changes. Please read the upgrading documentation for more information on how to upgrade from previous versions.
If you are upgrading from v0.15.x, replace the binary and update the webadmin.
This version includes multiple breaking changes. Please read the upgrading documentation for more information on how to upgrade from previous versions.
This version includes multiple breaking changes. Please read the upgrading documentation for more information on how to upgrade from previous versions.
Added
Linear spam classifier using FTRL-Proximal and feature/cuckoo hashing.
If you are upgrading from v0.13.4 and below, this version includes breaking changes to the internal directory, calendar and contacts. Please read the upgrading documentation for more information on how to upgrade from previous versions.
If you are upgrading from v0.13.4 and below, this version includes breaking changes to the internal directory, calendar and contacts. Please read the upgrading documentation for more information on how to upgrade from previous versions.
If you are upgrading from v0.11.x or v0.12.x, this version includes breaking changes to the message queue and MTA configuration. Please read the UPGRADING.md file for more information on how to upgrade from previous versions.
Added
Changed
JMAP: Protocol layer rewrite for zero-copy deserialization and architectural improvements.
Fixed
IMAP: Unbounded memory allocation in request parser (CVE-2025-61600 ).
IMAP: Wrong permission checked for GETACL.
JMAP: References to previous method fail when there are no results (#1507).
JMAP: Enforce quota checks on Blob/copy.
JMAP: Mailbox/get fails without accountId argument (#1936).
JMAP: Do not return invalidProperties when email update doesn't contain changes (#1139)