Stalwart Mail Server 0.16.17 → 0.16.26
9 releases · 0 breaking changes · 0 security fixes · 0 advisories fixed
0security0breaking0deprecated20feature192fix
Breaking changes
None in the release notes.
Security changes
None in the release notes.
Every release in between
featuresd_notify support.
featureJMAP: Mailbox/set allows moving a mailbox under a parent that already has a child with the same name, and rejects renames that only change the case of a mailbox name with alreadyExists.
fixDNSSEC: Use hickory-resolver patched fork at https://github.com/stalwartlabs/hickory-dns.
fixRocksDB: Blob garbage collection rewrites every stored blob on each compaction of the blobs column family, about once per 128MB of new mail.
fixMilter: End-of-headers is not sent to milters that negotiate SMFIP_NOHDRS without SMFIP_NOEOH, so the transaction stalls until it times out.
fixOIDC: When the access token lacks the claimUsername claim but has an email claim, the account is built from email without consulting the userinfo endpoint.
fixJMAP:
fixonSuccessUpdateEmail and onSuccessDestroyEmail entries in EmailSubmission/set that name an existing submission by id update or destroy the Email with the same id instead of the submission's own Email.
fixA VacationResponse/set that only sets isEnabled on an account without a vacation response activates an empty Sieve script.
fixJMAP: Creating a MaskedEmail with emailDomain fails with forbidden for every domain when the account has addresses on more than one domain.
fixAutodiscover: Requests for a response schema other than Outlook's, such as ActiveSync (mobilesync), are answered with the Outlook settings instead of error 601.
fixIMAP:
fixLOGIN and AUTHENTICATE with a wrong, expired or unknown app password or API key are answered with an untagged NO, so clients keep waiting for the command to complete until the connection times out.
fixThe failed login that exceeds the maximum number of authentication failures is answered with an untagged NO before the connection is closed.
fixDKIM:
fixA rotation moves the active key to retiring even when its successor fails to publish or propagate, so outgoing mail is sent unsigned until a retry publishes the new key. The DNS write failure is also not logged and the task reports success.
fixKeys created while DNS management was manual, or before DKIM was added to the published records, are never rotated after DNS management becomes automatic. Domains already affected start rotating once a DkimManagement task is created for them.
fixAfter switching DNS management from automatic to manual, a due rotation activates a new key that was never published in DNS, so signatures fail verification, and retiring the old key is retried forever.
fixSpam filter:
fixMessages with no text line long enough for a Pyzor digest are checked with the digest of empty input and tagged PYZOR.
fixDNSBL answers with several return codes, such as a Spamhaus ZEN listing in both SBL and PBL, are scored for only the first code returned.
fixDNSBL lookups that return "not listed" are cached for 24 hours regardless of the zone's negative TTL.
fixRemoving a duplicate training sample of a message reclassified on the same day clears the blob link of the sample that is kept.
fixMTA: Queue quotas with an empty match expression are never enforced, including the global queue quota created on first start.
fixRocksDB: The info log (LOG, LOG.old.*) grows without limit because log rotation and retention are left at RocksDB defaults.
fixWebUI: A blob store read error at startup, such as an S3 authentication failure, stops the web interface from being downloaded.
featureDNS: PowerDNS Authoritative provider for automatic DNS record management.
fixTroubleshoot tool: TLSA records are looked up for every MX host, including hosts whose zone is not DNSSEC signed.
fixSpam filter:
fixOpenPhish and PhishTank entries containing uppercase characters never match, since message URLs are lowercased while HTTP lookup entries keep their original case. HTTP lookups now match keys case-insensitively.
fixURL shortener links are followed using the lowercased URL, so case-sensitive short links resolve to the wrong destination or not at all.
fixIncremental training never advances its position past the first run, so every retained sample added since then is trained again, and counted again in the reservoir, on each run until it expires.
fixUpdating the rules only adds new objects, so upstream changes to existing rules, DNSBL servers, HTTP lookups, lookup keys and file extensions never reach an existing installation.
fixUpdating the rules reports success when objects fail to import, or when a configuration error stops the updated settings from being activated.
fixJMAP:
fixA PushSubscription created within the verification rate limit window of another one on the same account never receives its PushVerification, since the blocked verification is dropped instead of being sent once the window expires.
fixA push notification retried after a failed delivery can report an older state than a change queued during the failed attempt, since the older state changes are merged last and overwrite the newer ones.
fixChanges made while a push request is in flight are not delivered until the next change reaches the same subscription, since a successful delivery cancels the pending retry.
fixThe VAPID aud claim is derived from a hand-written parse of the push URL, so a crafted push URL can make the server sign a token for a push service other than the one the request is sent to.
fixEmail/import rejects a blobId that refers to a Blob/upload creation id in the same request ("#u0") with Invalid blob id..
fixEmail/set with a full mailboxIds object identical to the current mailboxes, together with a keyword change, stores the message with IMAP UID 0, so IMAP clients stop seeing it.
fixMTA:
fixA node without the outboundMta role stops replying to DATA and to JMAP submissions once about 1024 messages have been queued on it.
fixMX records are resolved through the DNSSEC-validating resolver even when DANE is disabled.
fixA DATA stage Sieve script does not see headers added by milters or MTA hooks, and discards every milter and MTA hook change when it edits the message.
fixMySQL: Range deletions and search index removals start with a single unbounded DELETE and switch to chunks only after a timeout.
fixIMAP: COPY and MOVE fail with NO [CONTACTADMIN] when another session changes the same message at the same time.
fixAutodiscover: Implicit TLS ports (993, 995, 465) are advertised with TLS, which Outlook reads as STARTTLS.
fixHTTP: Idle keep-alive connections are never closed.
featureExpressions: bit_and function.
fixMTA:
fixA mailing list whose recipients include another mailing list is accepted at RCPT TO and then rejected at local delivery with 550 5.5.0 Mailbox not found.
fixDMARC aggregate reports carry two spf elements per record and the version element of a DMARC aggregate report is written as 1 instead of 1.0.
fixDSNs generated for an alias rewrite or a list expansion emit a doubled addr-type in Original-Recipient (rfc822;rfc822;[email protected]).
fixDSNs that cannot be written to the store are discarded, the recipients are flagged as notified and the original message is removed from the queue, losing both the bounce and the message.
fixPOP3:
fixTOP msg n counts the n lines from the first byte of the message instead of from the first byte of the body.
fixA message whose very first line begins with . is not byte-stuffed.
fixSpam filter: Moving or copying a message from one account into another creates no training sample, so the classifier never learns from it.
fixSieve: envelope "orcpt" yields the bare address for an ORCPT supplied over SMTP. It now carries the addr-type prefix in every case, as required by RFC 6009.
fixACME: The _acme-challenge TXT records published for a DNS-01 authorization are never removed.
fixDNS: The DNSSEC resolver queries a single nameserver at a time, working around a hickory-resolver race that cancels the TCP retry when two nameservers return a truncated response in parallel.
fixTroubleshoot tool:
fixMX records are resolved through the DNSSEC-validating resolver, matching the resolver used by the delivery path.
fixA TLSA lookup that fails or returns bogus records stops the delivery attempt for that host, instead of continuing without DANE.
fixOIDC: Bearer tokens that carry no email, preferred_username or upn claim are always authenticated against the default directory.
fixMeilisearch: A confirmation timeout is treated as a failed write even when failOnTimeout is disabled, so an index whose batches take longer than pollInterval x maxRetries never completes an indexing task and resubmits the same batch indefinitely.
fixWebUI: A failed update no longer takes an Application offline.
fixFoundationDB: The cached read version is invalidated when any broadcast is received from another node.
fixRedis:
fixOn a cluster, the rate limiter and the blob upload quota issue INCR and EXPIRE as a MULTI/EXEC transaction, whose MOVED redirects collapse into a single EXECABORT that never refreshes the slot map.
fixA connection that fails because it is addressing the wrong server is returned to the pool and reused, since the recycle check only issues PING.
fixWebDAV: PROPFIND responses do not declare the namespace of every requested property on the DAV:multistatus element.
fixMTA:
fixSMTP session state obtained before STARTTLS is discarded once the TLS handshake completes, as required by RFC 3207.
fixInbound throttle, outbound throttle and queue quota match expressions evaluate their if/then conditions.
fixDMARC: Messages without an aligned SPF or DKIM pass from a domain that publishes a DMARC policy are reported as fail instead of none in logs.
fixDMARC: A temporary DNS error on an SPF or DKIM check whose identifier aligns with the author domain produces temperror instead of fail.
fixDMARC: A policy record without a p tag is only applied, as p=none, when it contains a rua tag, even if it declares sp or np.
fixiMIP: Notification subjects and bodies omit the event start date, time and timezone for recurring events.
fixOIDC: Discovery is retried for 30 seconds before the directory is marked as unavailable, so a provider that is still starting up no longer requires a restart.
fixWebUI: The cached bundle of an Application is discarded when its resourceUrl changes or the record is deleted, so the next unpack fetches the new resource.
fixDNS: Append . to MX record hostnames.
fixRecovery mode: Automatic IP banning is disabled during recovery and initial setup.
fixFoundationDB: The cached read version is invalidated when a queue refresh or registry change broadcast is received.
fixSieve: Messages filed with fileinto by a user script are treated as ham and are no longer moved to Junk when classified as spam.
fixIMAP:
fixSELECT, EXAMINE and STATUS on a shared mailbox require the r (read) right.
fixAUTHENTICATE is refused on clear-text connections unless allowPlainTextAuth is enabled, and the greeting and CAPABILITY response advertise LOGINDISABLED instead of the AUTH= mechanisms in that case.
fixIMAP, POP3, ManageSieve: Partial commands received before STARTTLS or STLS are discarded once the TLS handshake completes.
fixNetwork: Inbound TLS handshakes, both implicit and STARTTLS, are aborted after the listener's tlsTimeout, releasing the connection slot.
fixOAuth: A random key is used when the OIDC provider's encryptionKey or HMAC signatureKey cannot be read, instead of an empty key.
fixLDAP: The {local} and {domain} filter placeholders are escaped.
fixJMAP:
fixCalendarEvent/set stores useDefaultAlerts per user, and CalendarEvent/get returns false when it was never set.
fixCalendarEvent/get returns null for baseEventId unless the id is a synthetic recurrence instance.
fixCalendarEvent/get returns null for requested recurrenceRule and recurrenceOverrides properties on synthetic recurrence instances.
fixCalendarEvent/get and ContactCard/get return only id when the properties argument is an empty list, instead of every property.
featureSieve: Messages generated by user scripts are DKIM signed through the new SieveUserInterpreter.dkimSignDomain setting, which defaults to the account's own domain.
fixJMAP:
fixCalendarEvent/set requests that ask for scheduling messages are rejected with a forbidden error when the account cannot send them.
fixCalendar/get and AddressBook/get return every property when the properties argument is omitted or null.
fixEventSource ping events advertise the interval in seconds rather than milliseconds.
fixCalendar synthetic ids returned when expanding recurrences identify an occurrence by its recurrence id.
fixIMAP: Every command in a pipelined STATUS or FETCH batch receives its tagged completion, instead of the first failing command dropping the responses for all commands queued behind it.
fixWebDAV: Accounts without a storage quota no longer advertise a 4 GiB limit in DAV:quota-available-bytes.
fixMTA: Inbound DMARC and TLS aggregate reports that a reporter sends more than once are imported again as a duplicate entry.
fixSpam filter: Domain and URL blocklists are queried only for text written as a link.
fixiTIP: Detaching an occurrence that the recurrence rule already generates is sent as a METHOD:REQUEST carrying the RECURRENCE-ID instead of a METHOD:ADD.
fixSieve: fileinto :specialuse and specialuse_exists accept special-use attributes in the \Trash form.
fixLDAP: Active Directory servers that answer an unauthenticated bind (a non-empty DN with a zero-length password) with success no longer authenticate accounts without a password.
fixNetwork: Listeners bound to the unspecified IPv6 address ([::]) fall back to IPv4 when socket creation fails with EPROTONOSUPPORT.
fixOpenTelemetry: log exporter does not include the parent span's attributes.
featureSystem for Cross-domain Identity Management (SCIM) v2 (Enterprise):
featureCore Schema (RFC 7643)
featureProtocol (RFC 7644)
featureCursor-Based Pagination (RFC 9865)
featureInteroperability Profile (draft-zollner-scim-interop-profile)
featureIPSIE lifecycle profile (draft-schreiber-scim-ipsie-profile)
featureJMAP: CalendarEvent/set support for updating and deleting synthetic ids (#2925).
featureCalendar:
featureConference links in calendar invites and email alarms.
featureTranslations 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.
otherCalendar: Updated HTTP RSVP page.
fixDANE:
fixTLSA records are looked up whenever the MX RRset is signed, even when the MX host's own zone is not.
fixMandatory DANE failures are permanent rather than temporary, bouncing messages that should be delayed.
fixValid but unusable TLSA records fall back to the configured TLS strategy, permitting cleartext delivery where TLS is required.
fixS3: Fix outdated upstream af-south-1 region configuration.
fixSetup wizard: SQL directories set to use the main data store are now validated against the data store being configured.
fixCardDAV: Delete default address book id when deleting the default address book.
fixRedis: Sentinel deployments configured with rediss:// URLs now connect to the master over TLS instead of silently falling back to cleartext.
fixEmail: Generated Message-ID headers use the hostname of the node that built the message instead of the configured server hostname.
fixMTA:
fixDo not send DMARC reports to local domains.
fixMessages addressed to an inboundReportAddresses match are only discarded when they actually contain a report (#1088).
fixDirectory: Impersonation using the recovery admin fails when the impersonated account has not logged in before (LDAP and SQL directories).
fixWebUI: Failed logins open the browser's native credential prompt.
fixCluster: Expired node id leases are released periodically rather than only during startup, so entries for removed nodes no longer remain Stale or Inactive indefinitely.
featureWebUI: oauthClientId setting in Application, which allows the WebUI to use a different OAuth client than the default.
featureSieve: env.spam.score and env.spam.is_spam variables, which expose the spam filter result to system scripts running at the DATA stage.
featureCalDAV: vCardVersion setting in AddressBook, which allows the default vCard version to be specified when the client does not request a specific version.
fixACME:
fixOrder and authorization failures are never logged, so an order rejected by the CA.
fixAn order rejected by the CA marks the renewal task as permanently failed.
fixCalDAV:
fixAttendee addresses whose mailto: URI percent-encodes a full name-addr are silently dropped from the scheduling snapshot.
fixAttendees whose calendar user address cannot be parsed should be flagged with SCHEDULE-STATUS=3.7.
fixThe 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.
fixMKCALENDAR, 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.
fixDirectory:
fixAn empty column, attribute or claim returned by an external directory is synchronized as an empty string rather than a missing value.
fix/api/discover splits the account name on @ without accounting for the % master user separator or the recovery administrator.
fixFoundationDB: Older chunked entries are not deleted.
fixIMAP: SETACL and DELETEACL fail to resolve an identifier spelled with uppercase characters.
fixiMIP: Invitations, replies and cancellations reference a TZID parameter with no matching VTIMEZONE component whenever the event was stored without one.
fixJMAP:
fixAddressBook/get: A new account's default address book is never recorded.
fixEmail/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.
fixEmail/set writes display names as an RFC 2047 encoded-word wrapped in a quoted-string, which RFC 2047 forbids.
fixMailbox/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.
fixPrincipal/query returns no results when the name or email filter is spelled with uppercase characters.
fixFileNode/set: File nodes created over JMAP are returned with a holding the raw name over WebDAV.
fixMeilisearch:
fixQueries return at most 1000 results, as the maxTotalHits pagination setting is left at the Meilisearch default.
fixSearches combining several terms return documents that match only some of them.
fixA task confirmation timeout is reported as a success when failOnTimeout is disabled.
fixImport: --import always aborts with the target database already containing data in the key range being imported.
fixMTA:
fixA 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.
fixis_local_address() and is_local_domain() expression functions do not match an address or domain spelled with uppercase characters.
fixRelay routes are rejected with host resolves loopback address, which prevents relaying through a local proxy or tunnel.
fixMySQL, 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.
fixNetwork: 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.
fixTask manager:
fixtotalDeadline is not enforced on tasks that fail with a specific retry time.
fixIndexing tasks are dropped after maxAttempts failures, so a search store that is unavailable or overloaded leaves messages permanently missing from the index.
fixIndexing 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.
fixThe DNS management task republishes the DKIM records of retired keys that the DKIM rotation task had already removed from the zone.
+3 more items in the release notesfeatureReporting: inboundReportMaxSize setting, which bounds the size of a decompressed inbound DMARC or TLS report (default 25MB).
featureRocksDB: cacheSize setting, which bounds the total memory shared by the block caches of every column family (default 128MB).
otherASN & 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.
otherJMAP: Identity/get keeps identities in sync with the account's e-mail addresses.
otherMTA: Queue scheduler no longer rescans the queue from the earliest pending event and coalesces bursts of delivery completions into a single scan.
otherRocksDB:
otherColumn families are tuned for the access pattern of the data they hold.
otherRange iteration uses bounded iterators and no longer reads values when only keys were requested.
fixJMAP:
fixSetting uploadTtl to 1ms triggers panic.
fixCalendarEvent/set does not assign organizerCalendarAddress nor send scheduling messages when an event is created with participants.
fixCalendarEvent/get omits isOrigin when it is listed explicitly in properties.
fixCalendarEventNotification/changes and FileNode/changes reject with cannotCalculateChanges the state that /get returned for an account with no change history.
fixCalendarEvent/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.
fixCalDAV: Attendee addresses that percent-encode a display name into the mailto: URI are queued verbatim.
fixCalendar: Recurring events disappear from CalDAV time-range REPORTs and JMAP CalendarEvent/query results a few years after their first occurrence.
fixWebDAV:
fixWhen a file node references a parent folder that no longer exists, any request on a file collection panics.
fixMOVE on a folder honors a Depth header of 0 or 1 instead of always moving the whole subtree.
fixMTA:
fixDSN bounces are emitted with a malformed Message-ID wrapped in doubled angle brackets.
fixDelivery to any MX host whose name is an IDN A-label fails permanently.
fixQueue strategy and quota expressions that branch on source never match at enqueue.
fixMTA-STS:
fixPolicies in testing mode are enforced, turning any TLS error into a permanent failure.
fixmx patterns published as U-labels never authorize the MX host they name.
fixDMARC:
fixAlignment compares identifiers in their A-label form.
fixExternal reporting addresses published as U-labels are rejected as unauthorized.
fixSpam filter:
fixSome rules misfire on internationalized addresses when the envelope and the headers spell the same domain in different label forms.
fixPunycode labels that do not re-encode to the label they came from are no longer decoded.
fixWebPush: Validate push URL and use application/octet-stream as Content-Type for encrypted payloads.
fixDirectory:
fixLocal group membership is cleared when the external directory is configured with a group claim or attribute that it does not return.
fixLDAP: Directories that store aliases as additional values of the primary address attribute provision no aliases.
fixMail 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.
fixRocksDB: bufferSize setting was applied to the unused default column family and had no effect.
fixSieve: include statements fail to find system and user global scripts whose name contains uppercase characters.
fixTask manager: totalDeadline is measured from the time a task was created instead of its first failed attempt.