App Suite Middleware
8.50.169
3rd Party Libraries/License Change
SCR-1780
Summary: Upgraded Apache CXF to 4.2.2 and Metro JAX-WS runtime to 4.0.5
Effective: applies to the 8.50 release line
Upgraded the SOAP stack embedded in the com.openexchange.soap.common bundle:
11
cxf-*libraries upgraded from 4.0.7 to 4.2.2jakarta.xml.ws-api-3.0.1.jarupgraded tojakarta.xml.ws-api-4.0.3.jarjaxws-rt-3.0.2.jar(Metro) upgraded tojaxws-rt-4.0.5.jarsaaj-impl-2.0.1.jarupgraded tosaaj-impl-3.0.6.jarneethi-3.2.1.jarupgraded toneethi-3.2.2.jar,xmlschema-core-2.3.1.jartoxmlschema-core-2.3.2.jar,gmbal-api-only-4.0.3.jartogmbal-api-only-4.1.2.jar,mimepull-1.9.15.jartomimepull-1.11.0.jar,streambuffer-2.0.2.jartostreambuffer-2.1.0.jar
The legacy javax.xml.ws compatibility libraries stay unchanged.
SCR-1774
Summary: Upgraded Hazelcast library to 5.7.0
Effective: applies to the 8.50 release line
Upgraded third-party library embedded in the com.hazelcast bundle:
hazelcast-5.3.8.jarupgraded tohazelcast-5.7.0.jar
Note for operators: Hazelcast Open Source does not support rolling upgrades across minor versions. During a deployment upgrade, middleware nodes running 5.7.0 will form a separate cluster from remaining 5.3.8 nodes until the rollout completes; cluster-wide volatile data (e.g. sessions held in Hazelcast maps) follows the usual full-cluster-upgrade semantics.
SCR-1773
Summary: Upgraded OWASP ESAPI library to 2.7.0.0
Effective: applies to the 8.50 release line
Upgraded third-party library embedded in the com.openexchange.common bundle:
esapi-2.0.1.jarupgraded toesapi-2.7.0.0.jar
Only the org.owasp.esapi.codecs package is consumed by the middleware (HTML entity decoding in com.openexchange.html); the new transitive dependency tree of the unused ESAPI reference implementation (antisamy, batik, httpclient) is excluded from the bundle.
SCR-1772
Summary: Upgraded Box Java SDK to 4.16.4
Effective: applies to the 8.50 release line
Upgraded third-party libraries embedded in the com.openexchange.file.storage.boxcom bundle:
box-java-sdk-2.54.0.jarupgraded tobox-java-sdk-4.16.4.jar(latest release of the classiccom.box.sdkAPI line; the 10.x line is a different, generated SDK with a new API)jose4j-0.5.5.jarupgraded tojose4j-0.9.4.jarzstd-jni-1.5.7-2.jarnewly embedded (response decompression support of the SDK)
The SDK now performs HTTP via OkHttp, which is consumed from the com.squareup.okhttp3 platform bundle; that bundle additionally exports the kotlin base package. File thumbnails are retrieved through the file representations endpoint, as the SDK removed the legacy thumbnail API.
SCR-1771
Summary: Upgraded Dropbox Core SDK to 8.0.1
Effective: applies to the 8.50 release line
Upgraded third-party library embedded in the com.openexchange.oauth.dropbox bundle:
dropbox-core-sdk-3.1.5.jarupgraded todropbox-core-sdk-8.0.1.jar
SCR-1770
Summary: Upgraded Apache XML-RPC libraries to 6.1.0
Effective: applies to the 8.50 release line
Upgraded third-party libraries embedded in middleware bundles:
com.openexchange.parallels:xmlrpc-client-5.0.0.jar,xmlrpc-common-5.0.0.jar,xmlrpc-server-5.0.0.jarupgraded to 6.1.0;ws-commons-util-1.0.2.jarupgraded tows-commons-util-1.1.0.jarcom.openexchange.eas.provisioning.action.sms:xmlrpc-client-5.0.0.jar,xmlrpc-common-5.0.0.jarupgraded to 6.1.0;ws-commons-util-1.0.2.jarupgraded tows-commons-util-1.1.0.jar
SCR-1769
Summary: Upgraded lib-recur library to 0.17.1
Effective: applies to the 8.50 release line
Upgraded third-party library embedded in the com.openexchange.chronos.common bundle:
lib-recur-0.10.jarupgraded tolib-recur-0.17.1.jarjems2-2.23.1.jarnewly embedded (required by lib-recur 0.17)
The recurrence rule expansion engine (org.dmfs.rfc5545.recur) is updated to the latest upstream release. The legacy recurrence-set helper classes that upstream removed in favor of a redesigned API are retained as sources in the bundle, so the iteration behavior of the calendar recurrence service is unchanged (verified by the full recurrence test suite, 50000+ tests).
SCR-1768
Summary: Upgraded ez-vcard library to 0.12.2
Effective: applies to the 8.50 release line
Upgraded third-party library embedded in the com.openexchange.contact.vcard.impl bundle:
ez-vcard-0.10.6.jarupgraded toez-vcard-0.12.2.jar
The vCard date mappings were adopted to the library's new java.time-based API. Date properties (BDAY, ANNIVERSARY) are now handled as LocalDate without the former local-timezone adjustment workarounds; the serialized vCard output is unchanged.
SCR-1767
Summary: Upgraded ROME, jaudiotagger, Caffeine, MaxMind GeoIP2 and libphonenumber libraries
Effective: applies to the 8.50 release line
Upgraded third-party libraries embedded in middleware bundles:
com.openexchange.rss:rome-1.19.0.jarupgraded torome-2.1.0.jar,rome-utils-1.19.0.jarupgraded torome-utils-2.1.0.jar(rome-fetcherstays at 1.19.0, no 2.x release exists)com.openexchange.server:jaudiotagger-2.2.5.jarupgraded tojaudiotagger-3.0.1.jarcom.openexchange.oauth.provider.impl:caffeine-2.8.5.jarupgraded tocaffeine-3.2.4.jarcom.openexchange.geolocation.maxmind.binary:geoip2-2.17.0.jarupgraded togeoip2-5.1.0.jar,maxmind-db-2.1.0.jarupgraded tomaxmind-db-4.1.0.jarcom.openexchange.sms:libphonenumber-8.13.1.jarupgraded tolibphonenumber-9.0.34.jar
SCR-1766
Summary: Upgraded webauthn-server-core, reactor-core and zero-allocation-hashing libraries
Effective: applies to the 8.50 release line
Upgraded third-party libraries embedded in middleware bundles:
com.openexchange.webauthn:webauthn-server-core-2.5.3.jarupgraded towebauthn-server-core-2.9.0.jar,yubico-util-2.5.3.jarupgraded toyubico-util-2.9.0.jario.lettuce:reactor-core-3.6.6.jarupgraded toreactor-core-3.8.6.jarnet.openhft.hashing:zero-allocation-hashing-0.16.jarupgraded tozero-allocation-hashing-2026.0.jar
SCR-1765
Summary: Upgraded BouncyCastle libraries to 1.84 in target platform
Effective: applies to the 8.50 release line
Upgraded BouncyCastle libraries in target platform (com.openexchange.bundles):
bcmail-jdk18on-1.79.jarupgraded tobcmail-jdk18on-1.84.jarbcpg-jdk18on-1.79.jarupgraded tobcpg-jdk18on-1.84.jarbcpkix-jdk18on-1.79.jarupgraded tobcpkix-jdk18on-1.84.jarbcprov-jdk18on-1.79.jarupgraded tobcprov-jdk18on-1.84.jarbcutil-jdk18on-1.79.jarupgraded tobcutil-jdk18on-1.84.jar
BouncyCastle 1.84 removed the legacy post-quantum algorithm packages org.bouncycastle.pqc.crypto.rainbow, org.bouncycastle.pqc.jcajce.provider.gmss and org.bouncycastle.pqc.jcajce.provider.mceliece; stale (unused) imports of these packages were removed from the com.openexchange.saml bundle manifest. The OpenPGP API change of PGPKeyEncryptionMethodGenerator.generate(...) was adopted in com.openexchange.pgp.core (wire format of generated PKESK packets is unchanged).
SCR-1762
Summary: Upgraded Liquibase to v5.0.3
Effective: applies to the 8.50 release line
Upgraded the embedded database migration engine in the encapsulated liquibase.core wrapper bundle:
liquibase-core-4.33.0.jarupgraded toliquibase-core-5.0.3.jaropencsv-5.11.2.jarupgraded toopencsv-5.12.0.jar
Liquibase 5.0.x is a major release, but the exported package set and external dependency surface are identical to 4.33.0, so Export-Package/Import-Package stay structurally unchanged. The in-house Liquibase extensions in com.openexchange.database.migration (custom ChangeLogHistoryService, XML changelog parser, preconditions, SLF4J logging) compile and pass their tests against the 5.0.3 SPIs without source changes.
Checksum stability was verified end-to-end against MariaDB: a DATABASECHANGELOG populated with legacy checksums is recognized as already-applied and left untouched (no changeset re-execution), preserving rollback compatibility.
8.50.165
General
SCR-1803
Summary: New properties for the replication monitor's replica status check
Effective: 8.50.165 and later
The replication monitor now probes read replicas' replication status (SHOW SLAVE STATUS) and redirects reads to the master while a replica reports broken replication or excessive lag. This closes the gap that a re-seeded or inconsistently restored replica could serve incomplete data undetected (middleware/core#4, follow-up to the incident behind appsuite/support#1599). Four new lean configuration properties control the behavior:
com.openexchange.database.replicationMonitor.checkReplicaStatus(default: true) - Whether to watch read replicas for broken or excessively lagging replication and redirect reads to the master meanwhile. Works out of the box: where the REPLICA MONITOR (MariaDB) or REPLICATION CLIENT (MySQL) privilege is available, the replication status statement provides fast, precise detection; without it the check falls back to a privilege-free heartbeat, a time stamp periodically written through the replication channel into the replicationMonitor table (reserved row cid=4294967295), needing only the regular INSERT/UPDATE/SELECT permissions.REPLICA MONITOR(MariaDB) or REPLICATION CLIENT (MySQL) privilege; both are global privileges, so one grant per database host covers all existing and future schemas, and initconfigdb -a now grants them automatically. Without the privilege the check suspends itself for the affected pool. Only effective if the replication monitor is active. Default: true. Reloadable: false. Config-cascade aware: false.com.openexchange.database.replicationMonitor.maxReplicaLag- Maximum tolerated replication lag in seconds before reads are redirected to the master. Default: 300. Reloadable: false. Config-cascade aware: false.com.openexchange.database.replicationMonitor.replicaStatusCheckInterval- Minimum number of seconds between two replication status probes per read pool. Default: 10. Reloadable: false. Config-cascade aware: false.com.openexchange.database.replicationMonitor.requireReplication- Whether a read host that does not act as a replica at all (emptySHOW SLAVE STATUS) is considered unhealthy. Keep false for Galera or multi-primary setups; set to true where read pools are always asynchronous replicas. Default: false. Reloadable: false. Config-cascade aware: false.
All four properties are read once at middleware start-up; changing them requires a restart. They are server-scoped (no config-cascade evaluation) and documented in documentation-generic/config/ConfigDB.yml. Defaults are safe for every topology: without the privilege or without asynchronous replication the check fails open and behavior is unchanged.
8.50.164
3rd Party Libraries/License Change
SCR-1749
Summary: Upgraded Grizzly to 5.0.2
Effective: 8.50.164 and later
Upgraded the encapsulated Grizzly libraries in the com.openexchange.http.grizzly PDE bundle:
grizzly-http-all-5.0.1.jarupgraded togrizzly-http-all-5.0.2.jargrizzly-framework-monitoring-5.0.1.jarupgraded togrizzly-framework-monitoring-5.0.2.jargrizzly-http-monitoring-5.0.1.jarupgraded togrizzly-http-monitoring-5.0.2.jargrizzly-http-server-monitoring-5.0.1.jarupgraded togrizzly-http-server-monitoring-5.0.2.jar
Resolved transitive shifts: gmbal/gmbal-api-only 4.1.1 -> 4.1.2, pfl-* 5.1.0 -> 5.1.1 (management-api unchanged at 3.3.0). No new or removed embedded dependencies.
Code adaptation
Grizzly 5.0.2 replaces the HttpResponsePacket acknowledgement API (setAcknowledgement()/acknowledged()) with an interim-response model (setInterimStatus()/interimResponseSent(), also covering 103 Early Hints). The custom codec filter (CustomHttpCodecFilter), which sends the 100 Continue interim response at header-parse time, now sets the interim status and lets the codec serialize the status line instead of hand-building the bytes. The wire format is unchanged (HTTP/1.1 100 Continue).
Behavioral change: strict RFC 9110 header validation enabled by default
Grizzly 5.0.2 enables strict RFC 9110 validation of HTTP header names (token rules) and header values (field-content rules) by default. Requests carrying malformed header names/values are now rejected with 400 Bad Request during parsing (hardening against request smuggling).
New configuration properties
The validation switches are exposed as lean OX configuration properties (no .properties file entry, read on server start):
com.openexchange.http.grizzly.strictHeaderNameValidation(default:true)com.openexchange.http.grizzly.strictHeaderValueValidation(default:true)
Setting a property to false restores the former lenient parsing for legacy clients. The OX properties are authoritative for the HTTP server codec and take precedence over the Grizzly JVM system properties org.glassfish.grizzly.http.STRICT_HEADER_NAME_VALIDATION_RFC_9110 / org.glassfish.grizzly.http.STRICT_HEADER_VALUE_VALIDATION_RFC_9110.
8.50.152
General
SCR-1800
Summary: New property to obtain IMAP subscription state from separate LSUB when the \Subscribed attribute of LIST-EXTENDED responses is untrustworthy
Effective: 8.50.152 and later
Motivation
On IMAP servers advertising the LIST-EXTENDED capability (RFC 5258), the middleware determines mailbox subscriptions from the single consolidated command LIST "" "*" RETURN (SUBSCRIBED CHILDREN [SPECIAL-USE]). Certain proxy setups (e.g. Dovecot with an imapc backend, see /appsuite/support#1543 and DOP-3897) answer the SUBSCRIBED return option inconsistently with LSUB: subscribed mailboxes in shared/user namespaces are listed without the \Subscribed attribute, so subscriptions to shared folders never become visible in App Suite.
Change
New lean configuration property (no .properties file entry):
- Key:
com.openexchange.imap.considerSubscribedInListExtended - Default:
true(unchanged behavior) - Reloadable: yes; config-cascade aware: no (server scope)
Supported values:
true: trust the attribute; subscription state comes from the single consolidated round-trip (behavior as before).false: hybrid mode; the consolidated command (withoutSUBSCRIBED) still provides hierarchy, children and special-use information, while a separateLSUB "" "*"provides the subscription state.probe: verify once per IMAP server whether the attribute matchesLSUBoutput and cache the verdict per server (lifetime governed bycom.openexchange.imap.cache.commonImapServerCacheTimeToLive). A probe is only conclusive if it either finds a mismatch or covers at least one subscribed mailbox inside a shared/user namespace; otherwise no verdict is cached and the next folder-cache initialization probes again. A probe run costs no additional IMAP round-trip compared to hybrid mode.
The property only takes effect on servers advertising LIST-EXTENDED; without that capability separate LIST/LSUB commands are issued anyway.
Operator action
None by default. Set the property to false (or probe) for installations whose IMAP server/proxy reports the \Subscribed attribute of the consolidated LIST command unreliably.
8.50.140
General
SCR-1793
Summary: Redis connector: per-node client name, max. connection lifetime, deterministic shutdown
Effective: 8.50.140 and later
Hardening of the Redis connector against stale / orphaned connected clients.
New configuration option:
com.openexchange.redis.connection.pool.maxLifetimeSecondsMaximum lifetime in seconds of a pooled Redis connection. Once a connection exceeds this age it is proactively recycled by the connection-pool cleaner as soon as it becomes idle, regardless of usage; this applies to both the shared and the dedicated pool. Acts as defense-in-depth against slowly accumulating or long-lived stale connections that TCP keepalive cannot reap (a live-but-idle connection is never detected as dead). A value of0(zero) disables max. lifetime recycling. Default3600(one hour). Not reloadable, not config.cascade aware. Package:open-xchange-core.
Behavioral changes (no configuration):
- Client name: the announced Redis client name now includes the local host / pod name (e.g.
Open-Xchange-Redis-Connector-v8.53.0-<host>), so connections become attributable per node via RedisCLIENT LIST. This is what lets operators tell restart orphans (dead pod addresses) apart from live-node connections. - Deterministic shutdown: the shared connection pool now closes its connections synchronously on shutdown, so Redis reclaims the clients immediately on a graceful (rolling) restart instead of leaving them as ghosts.
8.50.121
API - REST
SCR-1714
Summary: New Administrative REST Servlet for Shared Accounts
Effective: 8.50.121 and later
Permissions and capabilities a particular user effectively has for a shared account are not persisted as such, but evaluated dynamically at runtime - based on the base configuration and all shared account permissions the user received, directly as well as indirectly through his group memberships. Since this calculated result can therefore not be deduced directly from the provisioned data, a dedicated administrative REST interface is available that answers the question: which effective permissions and capabilities does a certain user have for a shared account?
The endpoints are exposed below /preliminary/sharedaccounts/v1 and are protected via HTTP Basic Authentication, with the credentials configured through the properties com.openexchange.rest.services.basic-auth.login and com.openexchange.rest.services.basic-auth.password.
The user whose access is to be evaluated - and, where applicable, the targeted shared account - can be referenced in three alternative ways: by their explicit internal identifiers, by their email address, or by their mail login string.
See the general documentation, as well as the REST API documentation for further details.
8.50.114
General
SCR-1708
Summary: Grizzly 5.0.1 + jakarta.servlet 6.1 introduction; CXF 4, JAX-WS RT 3, Angus Activation pulled in
Effective: 8.50.114 and later
- OSGi HTTP stack lifted to Jakarta Servlet 6.1
- Grizzly upgraded to 5.0.1 (JDK 21 baseline, virtual threads support)
- Grizzly HTTP filter chain (WrappingFilter, RequestReportingFilter, wrappers) runs natively on jakarta.servlet — no more javax↔jakarta bridging at the filter level.
- A parallel javax-servlet surface is kept alive via an in-process bridge so existing bundles and external consumers (Guard, OEM) continue to work unchanged.
Library updates
|| Library || Old || New || | Eclipse Grizzly | 2.4.4 | 5.0.1 | | Apache CXF | 3.5.11 | 4.0.7 | | Sun/Glassfish JAX-WS RT | 2.x | 3.0.2 | | Jolokia | 1.x | 2.x | | jakarta.servlet-api | — | 6.1.0 | | jakarta.xml.ws-api | — | 3.0.1 | | jakarta.jws-api | — | 3.0.0 | | jakarta.xml.bind-api | — | 3.0.1 | | jakarta.xml.soap-api | — | 3.0.2 | | jakarta.activation-api | — | 2.1.3 | | jakarta.annotation-api | — | 2.1.1 | | Eclipse Angus Activation (jakarta.activation SPI impl) | — | 2.0.2 | | gmbal | 4.0.3 | 4.1.1 | | management-api | 3.2.3 | 3.3.0 | | pfl-* | 4.1.2 | 5.1.0 |
Scope
com.openexchange.http.grizzlyported to Grizzly 5.0.1 / jakarta-servlet 6.1. Filter chain and servlet wrappers run natively on jakarta.servlet.HttpServletRequestWrapperimplementsHolders.RequestHolderfor direct Grizzly Request access.RequestWatcherServiceconverted to jakarta.servlet types.- ASM JARs removed from Grizzly bundle (resolved from target platform via Import-Package).
- New bridge bundle
com.openexchange.servlet.bridgeadapts javax↔jakarta requests/responses in both directions, enabling a gradual migration. - 11 SOAP stub bundles (
com.openexchange.admin.soap.{context,deputy,group,reseller,resource,secondaryaccount,sharedaccount,taskmgmt,user,usercopy,util}) pluscom.openexchange.sessiond.soapandopenexchange-testmigrated tojakarta.xml.ws/jakarta.jws. - DAV/CalDAV/CardDAV, Prometheus exporter, Jolokia and R8 whiteboard servlets now use jakarta-servlet natively.
- Existing javax-servlet consumers keep running via the bridge.
Compatibility
No breaking changes for external RMI/SOAP consumers. External plug-ins that reference javax.servlet wrapper classes directly need no changes — the javax.servlet 4.0 Import-Package surface is preserved.
8.50.112
API - HTTP-API
SCR-1711
Summary: Added new cluster-internal REST endpoint to validate Middleware sessions for the JMAP-IMAP proxy
Effective: 8.50.112 and later
Motivation
The HTTP/REST API previously had no entry point that lets the cluster-internal JMAP-IMAP proxy resolve a user's Middleware session into the IMAP backend coordinates and credentials it needs to forward JMAP calls. Standalone JMAP clients can authenticate against the proxy directly via HTTP Basic / OIDC -- the App Suite UI cannot, because it only carries a Middleware session cookie.
This SCR closes that gap with a dedicated cluster-internal REST endpoint, hardened against credential exposure.
New Endpoint
- Method + path:
GET /preliminary/mail/v1/validate-session/<session> - Bundle:
com.openexchange.mail.rest(new), registered viaopen-xchange-core.psf - Required path parameter:
session-- the Middleware session identifier (length-capped to 128 chars) - Required header:
X-OX-Session-Secret-- the plain value of the user'sopen-xchange-secret-<hash>cookie, forwarded by the proxy from the originating client request (length-capped to 512 chars) - HTTP Basic-Auth: gated by
Role.BASIC_AUTHENTICATED(cluster-internal REST credentialscom.openexchange.rest.services.basic-auth.*; identical toSessionRESTService)
The session is resolved in a touch-free manner via SessiondService.peekSession(String); repeated polling does not reset the session's idle expiration counter, so the proxy can poll at ~30 s without keeping otherwise idle sessions alive.
Response: AES-256-GCM Envelope
Because the response carries the user's plaintext mail password (LOGIN flow) / OAuth access token plus internal infrastructure details (IMAP host name, login, primary email), the entire success body is wrapped in an AES-256-GCM envelope.
Wire format on HTTP 200:
{
"v": 1,
"envelope": "v1:<base64-iv>:<base64-ct-with-tag>"
}
The ciphertext decodes to the inner payload:
{
"identity": { "user", "context", "displayName", "primaryEmail" },
"imap": { "host", "port", "secure" },
"auth": { "type", "loginName", "secret", "secretExpiresInSeconds" },
"session": { "expiresInSeconds" }
}
auth.type ∈ `{LOGIN, XOAUTH2, OAUTHBEARER\}, mirroring the Middleware-internal AuthType` enum.
A fresh 12-byte random IV is generated per call. The caller's Basic-Auth identity (UTF-8 bytes) is additionally bound into the GCM authentication tag via Associated Authenticated Data, so an envelope captured from one caller cannot be successfully decrypted with a different caller's credentials. The proxy must pass the byte-identical AAD when decrypting; the wire format itself remains unchanged.
Error responses (401/403/429/503/500) are plaintext OX-error-JSON so the proxy can forward them to the originating client untouched.
Example request:
GET /preliminary/mail/v1/validate-session/abc123def456
Authorization: Basic <base64 of proxy credentials>
X-OX-Session-Secret: <secret cookie value>
Authentication
The endpoint enforces two independent authentication layers:
AuthorizationBasic-Auth gates the caller (proves "you're the JMAP-IMAP proxy"). Cluster-internal credentials, same pool as other internal REST endpoints.X-OX-Session-Secretcompared againstsession.getSecret()in constant time (viaMessageDigest.isEqual) so the comparison's running time does not leak information about which bytes already matched. Prevents resolving arbitrary session identifiers -- the caller must have seen the user's actual cookies, otherwise the lookup fails.
After 5 consecutive secret-mismatch attempts on the same session identifier within a 10-minute window, the session itself is invalidated cluster-wide via SessiondService.removeSession(..., ADMIN_CLOSED). A legitimate proxy call never produces a mismatch, so the threshold cannot fire on real traffic.
Sessions whose OAuth access-token expiry (Session.PARAM_OAUTH_ACCESS_TOKEN_EXPIRY_DATE) is in the past are rejected upfront with SES-0203 rather than handed out as a dead token.
Error Handling
- HTTP 401 (Basic-Auth missing/invalid) -- handled by the REST stack before the resource method runs.
- HTTP 401 with OX error JSON (
SES-0203 SESSION_EXPIRED) -- raised on unknown / expired sessions, missing / mismatchingX-OX-Session-Secret, or expired OAuth tokens. TheOXExceptionchain matchesSessionUtility.checkSecretbyte-for-byte (OXEXCEPTION_PROPERTY_SESSION_EXPIRATION_REASONcarriesNO_SUCH_SESSION,NO_EXPECTED_SECRET_COOKIEorSECRET_MISMATCH), so the proxy can forward the resulting error JSON to the originating client untouched and the standardSES-0203handling kicks in. - HTTP 403 with OX error JSON (
MAIL-0114 MAIL_ACCESS_DISABLED) -- raised when the user has no primary mail account or the primary account is disabled. - HTTP 403 -- raised when TLS is required (
com.openexchange.mail.rest.requireTls=true, default) and the request is not secure, or when the source IP is not contained in the configured allowlist (com.openexchange.mail.rest.allowedSourceIPs). - HTTP 429 (empty body) -- raised when a Basic-Auth identity exceeds 6 000 requests per minute. The proxy should treat this as a load signal and back off exponentially; do not forward to the originating client.
- HTTP 503 with OX error JSON -- raised when the server-side AES-256 encryption key is missing or invalid. Fails closed: the endpoint never serves a plaintext fallback.
Operational Hardening
Cache-Control: no-store, no-cache, must-revalidate+Pragma: no-cacheon every response so no HTTP intermediary along the in-cluster path persists the (encrypted) body.- Every call is audit-logged via
AuditLogServicewith an outcome-specific event id (ox.mail.validateSession.success,ox.mail.validateSession.session-expired.<reason>,ox.mail.validateSession.mail-access-disabled,ox.mail.validateSession.error). Caller identity, session id and timestamp only; never the supplied secret value, never the user's password / token.
Configuration
The endpoint introduces a small set of properties, documented and tracked separately in SCR-1712:
com.openexchange.mail.rest.encryption.key(required) -- the AES-256 key shared with the JMAP-IMAP proxycom.openexchange.mail.rest.requireTls(defaulttrue) -- toggle for TLS enforcementcom.openexchange.mail.rest.allowedSourceIPs(default empty) -- optional source-IP allowlist
The endpoint additionally reuses:
com.openexchange.rest.services.basic-auth.login/.password-- the cluster-internal REST credentials (shared with the otherRole.BASIC_AUTHENTICATEDendpoints)com.openexchange.sessiond.sessionDefaultLifeTime/sessionLongLifeTime-- session lifetime estimation
SCR-1695
Summary: New Action 'hasActive' in Module 'mailfilter/v2'
Effective: 8.50.112 and later
In order to get a quick information if there are currently specific mail filter rules active or not for an account, the new action hasActive is introduced in module mailfilter/v2 of the HTTP API.
See the API documentation for further details.
SCR-1692
Summary: Additional Field 'com.openexchange.imap.rootFolderStatus' for Mail Account Root Folders
Effective: 8.50.112 and later
The folder model (FolderResponseData) of the HTTP API is extended by the additional read-only field com.openexchange.imap.rootFolderStatus (column id 3053). It is only available for the special, virtual mail account root folders (e.g. with if default0 or default14), if supported by the underyling IMAP server.
It contains information about the data within the mail account as JSON object - which currently is a simple overall containsUnread flag that is true whenever there is an unseen message within any of the contained mail folders.
See the documentation for further details.
Configuration
SCR-1696
Summary: New Configuration Property 'com.openexchange.mail.filter.options.vacation.minimumInterval.seconds'
Effective: 8.50.112 and later
A new property com.openexchange.mail.filter.options.vacation.minimumInterval.seconds has been introduced to allow configuring the minimum interval for seconds-based vacation Sieve rules.
When set to -1 (default), the use of seconds-based vacation rules is disabled. Any positive value defines the minimum number of seconds that must elapse between automated vacation responses sent to the same sender.
This property only takes effect if the IMAP server advertises the vacation-seconds capability.
See the [property documentation](https://documentation.open-xchange.com/components/middleware/config/8/#mode=search&term=com.openexchange.mail.filter.secondary.) for further details.
8.50.108
Configuration
SCR-1713
Summary: New and changed configuration defaults for database connection pool admission control, worker thread pool, and health check
Effective: 8.50.108 and later
New and changed configuration defaults to prevent thundering-herd death spirals during Kubernetes autoscaler scale-up events (see support#1477 and core#520).
Connection pool admission control
maxWaitingMaximum number of threads allowed to wait for a database connection when the pool is exhausted andexhaustedActionis set toBLOCK. If this limit is reached, additional requests fail immediately with an exception instead of blocking. This prevents unbounded thread accumulation during load spikes (e.g. cold-cache stampedes after autoscaler scale-up events). A value of-1means unlimited (no cap on waiting threads). Shipped default400(4xmaxActive); set-1to restore the previous unlimited behavior. Not reloadable, not config-cascade aware. File:configdb.properties.
Database pool readiness health check
Two properties control a new database-pool health check that is wired into the /ready readiness endpoint. When the check reports DOWN, Kubernetes stops routing traffic to the pod.
com.openexchange.database.health.poolUtilizationThresholdThe database connection pool utilization percentage (0-100) at or above which the readiness health check reports DOWN. Default90. Not reloadable, not config-cascade aware. File:configdb.properties.com.openexchange.database.health.maxWaitingThresholdThe maximum number of threads waiting for a database connection above which the readiness health check reports DOWN. Default500. Not reloadable, not config-cascade aware. File:configdb.properties.
8.50.96
Configuration
SCR-1712
Summary: New configuration options for the validate-session REST endpoint
Effective: 8.50.96 and later
New configuration options for the cluster-internal validate-session REST endpoint (see SCR-1711)
com.openexchange.mail.rest.encryption.keyShared secret string from which the AES-256 key for wrapping the validate-session response body (identity, IMAP coordinates, credentials) in an AES-256-GCM envelope is derived. The byte-identical secret must be provisioned on the JMAP-IMAP proxy side so the proxy can derive the same key, decrypt the response, and recover the IMAP backend coordinates plus the user's plaintext password / OAuth access token. <b>Key derivation</b>: the configured value is trimmed and then hashed once with SHA-256 over its UTF-8 bytes; the 32-byte digest is the AES-256 key. The proxy must reproduce this derivation exactly. No salt and no iteration count are involved, so the secret itself must carry enough entropy (a long random string, not a passphrase). Minimum length is 16 characters after trimming; shorter values are rejected fail-closed. Generate a fresh secret via e.g.openssl rand -hex 32(64 hex chars) orpwgen -s 64 1; use a different secret per environment; rotate it independently of the SessionD encryption key and the cluster-internal REST basic-auth password. The caller's Basic-Auth identity is bound into the GCM tag as Associated Authenticated Data, so an envelope captured from one caller cannot be decrypted with another caller's credentials. <b>Fail-closed</b>: if the property is unset, blank, or shorter than the minimum length, the endpoint responds with HTTP 503 instead of returning a plaintext payload. No default. Not reloadable, not config.cascade aware.com.openexchange.mail.rest.requireTlsWhether the validate-session REST endpoint rejects non-TLS requests with HTTP 403. Defaults totrue(fail-secure) so that even an accidental plain-HTTP route to the endpoint cannot expose the encrypted-but-still-sensitive validate-session payload. Set tofalseonly in deployments where the in-cluster path from the JMAP-IMAP proxy to the Middleware is known to be plain-HTTP by design (e.g. when TLS is terminated upstream of the Middleware container and the request is delivered via cleartext within a trusted pod network). Defaulttrue. Reloadable, not config.cascade aware.com.openexchange.mail.rest.allowedSourceIPsOptional comma-separated allowlist of source addresses permitted to call the validate-session REST endpoint. When set, only requests originating from one of the listed addresses are accepted; everything else is rejected with HTTP 403 before any further processing. The value is parsed viacom.openexchange.net.HostListand therefore supports individual IP addresses, CIDR ranges (e.g.10.42.0.0/16,2001:db8::/32), and host names. Defaults to empty, meaning no allowlist filter is applied. Defense-in-depth on top of the cluster-internal ingress restriction that already keeps/preliminary/*off the public network. Example:10.42.0.0/16, 192.168.1.100. No default. Reloadable, not config.cascade aware.
8.50.90
API - HTTP-API
SCR-1710
Summary: Added new HTTP-API end-point to fetch a mail by its GUID
Effective: 8.50.90 and later
Motivation
The HTTP API currently only allows resolving a mail via its (folder, UID) tuple. For clients that hold a globally unique identifier (GUID) advertised by the mail backend (such as Dovecot's X-GUID attribute), no entry point exists. This SCR introduces a new read-only AJAX action that performs a GUID-based look-up.
New Action
- Module:
mail - Action:
getByGuid - Method:
GET - Required parameter:
guid— the GUID as advertised by the mail backend - Optional parameter:
folder— restricts the look-up to that folder; when omitted, the action queries the virtual "all messages" mailbox configured via propertycom.openexchange.find.basic.mail.allMessagesFolder - Response:
MailResponse} (same payload asaction=get); for cross-folder look-ups the response carriesoriginal_folder_idandoriginal_id` to identify the source folder.
Example:
GET /ajax/mail?action=getByGuid&guid=deadbeefcafe1234&session=...
GET /ajax/mail?action=getByGuid&guid=deadbeefcafe1234&folder=default0/INBOX&session=...
Capability Gating
The action requires the underlying mail backend to advertise GUID support. If the backend does not support it, or if cross-folder look-up is requested but com.openexchange.find.basic.mail.allMessagesFolder`` is empty, the request fails with MAIL_FILESTORE-0030 (UNSUPPORTED_OPERATION`).
If no mail matches the supplied GUID, the request fails with MAIL-0032 (MAIL_NOT_FOUND).
Configuration
No new properties are introduced. The existing property com.openexchange.find.basic.mail.allMessagesFolder (already used by the Find module) gates the cross-folder code path.
8.50.77
Configuration
SCR-1706
Summary: New configuration options for externalizing data: URL inline images
Effective: 8.50.77 and later
New lean configuration options for externalizing data: URL inline images
com.openexchange.html.inlineDataUrls.extractWhetherdata:URL inline images embedded in an HTML mail body shall be externalized into managed-file body parts and replaced withcid:references before the HTML size check (com.openexchange.html.maxLength) is applied. This avoids degrading to plain text for mails whose only oversize-cause is one or more inflated base64 inline images. Default true. Reloadable, but not config.cascade aware.com.openexchange.html.inlineDataUrls.minPartSizeMinimum size in bytes of a decodeddata:URL inline image to qualify for externalization. Smaller payloads (e.g. tiny tracking pixels) are left in place because the synthetic body part overhead would outweigh the savings. Default 4096. Reloadable, but not config.cascade aware.com.openexchange.html.inlineDataUrls.maxPartSizeMaximum size in bytes of a single decodeddata:URL inline image. Larger payloads are left in place; the regular HTML size check then governs whether the mail is rendered as HTML or as plain text. Default 26214400. Reloadable, but not config.cascade aware.com.openexchange.html.inlineDataUrls.maxTotalSizeAggregate cap in bytes across alldata:URL inline images that may be externalized from a single HTML body. Also used to relax the HTML size check by the same amount when extraction is enabled (relaxed cap iscom.openexchange.html.maxLength + this). Default 52428800. Reloadable, but not config.cascade aware.com.openexchange.html.inlineDataUrls.ttlSecondsTime-to-live in seconds for managed files that hold the bytes of extracteddata:URL inline images. Must be long enough to cover the time between HTML render and the client's image fetches. On miss, theInlineImageDataSourceworst-case fallback re-extracts the image from the source mail. Default 1800. Reloadable, but not config.cascade aware.
8.50.74
3rd Party Libraries/License Change
SCR-1707
Summary: Upgraded Liquibase from forked 3.0.7 to upstream 4.33.0
Effective: 8.50.74 and later
Replaced the bespoke liquibase.core/ source fork with a thin OSGi JAR-wrapper that ships the official upstream artifacts:
liquibase-core-4.33.0.jaropencsv-5.11.2.jar
Adapter changes in com.openexchange.database.migration
Slf4jLoggerreimplemented againstliquibase.logging.Logger(severe/warning/info/config/fine/debug +log(Level,String,Throwable))- new
Slf4jLogServiceregistered viaMETA-INF/services/liquibase.logging.LogServicewith priority 5 BundleResourceAccessorrewritten against the newResourceAccessorcontract (search / getAll / describeLocations,AbstractResource-backedBundleResource)BundlePackageScanClassResolverremoved - the oldServiceLocator-based package scan is replaced byjava.util.ServiceLoaderplus the OSGi activator's bundle trackingDBMigrationActivatorno longer sets aCustomResolverServiceLocatorStaleMigrationDetectingLockServiceswitched fromLogFactorytoScope.getCurrentScope().getLog(getClass())
Namespace tolerance
Added liquibase.parser.ext.UrnNamespaceTolerantXMLChangeLogParser which rewrites the legacy urn:liquibase namespace to the canonical http://www.liquibase.org/xml/ns/dbchangelog on the fly so the four existing changelog XMLs (configdbChangeLog, globaldbChangeLog, resellerConfigdbChangeLog, autocidConfigdbChangeLog) continue to parse without modifications. Registered via META-INF/services/liquibase.parser.ChangeLogParser with a +10 priority bump.
Rollback compatibility (legacy MD5SUM preservation)
To allow rollback to a pre-Liquibase-4 OX container, the DATABASECHANGELOG table must keep its version-7 checksum prefix the old fork understands. Two safety nets are in place:
LegacyChecksumPreservingHistoryServiceextendsStandardChangeLogHistoryServiceand no-opsupgradeChecksums+replaceChecksum. Liquibase 4.x still recomputes hashes in memory and matches them with multi-algo tolerance, so legacy7:entries continue to be recognized as already-run; only the persistence side is blocked. Registered viaMETA-INF/services/liquibase.changelog.ChangeLogHistoryServicewith a +10 priority bump.LiquibaseHelper.snapshotLegacyChangelogIfNeededcopiesDATABASECHANGELOGintoDATABASECHANGELOG_BACKUP_LQ4on the very first 4.x boot per schema (idempotent, skipped on fresh schemas and on subsequent boots). Failures are logged, not thrown - a failed snapshot must not block the migration.
8.50.69
Database
SCR-1709
Summary: Enlarge the "meta" column from BLOB to MEDIUMBLOB for the "oxfolder_tree" and "del_oxfolder_tree" tables
Effective: 8.50.69 and later
Added new update task com.openexchange.groupware.update.tasks.EnlargeMetaForOXFolderTablesTask enlarging the "meta" column from BLOB to MEDIUMBLOB for the "oxfolder_tree" and "del_oxfolder_tree" tables
8.50.10
Configuration
SCR-1694
Summary: Added several configuration options to mitigate too many SMTP connections
Effective: 8.50.10 and later
com.openexchange.smtp.enablePipeliningSpecifies if the "PIPELINING" extension of an SMTP server should be used. Default is true. Reloadable and config-cascade awarecom.openexchange.smtp.pool.enabledEnables or disables the SMTP connection pool. Default is false. Reloadable and config-cascade awarecom.openexchange.smtp.pool.maxIdlePerKeySpecifies the max. number of idle pooled SMTP connections per SMTP end-point. A vale of equal to/less than 0 (zero) means infinite. Default is 5. Reloadable and config-cascade awarecom.openexchange.smtp.pool.maxIdleMillisSpecifies the time in milliseconds an SMTP connection may reside idle in pool before it is dropped. Default is 10000. Reloadable and config-cascade awarecom.openexchange.smtp.pool.maxLifetimeMillisSpecifies the max. lifetime in milliseconds an SMTP connection regardless if idle or was in use. Default is 300000. Reloadable and config-cascade awarecom.openexchange.smtp.pool.testOnBorrowSpecifies whether an SMTP connection is checked if still orderly connected when borrowed. Default is true. Reloadable and config-cascade awarecom.openexchange.smtp.pool.testOnReturnSpecifies whether an SMTP connection is checked if still orderly connected when returned. Default is false. Reloadable and config-cascade awarecom.openexchange.smtp.pool.cleanupIntervalMillisSpecifies the frequency to check for timed out idle SMTP connections. Default is 3500. Reloadable and config-cascade awarecom.openexchange.smtp.pool.maxConnectionsPerKeySpecifies the max. number of total SMTP connections that are permitted for a user to a certain SMTP end-point. A vale of equal to/less than 0 (zero) means infinite. Default is 8. Reloadable and config-cascade awarecom.openexchange.smtp.pool.borrowWaitMillisSpecifies the max. time in milliseconds to wait for an SMTP connection available in pool. Default is 5000. Reloadable and config-cascade awarecom.openexchange.mail.scheduled.checkAndSendDueScheduledMailsThe switch to allow per node/JVM to perform the check and transport of due scheduled mails. Default is true. Reloadable, but not config-cascade awarecom.openexchange.mail.scheduled.transport.maxNumberOfConcurrentScheduledMailsThe max. total number of scheduled mails (of all users) that are allowed being concurrently sent. Default is 0 (infinite). Reloadable, but not config-cascade awarecom.openexchange.mail.scheduled.transport.globalLimitWhether com.openexchange.mail.scheduled.transport.maxNumberOfConcurrentScheduledMails property refers to a global limit or per JVM/node only. Default is true. Reloadable, but not config-cascade awarecom.openexchange.mail.scheduled.transport.leaseDurationMillisThe duration (or time-to-live) in milliseconds a leased transport permit is considered as valid before it times out. Default is 60000. Reloadable, but not config-cascade awarecom.openexchange.mail.scheduled.transport.acquireTimeoutMillisThe duration in milliseconds to wait for a transport permit to become available. 0 (zero) merans to wait until a permit is available. Default is 0 (no wait). Reloadable, but not config-cascade aware