Databases upgrade automatically (schema 6012 → 6014) via the bundled DBUpdater. Take a backup before installing a pre-release. The built-in ACME client never worked against a real Let's Encrypt — fixed (#34)
Issue #34 reported certificate issuance failing every time against Let's Encrypt production with "Authorization offers no http-01 challenge", while an independent client succeeded within seconds — an excellent report that had already ruled out DNS, CAA, firewalling and stale authorizations.
The cause was ours, and it was one line: boulder — the software behind Let's Encrypt staging and production — pretty-prints its JSON, "type": "http-01" with a space after the colon. The challenge locator searched for the compact form, "type":"http-01", which can never match a real Let's Encrypt response. Every issuance failed at the first authorization with a message that blamed the CA for a parse miss on our side. The rest of the client's JSON handling was already whitespace-tolerant; this one search was the only compact-form assumption — and the one an issuance cannot get past.
The locator now tolerates any whitespace and checks context (the string must actually be a "type" key's value), and the real CA's response shape is pinned by self-tests so it cannot regress. The two diagnosability gaps the reporter named are also fixed: every failure message now says which domain it is about — three CNAME'd hostnames were indistinguishable in the log — and the no-challenge refusal now includes the CA's actual response, the only evidence of what was really offered. Log lines stopped going missing for forty minutes at a time (#33)
With Keep log files open enabled, each log line sat in a ~4 KB write buffer until enough later lines arrived to push it out — the close-per-line that the setting skips was the only flush. On a quiet server the tail of a session stayed invisible, cut off mid-line, for as long as nothing else happened; issue #33's reporter measured forty minutes. The logger now hands every line to the operating system as it is written — a visibility flush, deliberately not a physical disk sync — so the file is complete up to the last event the moment it happened. The setting keeps its actual saving, which is the open/close per line. (Installations without the setting were never affected, which is also why 1,589 regression tests never noticed.) Microsoft 365: ready for the Basic-auth shutdown, four months early
Microsoft shuts off Basic authentication for SMTP relay in December 2026. This build implements the XOAUTH2 bearer login Microsoft requires, in both directions:
- Outbound relay: when a route's destination is on the configured OAuth host list, AUTH presents a bearer token in Microsoft's exact one-round-trip XOAUTH2 shape instead of LOGIN with a password. Tokens are fetched with the client-credentials flow, cached to 80% of their lifetime, and invalidated on refusal. The host list is the safety: a token presented to the wrong relay is a leaked token, so unlisted relays keep their password login unchanged.
- POP3 collection: external accounts fetching from Microsoft 365 authenticate the same way. The password is deliberately not a fallback — a provider configured for OAuth has Basic auth off, and a quiet downgrade would send a password to a server that no longer wants one.
- The Control Panel's Relayer page carries the new settings with an explanation of each.
Sieve filtering grows up
The Sieve engine now implements and advertises, end to end, with delivery-side tests asserting where messages were actually filed: variables (RFC 5229), editheader (RFC 5293) with the protected-header rule, duplicate (RFC 7352), reject/ereject (RFC 5429) generating real DSNs, include (RFC 6609) with per-script variable scopes, enotify (RFC 5435, mailto), date/currentdate with :index and :zone (RFC 5260), spamtest (RFC 5235) reading the server's own verdict — never a header a sender could forge, ihave/environment (RFC 5463/5183), mailboxexists, and :regex — wearing the same runaway-pattern circuit breaker as the rules engine, because a hostile pattern should suspend itself, not the server.
ManageSieve refusals now carry machine-readable response codes alongside the prose, and RENAMESCRIPT — promised by the capability line all along — is implemented.
Eleven IMAP extensions, one theme: stop making clients guess
- APPENDLIMIT (RFC 7889): the upload size limit was always enforced but undiscoverable — clients learned it by uploading and failing. Now advertised exactly (per-account, in bytes), answered via STATUS, and oversize refusals carry TOOBIG.
- LITERAL- (RFC 7888): {n+} literals stop being answered with continuations the client never reads; a LOGIN or small APPEND now needs one round trip.
- LIST-STATUS (RFC 5819): a client syncing N mailboxes at startup issues one LIST instead of one STATUS per mailbox.
- UNAUTHENTICATE (RFC 8437): a session can hand the user back and be reused. The per-connection failed-login counter deliberately survives, so the command cannot reset the brute-force cap.
- QUOTA modernised (RFC 9208):
QUOTA=RES-STORAGE advertised, quota refusals carry OVERQUOTA, SETQUOTA is recognised and refused with an explanation (quotas are administrative), and the reply for an account without a quota is now grammatically valid. - PREVIEW (RFC 8970): the server hands clients a body snippet, so a message list renders without fetching bodies. HTML-only messages are stripped to text; the RFC's 256-octet ceiling is enforced on a UTF-8 boundary.
- MULTIAPPEND (RFC 3502): several messages in one APPEND, atomically — refusing any message means storing none, which is the entire difference from N separate APPENDs. Composes with LITERAL- into a single round trip; APPENDUID carries the whole uid-set.
- REPLACE (RFC 8508): saving a draft stops being APPEND + STORE \Deleted + EXPUNGE. The replacement is stored first, so a failed append leaves the original untouched.
- SAVEDATE (RFC 8514, schema 6013): when a message was saved into its mailbox, as its own column — INTERNALDATE must survive COPY, the save date must not, and one field cannot do both. FETCH item and all four search keys.
- METADATA (RFC 5464, schema 6014): annotations on mailboxes and the server, with DEPTH/MAXSIZE options, atomic SETMETADATA, and shared entries visible to every session with access to the folder.
- Outbound SIZE (RFC 1870) on the SMTP client: MAIL FROM declares the message size, and a message above the remote's advertised limit is refused locally before the upload — some servers only enforce their limit after DATA. Building this exposed that the client only spoke EHLO on routes needing TLS or authentication, so ordinary MX-to-MX deliveries never learned the remote's capabilities at all; EHLO is now the opener on every delivery, with the HELO fallback kept.
Also in this build
- Schema 6012: an auto-reply can be given a start date as well as an end date, and rule criteria accept patterns up to 2,000 characters. A COM interface that reported bare HRESULTs for every error it ever raised now reports the actual message.
- Vacation-message begin dates, the rule-criteria length limit and the M365 relay settings are all editable in the Control Panel.
Known issues and honest gaps
- BINARYMIME, IMAP BINARY, CATENATE/URLAUTH,
COMPRESS=DEFLATE and OBJECTID remain unimplemented; the roadmap describes each honestly. - Outbound PIPELINING/CHUNKING: the delivery client is strictly one-command-one-reply. Round-trip optimisations, not correctness gaps.
- Equal-preference MX records are still not randomised (RFC 5321 5.1).