App Suite Middleware
8.51.133
3rd Party Libraries/License Change
SCR-1745
Summary: Updated Netty libraries from v4.1.132 to v4.1.135
Effective: applies to the 8.51 release line
Updated Netty libraries from v4.1.132 to v4.1.135 in bundle io.netty
netty-buffer-4.1.135.Final.jarnetty-codec-4.1.135.Final.jarnetty-codec-dns-4.1.135.Final.jarnetty-codec-http2-4.1.135.Final.jarnetty-codec-http-4.1.135.Final.jarnetty-codec-socks-4.1.135.Final.jarnetty-common-4.1.135.Final.jarnetty-handler-4.1.135.Final.jarnetty-handler-proxy-4.1.135.Final.jarnetty-resolver-4.1.135.Final.jarnetty-resolver-dns-4.1.135.Final.jarnetty-transport-4.1.135.Final.jarnetty-transport-native-unix-common-4.1.135.Final.jarnetty-transport-classes-epoll-4.1.135.Final.jarnetty-transport-native-epoll-4.1.135.Final.jarnetty-transport-classes-kqueue-4.1.135.Final.jarnetty-transport-native-kqueue-4.1.135.Final.jarnetty-tcnative-classes-2.0.80.Final
Database
SCR-1721
Summary: CacheService Database Load Optimization
Effective: applies to the 8.51 release line
Based on customer feedback and analysis of logs and metrics, we identified that the CacheService could generate significant database load spikes during scheduled cleanup operations. This behavior may negatively affect Core-MW database workloads when both services are configured to use the same database server. The impact is most noticeable in environments where DocumentConverter(s) or ImageConverter(s) store millions of cached entries.
Database structure migration The underlying database structure of the CacheService has been redesigned. The migration is carried out in two distinct phases to allow both versions of the service to run in parallel during the transition period.
Phase 1 — Introduction of the new version (8.51) When the new version of the CacheService is introduced, the new database structure becomes active by adding new tables. At this point, the old database tables are emptied and the associated object store contents are removed. Both the old and new versions of the service can be operated in parallel during this phase without conflict.
Phase 2 — Final cleanup At a later point, the old database tables are dropped and any remaining storage is cleaned. This step establishes a consistent state and ensures the environment is fully prepared to move forward with the new structure exclusively.
No action required. Both phases are performed automatically during rollout. Administrators do not need to take any manual steps under normal circumstances. Data held in the old tables and object stores will not be used by the new version of the CacheService. The final cleanup is performed automatically unless configured otherwise. If manual execution is preferred, the necessary steps are provided with the corresponding release.
In rare cases, such as temporary database connectivity issues during rollout or deployments on particularly slow clusters, manual intervention may be necessary. If CacheService logs continue to report database-related errors more than five minutes after the rollout has completed, administrators should restart the DocumentConverter and ImageConverter pods to re-establish their CacheService connections.
The following improvements have been implemented in detail. Refactoring design decisions are linked as well:
- Refactored database structure to improve request and interval-based cleanup efficiency ([https://gitlab.com/openxchange/appsuite/converters/cacheservice/-/blob/main/documentation/adr/fcv-5_optimized%20database_storage_and_cleanup_coordination.md?ref_type=heads])
- Improved interval-based cleanup to happen on one CS pod at a point of time only ([https://gitlab.com/openxchange/appsuite/converters/cacheservice/-/blob/main/documentation/adr/fcv-7_distributed_cleanup_job_coordination.md?ref_type=heads])
8.51.128
General
SCR-1803
Summary: New properties for the replication monitor's replica status check
Effective: 8.51.128 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.51.127
3rd Party Libraries/License Change
SCR-1749
Summary: Upgraded Grizzly to 5.0.2
Effective: 8.51.127 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.51.112
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.51.112 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.51.99
General
SCR-1793
Summary: Redis connector: per-node client name, max. connection lifetime, deterministic shutdown
Effective: 8.51.99 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.51.95
Behavioral Changes
SCR-1723
Summary: Java 25: virtual-thread HTTP worker pool and opt-in generational ZGC
Effective: 8.51.95 and later
Full admin guide: https://documentation.open-xchange.com/8/middleware/administration/garbage_collection_and_memory_sizing.html
Change
The core middleware now runs on Java 25 (JDK 25 runtime). Operationally relevant defaults that change with this upgrade:
- Virtual-thread HTTP worker pool — the Grizzly request workers run on virtual threads by default (
com.openexchange.http.grizzly.virtualThreadsEnabled=true), raising in-flight request concurrency. - Compact Object Headers (
-XX:+UseCompactObjectHeaders, JEP 519) are enabled viajavaOpts.other, reducing live heap.
The garbage collector default is unchanged: G1 stays the default. Generational ZGC is available as an opt-in alternative via the Helm value javaOpts.zgc (default false); set to true it appends -XX:+UseZGC to the JVM options. (An earlier revision shipped ZGC as the default; it was reverted to opt-in before release — see "Why opt-in, not default" below.) ZGC is the only change with deployment-sizing impact, and only when enabled (see below). The worker-pool defaults that accompany the virtual-thread switch are listed at the end.
What an administrator must do
Nothing is required. G1 stays the default garbage collector, so existing memory sizing is unaffected by the JDK 25 upgrade as far as the collector is concerned.
Who should opt in to ZGC. With the MALLOC_ARENA_MAX=2 default, ZGC's former native-memory penalty is largely gone - its non-heap native sits at G1 level and the only remaining premium is the eager heap commit, which converges with G1 under a realistic live set. The load test (below) showed ZGC faster than G1 - better mean and tail latency and higher throughput - even at a modest 4G/6G pod, so ZGC is a sound choice for virtual-thread, latency-sensitive deployments generally, not just large installations. G1 remains the default and the better fit for throughput-/batch-bound workloads, very small heaps (where G1 is more CPU-efficient), and CPU-starved pods (ZGC's concurrent GC needs CPU headroom). Validate under your own load before tightening below 4G/6G - the benchmark had a small heap live set and under-exercised mail/attachment-heavy paths.
If you do opt in (javaOpts.zgc: true), size for ZGC's native-memory headroom. With MALLOC_ARENA_MAX=2 set (now a chart default - see "Why the headroom is large" below), the load-validated configuration is a 4G heap on a 6G container limit:
javaOpts.memory.maxHeapSize: 4G(orjavaOpts.memory.maxRAMPercentage: "50")resources.requests.memory: 6Gandresources.limits.memory: 6GMALLOC_ARENA_MAX=2on the container env (chart default) - without it the same workload needs an 8G limit.- give the pod adequate CPU - concurrent GC needs headroom; do not run ZGC CPU-starved. This was hard-validated under load (50 concurrent users, real Dovecot/Postfix): cgroup peak ~5.3G, 0 OOM, 0 restarts, no request errors. Without
MALLOC_ARENA_MAXthe peak is ~6.5G and a 6G limit fails (matching the earlier CI observation that 4G/6G failed). Too little memory does not surface as an OOM - it shows up as failures to open outbound IMAP/SMTP connections (mail-backend timeouts) under load, a downstream effect of the container exhausting native memory, not the mail sockets themselves. The test had a small heap live set and under-exercised mail/attachment-heavy paths, so treat the peak as a floor and keep margin - do not tighten below 6G without a heavier-mail re-test.
Why the headroom is large, and how to shrink it (load-tested 2026-06-29). Native-memory tracking under load overturns the original assumption that direct buffers dominate: direct/off-heap memory (NMT "Other") peaks at only ~0.3-0.5G and ZGC's own structures at ~80MB. The real driver of the excess is glibc malloc-arena retention (~1.2G) - the many-threaded virtual-thread middleware spawns many per-thread malloc arenas that hoard memory. Setting MALLOC_ARENA_MAX=2 (container env, now a chart default) caps this and cuts the cgroup peak from ~6.5G to ~5.3G at a 4G heap, letting ZGC fit a 6G limit. Crucially this brings ZGC's non-heap native memory down to the same level as G1 (~1.25G in both with the cap) - the only remaining difference is that ZGC eager-commits its heap while G1 right-sizes, and that gap converges under a realistic (larger) heap working set. -XX:MaxDirectMemorySize is not a useful sizing lever here (direct memory is small); it is only worth setting as an optional fast-fail cap.
(If core-mw is deployed as a subchart, the keys live under the core-mw: block.)
Returning idle memory (pay-per-used hosting). On hosting billed by actual memory use (RSS), ZGC hands idle heap back to the OS. Set javaOpts.zgcUncommitDelay (e.g. "60") to uncommit unused heap sooner than the 300s default (-XX:+ZUncommit is on by default). A 20-min soak confirmed ~2.2G returned to the OS within ~4 min of load dropping, while staying KO=0 under load. This returns heap only - glibc malloc arenas are bounded separately by MALLOC_ARENA_MAX. Trade-off: re-commit costs page faults when load returns; too short a delay churns under spiky load. If billed on the pod reservation rather than RSS, right-size the request instead. Do not throttle the heap with -XX:SoftMaxHeapSize to force a smaller footprint - a soak with SoftMaxHeapSize=2G at a 4G heap caused a severe tail regression (request timeouts, max 37.5s) by starving ZGC of allocation headroom; the idle give-back does not need it. (For very spiky, small-live-set workloads G1 reclaims even more aggressively, at a worse tail.)
Load-test results - performance and sizing
A full-stack load test (self-deployed core-mw-test umbrella chart with real Dovecot/Postfix/DB/Redis, in-cluster Gatling AppSuiteSimulation, 50 concurrent users; JDK 25, generational ZGC, 4G heap) measured ZGC against G1 at an identical 4G heap / 6G limit with MALLOC_ARENA_MAX=2, both error-free (KO=0):
- ZGC is faster, not slower: mean 38 vs 56 ms, p95 106 vs 130 ms, p99 213 vs 796 ms, max 1466 vs 6118 ms, and +47% throughput (1.03M vs 0.70M requests in the same window). ZGC's occasional allocation stalls cost far less than G1's multi-second stop-the-world pauses on this allocation-heavy, virtual-thread workload.
- Memory: ZGC cgroup peak ~5.3G vs G1 ~1.3G. The gap is not GC overhead - with
MALLOC_ARENA_MAX=2the non-heap native is ~1.25G for both. It is ZGC eager-committing the 4G heap (file-backed) while G1 right-sized to ~370M for this small test live set; G1 could not be forced to hold 4G (-Xms4G/AlwaysPreTouchspiked then uncommitted). Under a production-sized live set the two converge. - Conclusion: with
MALLOC_ARENA_MAX=2the memory premium of ZGC shrinks to its eager heap commit (small in practice) while the latency/throughput win is clear. ZGC is therefore recommended for the virtual-thread worker pool (latency-sensitive deployments); G1 remains the safe default for tight or throughput-bound pods.
Why opt-in, not default
ZGC was initially made the default but reverted to opt-in before release. Defaulting it on would force a mandatory pod re-sizing onto every installation at upgrade time; an operator that did not re-size would silently hit the native-memory failure mode above (IMAP/SMTP connection failures, not an obvious OOM) — a poor default for large/cloud deployments. G1 has zero such sizing impact. The opt-in default is retained for conservatism (no forced re-sizing at upgrade time), but the latency/throughput benchmark has since been run (see "Load-test results" above) and favours ZGC: with MALLOC_ARENA_MAX=2 resolving most of the memory premium, ZGC is now the recommended collector for virtual-thread, latency-sensitive deployments, and a future release may reconsider it as the default.
Why ZGC, and why it fits the virtual-thread worker pool
The middleware request path now runs on a virtual-thread worker pool, which raises in-flight concurrency and the rate of short-lived, request-scoped allocations. G1's stop-the-world young/mixed collections scale with heap/live-set and pause all carrier threads at once, causing latency spikes across many virtual threads. Generational ZGC collects concurrently with sub-millisecond, heap-size-independent pauses, and its young generation suits exactly this short-lived-allocation pattern, giving stable tail latency under high concurrency. Compact Object Headers (also default) reduces live heap and further eases GC pressure. This synergy is why ZGC is offered as an opt-in for latency-sensitive, well-sized deployments.
Concerns / when to stay on G1
Native-memory headroom (see above) - largely mitigated by the
MALLOC_ARENA_MAX=2chart default, which brings ZGC's non-heap native down to G1 level and lets it fit a 6G limit; still budget the headroom and validate under load for mail/attachment-heavy workloads.CPU: ZGC trades some throughput/CPU for low pauses. On CPU-starved pods its concurrent GC threads compete with the virtual-thread carriers and can raise latency. Ensure CPU headroom.
Allocation stalls: if the allocation rate outpaces concurrent collection (heap or CPU too small), ZGC stalls threads until memory is freed — the failure mode to watch under load spikes (monitor for "Allocation Stall" GC log lines).
Stay on G1 (the default) for very tight containers, throughput-/batch-bound workloads, or very small heaps where G1 is more CPU-efficient.
Virtual-thread pinning is orthogonal — ZGC does not pin virtual threads.
The latency/throughput benchmark has now been run (see "Load-test results" above) and favours ZGC; it used a small heap live set and under-exercised mail/attachment-heavy paths, so a heavier-mail load test is still advisable before flipping ZGC to the default in a future release.
About the virtual-thread worker pool
Virtual threads (JEP 444, stable since JDK 21) are lightweight JVM-managed threads multiplexed onto a small pool of OS "carrier" threads. A virtual thread blocked on I/O (IMAP/SMTP/DB) unmounts its carrier instead of holding an OS thread, so the server keeps far more requests in flight at roughly a stack's cost each rather than a full platform thread.
- Benefit: HTTP throughput under high concurrency is no longer capped by a bounded worker pool, while blocking I/O stays simple (no async rewrite).
- Behavioral changes: concurrency is no longer throttled by pool exhaustion — global back-pressure is now
com.openexchange.threadpool.virtual.maxConcurrency(defaultauto); more in-flight requests mean higher peak heap/native use (hence the ZGC sizing above applies when ZGC is enabled); thread dumps show many short-lived virtual threads instead of a fixed named pool, and pool-saturation metrics no longer apply to HTTP work. - Fallback:
com.openexchange.http.grizzly.virtualThreadsEnabled=falsereverts to the platform-thread worker pool. - Virtual-thread pinning (a VT stuck to its carrier during
synchronized/native sections) was audited — middleware code shows none; ZGC does not pin either.
Worker thread pool defaults (changed)
The shared worker thread pool ("OXWorker") previously shipped with an unbounded maximumPoolSize and a synchronous hand-off queue, allowing unbounded platform-thread creation under load. The Grizzly HTTP worker pool now runs on virtual threads by default (com.openexchange.http.grizzly.virtualThreadsEnabled=true) and is not governed by this pool; the bounded default guards non-HTTP work and the virtualThreadsEnabled=false fallback.
com.openexchange.threadpool.maximumPoolSizeMaximum number of platform threads in the shared worker pool. Shipped default changed2147483647->2000. Not reloadable, not config-cascade aware. File:threadpool.properties.com.openexchange.threadpool.workQueueQueue type for the shared worker pool. Shipped default changedsynchronous->linked. Combined withmaximumPoolSizegreater thancorePoolSizethis activates the ScalingQueue: threads scale up tomaximumPoolSize, then excess tasks queue instead of spawning further threads. Not reloadable, not config-cascade aware. File:threadpool.properties.com.openexchange.threadpool.virtual.maxConcurrencyThe maximum number of tasks that may run concurrently on the shared virtual-thread executor. Acts as a global back-pressure limit: once reached, submission of further tasks blocks until a running task completes. This is a process-wide overload limit, not a per-caller setting; individual fan-out sites may apply their own, narrower concurrency bound on top of it. Accepts a positive integer or the special valueauto(default). Withautothe limit is derived best-effort at start-up from the maximum heap size (the dominant constraint on in-flight request memory) and the active garbage collector: it scales with the heap and is reduced slightly under ZGC, which needs more native-memory headroom. The derived value is clamped to [512, 20000] and logged with its inputs at start-up (roughly ~4000 at a 4G heap on G1, ~3300 on ZGC). An explicit positive integer overrides the automatic value; a non-positive or unparseable value falls back toauto. Default auto (previously the fixed value 20000). Not reloadable, not config-cascade aware. File: threadpool.properties. Note: this is a memory-OOM safeguard, not a concurrency tuning target — the useful concurrency of blocking virtual-thread fan-out is almost always bound by a downstream pool (database connections, mail access, etc.) below this ceiling, which enforces its own narrower limit. The auto estimate is tunable viacom.openexchange.threadpool.virtual.maxConcurrency.auto.heapFractionandcom.openexchange.threadpool.virtual.maxConcurrency.auto.perRequestKB(below).com.openexchange.threadpool.virtual.maxConcurrency.auto.heapFractionFraction of the maximum heap budgeted for transient per-request state by theautoderivation ofcom.openexchange.threadpool.virtual.maxConcurrency; only consulted when that property isauto. Must be a decimal in (0, 1]; an absent, out-of-range or unparseable value falls back to0.25. Not reloadable, not config-cascade aware. File:threadpool.properties.com.openexchange.threadpool.virtual.maxConcurrency.auto.perRequestKBEstimated transient heap (in KiB) per in-flight request used by theautoderivation ofcom.openexchange.threadpool.virtual.maxConcurrency; only consulted when that property isauto. Raise it for requests with large transient state (buffered attachments, large responses) to make the safeguard more conservative; lower it for lightweight workloads. Must be a positive integer; an absent, non-positive or unparseable value falls back to256. Not reloadable, not config-cascade aware. File:threadpool.properties.
8.51.88
3rd Party Libraries/License Change
SCR-1724
Summary: Upgraded OSGi core library
Effective: 8.51.88 and later; changed in 8.51.89
Upgraded OSGi core library in target platform (com.openexchange.bundles):
eclipse.osgi_3.24.0.v20251126-0427.jarupgraded toorg.eclipse.osgi_3.24.200.v20260515-1403.jar
API - HTTP-API
SCR-1726
Summary: "sanitize_css" parameter for /mail?action=get
Effective: 8.51.88 and later; changed in 8.51.89
Summary
Adds an optional query parameter sanitize_css to the /mail?action=get endpoint. It lets a client decide per request whether CSS content in HTML mail is sanitized against the white-list (in CleaningJsoupHandler and CssOnlyCleaningJsoupHandler), instead of always sanitizing.
Parameter
||Name||Location||Type||Required||Description|| |sanitize_css|query|boolean|no|Controls whether CSS content in HTML mails is sanitized against the white-list.|
Values
||Value||Behavior|| |(omitted)|CSS is sanitized – unchanged behavior.| |true|CSS content is sanitized against the white-list.| |false|CSS content is passed through unfiltered.|
Notes
- Default is to sanitize: when the parameter is absent CSS sanitizing is performed exactly as before, so existing requests are unaffected.
- Affects CSS sanitizing only; HTML tag white-listing (the
sanitizeparameter) and external-image handling (thereplace_external_imagesparameter) are independent. - No configuration change and no API-breaking change.
API - REST
SCR-1714
Summary: New Administrative REST Servlet for Shared Accounts
Effective: 8.51.88 and later; changed in 8.51.89
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.
Behavioral Changes
SCR-1717
Summary: Deny Write-Access for Guest Users in Public Calendar Folders
Effective: 8.51.88 and later; changed in 8.51.89
With MW-1473 write access for invited guest users was introduced. However, write access in a calendar folder also implies taking over the organizer role for scheduled appointments. This role cannot be hijacked for a foreign principal residing on an external calendaring and mail system a guest user originates from. Therefore, guest users may only receive write access for personal or shared calendar folders that are bound to a known internal calendar user they can act on behalf of, but not for public calendar folders.
See the documentation for further details.
Configuration
SCR-1583
Summary: Per-user Filters for LDAP Contacts Provider
Effective: 8.51.88 and later; changed in 8.51.89
Besides the distinguishing attribute placeholder [value] for the folders, the filter template in mode dynamicAttributes may now also contain several user- or session-specific placeholders which are replaced dynamically from the requesting user's session prior passing the query to LDAP. Doing so, it is possible to model different 'views' on the data, in case the user base is also represented through the LDAP directory, in combination with multi-value LDAP attributes.
See the documentation for the new replacement options and further details.
Database
SCR-1718
Summary: Update Task to Downscope Unsupported Guest Permissions
Effective: 8.51.88 and later; changed in 8.51.89
Warning
Update Task com.openexchange.groupware.update.tasks.DownscopeGuestPublicCalendarPermissionsTask
The blocking database update task 'com.openexchange.groupware.update.tasks.DownscopeGuestPublicCalendarPermissionsTask' is introduced to downscope write permissions of guest users on public calendar folders to "read-only".
With MW-1473 write access for invited guest users was introduced. However, write access in a calendar folder also implies taking over the organizer role for scheduled appointments. This role cannot be hijacked for a foreign principal residing on an external calendaring and mail system a guest user originates from. Therefore, guest users may only receive write access for personal or shared calendar folders that are bound to a known internal calendar user they can act on behalf of, but not for public calendar folders.
This task aligns already existing permissions accordingly by stripping object-write, object-delete, sub-folder/create-object as well as administrative folder permissions from any guest user permission on a public calendar folder, leaving folder- and object-read permissions untouched.
8.51.76
Configuration
SCR-1744
Summary: New configuration options for the IMAP command-origin trace
Effective: 8.51.76 and later
New configuration options for the IMAP command-origin trace - a diagnostic facility in the IMAP bundle (bundle com.openexchange.imap) that attributes an issued IMAP command to its calling code path: it emits the command and its arguments, the command tag, the connection coordinates, the current log MDC and the caller's stack trace.
All options are read when an IMAP connection is established (a change applies to newly established connections), reloadable, not config-cascade aware. They map onto the JavaMail session properties mail.imap.traceLog.* consumed by com.sun.mail.imap.CommandOriginLog.
com.openexchange.imap.traceLog.enabledWhether the trace is enabled. Defaultfalse. Intended for short-lived diagnosis; leave disabled in normal operation.com.openexchange.imap.traceLog.targetOutput target:file(default),slf4j(dedicated loggercom.openexchange.imap.commandOriginTraceat TRACE level) orboth.com.openexchange.imap.traceLog.fileTrace file path for thefile/bothtarget; forslf4j/bothit additionally enables programmatic binding of a file appender on that path when the dedicated logger has no declarative Logback appender. No default (unset).com.openexchange.imap.traceLog.hostFilterComma-separated IMAP host names the trace is restricted to. Empty traces all hosts. No default.
The following only apply when a trace appender is bound programmatically (i.e. slf4j/both target with com.openexchange.imap.traceLog.file set and no declarative appender on the dedicated logger):
com.openexchange.imap.traceLog.appenderName- appender name. DefaultimapCommandOriginTrace.com.openexchange.imap.traceLog.pattern- encoder pattern. Default%msg%n.com.openexchange.imap.traceLog.append- append to (vs. truncate) the trace file. Defaulttrue.com.openexchange.imap.traceLog.level- level of the dedicated trace logger. DefaultTRACE.com.openexchange.imap.traceLog.additivity- additivity of the dedicated trace logger. Defaultfalse.com.openexchange.imap.traceLog.maxFileSize- per-file size cap; setting it (or any other rotation option) switches the appender to rolling mode. No default.com.openexchange.imap.traceLog.maxHistory- number of rolled-over files to keep. Default-1(unset).com.openexchange.imap.traceLog.totalSizeCap- total size cap across all rolled-over files. No default.com.openexchange.imap.traceLog.fileNamePattern- file-name pattern for rolled-over files. No default (derived from the trace file).
Documented in documentation-generic/config/IMAP.yml.
8.51.70
Configuration
SCR-1729
Summary: New configuration option for concurrent IMAP folder-ACL prefetch
Effective: 8.51.70 and later
New configuration option for IMAP folder-tree listing. Since IMAP offers no bulk GETACL, the per-folder ACL lookups (GETACL) were issued serially on a single connection -- one round-trip per folder. The option enables prefetching those ACLs concurrently over a bounded set of pooled connections, populating the per-folder ACL cache so the subsequent permission resolution finds cache hits instead of a serial GETACL storm.
The fan-out is additionally capped to the connection pool size (com.openexchange.imap.maxNumConnection minus one, reserving a connection for the driving operation); an unlimited pool keeps the configured bound to avoid connection churn.
com.openexchange.imap.aclPrefetchConcurrencyMaximum number of folder ACLs to prefetch concurrently during folder-tree listing. A value of 1 or less disables the parallel prefetch (sequential per-folder fallback). Default 4. Reloadable, config.cascade aware.
The prefetch runs the GETACLs in parallel over up to "aclPrefetchConcurrency" connections, reusing the already-open store connection plus free pooled connections and opening only the remaining few as short-lived connections for the duration of the folder listing. These extra connections are closed again afterwards, so the connection pool is restored to its prior state and the configured maxNumConnection limit is never exceeded.
8.51.68
Configuration
SCR-1728
Summary: New configuration option for trusting server-side UTF-8 search in IMAP
Effective: 8.51.68 and later
New configuration option for IMAP search. It controls whether the server-side UTF-8 search is trusted for non-ASCII (umlaut) matching once UTF8=ACCEPT (RFC 6855) has been enabled on the IMAP connection.
When enabled and the server advertises UTF8=ACCEPT (automatically enabled by the mail stack when offered), the application-side umlaut re-match governed by com.openexchange.imap.umlautFilterThreshold is skipped, since the server then performs RFC-6855-compliant UTF-8 matching itself. This removes a fetch-and-re-evaluate round-trip for non-ASCII searches. Disabling it keeps the application-side re-match as a safety net for servers with deficient UTF-8 search.
com.openexchange.imap.imapSearchTrustUtf8Whether to trust the server-side UTF-8 search for non-ASCII (umlaut) matching once UTF8=ACCEPT is enabled. When enabled, the application-side umlaut re-match is skipped for such servers. Default true. Reloadable, config.cascade aware.
8.51.59
Configuration
SCR-1727
Summary: New configuration options for early overload load-shedding
Effective: 8.51.59 and later
New configuration options for early overload load-shedding in the Middleware (see /appsuite/support#1517). When the back-end is overloaded, incoming requests are answered with a "try again later" error before acquiring a database connection, breaking the cascade "cache outage -> database stampede -> connection pool exhaustion -> unresponsive middleware". The overload decision is computed off the request path by a periodic timer; the request path only reads the cached decision. All options below are reloadable and not config.cascade aware.
com.openexchange.overload.enabledEnables early load-shedding. Disabled by default (opt-in), because shedding changes observable behavior (requests fail fast with a try-again error). When disabled, no request is ever shed. Default:false. Reloadable, not config.cascade aware.com.openexchange.overload.db.utilizationThresholdDatabase connection pool utilization in percent (0-100) at or above which requests are shed. Should stay belowcom.openexchange.database.health.poolUtilizationThresholdso the gate engages before the pod is pulled out of the load balancer. Default:85. Reloadable, not config.cascade aware.com.openexchange.overload.db.waitingThresholdNumber of threads waiting for a database connection above which requests are shed. Default:200. Reloadable, not config.cascade aware.com.openexchange.overload.cacheDegraded.db.utilizationThresholdLowered database utilization threshold (percent) applied while the distributed cache is degraded (staged detection), so the gate engages earlier when a cache outage and database back-pressure coincide. Default:70. Reloadable, not config.cascade aware.com.openexchange.overload.cacheDegraded.db.waitingThresholdLowered waiting-threads threshold applied while the distributed cache is degraded. Default:50. Reloadable, not config.cascade aware.com.openexchange.overload.sampleIntervalMillisInterval in milliseconds at which the overload decision is recomputed off the request path by a timer task. A changed value reschedules the timer task. Default:500. Reloadable, not config.cascade aware.com.openexchange.overload.allowlistComma-separated list of request qualifiers (e.g. AJAX module names) that are never shed. Default:login,logout. Reloadable, not config.cascade aware.com.openexchange.cache.v2.redis.loaderBulkhead.enabledWhether the cache-loader bulkhead is enabled. When enabled, the number of concurrent cache-loader executions (the database reads on a cache miss or while the cache is unavailable) is capped, so a cold or unreachable cache cannot stampede the database. Excess loads fail fast with a try-again error. Default:false(opt-in). Reloadable, not config.cascade aware.com.openexchange.cache.v2.redis.loaderBulkhead.maxConcurrentLoadsThe maximum number of concurrent cache-loader executions while the bulkhead is enabled. Size relative to the database connection pool capacity per node. A non-positive value disables the limit. Default:100. Reloadable, not config.cascade aware.
8.51.52
API - HTTP-API
SCR-1725
Summary: "replace_external_images" parameter for /mail?action=get
Effective: 8.51.52 and later
Summary
Adds an optional query parameter replace_external_images to the /mail?action=get endpoint. It lets a client decide per request whether external images in HTML mail content are routed through the image proxy, instead of relying solely on the configured default com.openexchange.mail.proxyExternalImageUrls.
Parameter
||Name||Location||Type||Required||Description|| |replace_external_images|query|boolean|no|Controls whether external images referenced in HTML content are routed through the image proxy.|
Values
||Value||Behavior|| |(omitted)|Configured default com.openexchange.mail.proxyExternalImageUrls applies – unchanged behavior.| |true|External images are routed through the image proxy.| |false|External images are not proxied.|
Notes
- The parameter only takes effect when external images are allowed at all (user mail setting "allow HTML images"); otherwise external images are dropped as before.
- Tri-state semantics: when the parameter is absent the previously configured behavior is kept, so existing requests are unaffected.
- No configuration change and no API-breaking change.
8.51.34
Configuration
SCR-1722
Summary: New configuration options for scheduled mail transport retry/back-off
Effective: 8.51.34 and later
New configuration options for the scheduled mail transport. They add a retry with exponential back-off around the mail access (connect + read) of a due scheduled mail when it fails with a retryable error.
Only the connect and read steps are retried; the actual send is never retried to avoid double-sending. A failure is classified as retryable purely by message: if a configured (case-insensitive) marker occurs in the thrown OXException's sole message or in the message of any chained cause. No assumption is made about exception categories.
com.openexchange.mail.scheduled.mailaccessRetry.maxAttemptsMax. number of attempts (initial attempt plus retries) for a failing mail access. A value of 1 (or less) disables retrying. Default 3. Reloadable, not config.cascade aware.com.openexchange.mail.scheduled.mailaccessRetry.baseDelayMillisBase delay in milliseconds for the exponential back-off between retries. Default 500. Reloadable, not config.cascade aware.com.openexchange.mail.scheduled.mailaccessRetry.maxDelayMillisMax. delay in milliseconds the exponential back-off is capped to. Default 5000. Reloadable, not config.cascade aware.com.openexchange.mail.scheduled.mailaccessRetry.messageMarkersComma-separated list of (case-insensitive) message markers that classify a failed mail access as retryable. Default STORE_CONCURRENCY_LIMIT_EXCEEDED. Reloadable, not config.cascade aware.
8.51.23
General
SCR-1702
Summary: Adjust existing remote service contracts to support gRPC-based site-aware forwarding
Effective: 8.51.23 and later
Summary: This change updates selected existing remote service contracts and package exports to support gRPC-based forwarding and service reuse across bundle boundaries. This SCR extends: SCR-1697
Motivation: The new site-aware gRPC forwarding layer reuses existing administrative service implementations and exception semantics. To support this, a small number of existing remote contracts and package exports were adjusted.
Contract ChangesAffected service contracts include:
- DataExportRMIService: selected methods now throw StorageException
- ChronosRMIService.setEventOrganizer(...): now throws StorageException
- PushRMIService.unregisterPermanentListenerFor(...): now throws StorageException
- LoginCounterRMIService.getLastLoginTimeStamp(...): now throws StorageException
- ContactStorageRMIService.deduplicateContacts(...): now throws StorageException
- OXUtilInterface.recalculateFilestoreUsage(...): now throws InvalidDataException
Public Package / Export Changes: Additional packages were exported or exposed for reuse by the new forwarding layer, including examples such as:
- com.openexchange.admin.rmi.site
- com.openexchange.admin.contextrestore.rmi.impl
- com.openexchange.admin.reseller.rmi.impl
- com.openexchange.admin.user.copy.rmi.impl
- com.openexchange.report.login.internal
- com.openexchange.share.impl
- com.openexchange.share.impl.rmi
- additional server-side RMI-related packages exported from com.openexchange.server
Compatibility:
- These changes are intended to preserve functional behavior while making error handling and implementation reuse compatible with remote gRPC forwarding.
- Because public remote contracts are touched, compatibility impact should be reviewed carefully for external consumers and cross-bundle integrations.
No Database or Configuration Changes:
- No database schema change was part of this contract adjustment.
- No dedicated new feature-local configuration properties were introduced.
API - REST
SCR-1705
Summary: Introduce external authentication bundles for active-active and edge authentication support
Effective: 8.51.23 and later
For the active-active and edge authentication work, the new bundles com.openexchange.external.authentication and com.openexchange.external.authentication.common are introduced. This SCR extends: SCR-1697
These bundles provide shared authentication-related APIs and utilities as well as the middleware-side implementation for external authentication handling. This includes common request/response contracts and the new external authentication servlet and request handling infrastructure. The bundles are part of package {}open-xchange-core{}.
The bundle com.openexchange.external.authentication.common provides the exported common API packages com.openexchange.external.authentication.common.api and com.openexchange.external.authentication.common.utils. The bundle com.openexchange.external.authentication provides the corresponding implementation.
New endpoints introduced there:
- POST /authentication/v1/login
- GET /authentication/v1/login/methods
These are exposed by:
- com.openexchange.external.authentication.rest.AuthenticateUserServlet.
No dedicated new feature-local configuration property was introduced for these bundles in the scope of this change. See the feature documentation for further details.
Behavioral Changes
SCR-1704
Summary: Introduce MultiSite support infrastructure for active-active deployments
Effective: 8.51.23 and later
For active-active deployments, the new bundle com.openexchange.multisite is introduced. This SCR extends: SCR-1697
This bundle provides the middleware-side multi-site support infrastructure used to determine remote sites and to access them in a multi-site setup. It is part of package {}open-xchange-core{}.
As part of this change, MultiSite configuration is introduced. The main feature property is {}com.openexchange.multisite.enabled{}, which controls whether the middleware runs in a multi-site setup. In addition, HTTP client properties for remote-site communication are introduced:
- com.openexchange.multisite.httpclient.totalConnections
- com.openexchange.multisite.httpclient.maxConnectionsPerRoute
- com.openexchange.multisite.httpclient.readTimeout
- com.openexchange.multisite.httpclient.connectionRequestTimeout
The MultiSite configuration is documented in documentation-generic/config/MultiSite.yml. See the active-active documentation for further details.
SCR-1701
Summary: Add gRPC-based site-aware GDPR data export support for active-active deployments
Effective: 8.51.23 and later
Summary: This change adds gRPC-based forwarding support for GDPR data export administrative operations in active-active deployments. Data export requests can now be executed on the responsible site for the affected context or user. This SCR extends: SCR-1697
Motivation: GDPR data export operations interact with user- and context-related data whose write ownership may belong to a different site in active-active deployments. This feature enables transparent forwarding to the responsible site.
Packages / BundlesAffected package:
- open-xchange-gdpr-dataexport
New bundle:
- com.openexchange.gdpr.dataexport.grpc
Functional Changes:
- Adds a gRPC endpoint and client implementation for GDPR data export operations.
- Adds a site-aware data export service implementation.
- Enables routing of data export related requests to the correct site.
Endpoint / API SurfaceNew gRPC service:
- DataExportService
Operational / Deployment Impact:
- Depends on the core site-aware RMI / gRPC infrastructure.
- Requires inter-site gRPC reachability.
- No database schema changes required.
- No new feature-dedicated properties have been introduced.
Compatibility:
- Existing GDPR data export workflows are preserved.
- Behavior is extended to support transparent execution on the responsible site in multi-site deployments.
SCR-1700
Summary: Add gRPC-based site-aware reseller support for active-active deployments
Effective: 8.51.23 and later
Summary: This change adds gRPC-based forwarding support for reseller-related administrative operations in active-active deployments. Reseller operations can be routed to the responsible write-active site when necessary. This SCR extends: SCR-1697
Motivation: Reseller-related operations may depend on context ownership and therefore need to run on the site responsible for the targeted data. In active-active deployments, this cannot be guaranteed solely by the initially contacted node. This change adds the required forwarding support.
Packages / BundlesAffected package:
- open-xchange-admin-reseller
New bundle:
- com.openexchange.reseller.grpc
Functional Changes:
- Adds a gRPC endpoint and client implementation for reseller operations.
- Adds a site-aware reseller service implementation.
- Enables transparent remote execution on the responsible site.
Endpoint / API SurfaceNew gRPC service:
- ResellerService
Operational / Deployment Impact:
- Depends on the core site-aware RMI / gRPC infrastructure.
- Requires inter-site gRPC reachability.
- No database schema change are required.
- No new feature-dedicated properties have been introduced.
Compatibility:
- Existing reseller-related flows remain available.
- Multi-site behavior is extended so operations can be executed on the correct site.
SCR-1699
Summary: Add gRPC-based site-aware user copy support for active-active deployments
Effective: 8.51.23 and later
Summary: This change adds gRPC-based forwarding support for user copy operations in active-active deployments. User copy requests can now be executed on the responsible write-active site even if the initial request reaches another site. This SCR extends: SCR-1697
Motivation: User copy is a write-relevant administrative operation. In active-active topologies, correct execution depends on reaching the responsible site for the targeted source and destination data. This change enables transparent forwarding.
Packages / BundlesAffected package:
- open-xchange-admin-user-copy
New bundle:
- com.openexchange.admin.user.copy.grpc
Functional Changes:
- Adds a gRPC endpoint and client implementation for user copy operations.
- Adds a site-aware user copy service implementation.
- Enables forwarding of user copy requests to the correct site.
Endpoint / API SurfaceNew gRPC service:
- UserCopyService
Operational / Deployment Impact:
- Depends on the core site-aware RMI / gRPC infrastructure.
- Requires inter-site gRPC reachability.
- No database schema change are required.
- No new feature-dedicated properties have been introduced.
Compatibility:
- Preserves existing user copy behavior for callers.
- Extends execution behavior to support remote forwarding in active-active environments.
SCR-1698
Summary: Add gRPC-based site-aware context restore support for active-active deployments
Effective: 8.51.23 and later
Summary: This change adds gRPC-based forwarding support for context restore operations in active-active deployments. Context restore requests can now be executed on the write-active site even if the initial request reaches a different site. This SCR extends: SCR-1697
Motivation: Context restore is an administrative operation that must run against the responsible site for the targeted data. In active-active deployments, requests may arrive on a non-owning site. This change adds a dedicated gRPC bundle so context restore operations can be routed correctly.
Packages / BundlesAffected package:
- open-xchange-admin-contextrestore{*}
*
New bundle:
- com.openexchange.admin.contextrestore.grpc
Functional Changes:
- Adds a gRPC endpoint and client implementation for context restore operations
- Adds a site-aware context restore service implementation that forwards requests to the responsible site when required.
- Keeps the existing context restore functionality, but enables execution on the correct remote site.
Endpoint / API SurfaceNew gRPC service:
- ContextRestoreService
Operational / Deployment Impact:
- Depends on the core site-aware RMI / gRPC infrastructure.
- Requires inter-site gRPC reachability in active-active deployments.
- No database schema changes required
- No new feature-dedicated properties have been introduced.
Compatibility:
- Existing administration workflows are preserved.
- Behavior is extended to support transparent remote execution in multi-site scenarios.
SCR-1697
Summary: Introduce site-aware RMI forwarding via gRPC for active-active deployments
Effective: 8.51.23 and later
Summary: This change introduces site-aware RMI services that forward administrative operations to the write-active site in active-active deployments. If an RMI call is received on a site that is not considered write-active for the addressed schema, context, or user, the call is forwarded via gRPC to the responsible site. If the local site is write-active, the operation continues to execute locally.
Motivation: In active-active deployments, administrative and provisioning calls may reach a site that is not responsible for performing write operations for the targeted data. Without additional routing, such calls either need to be rejected or rely on callers to identify the correct site in advance. This change adds transparent forwarding at the service layer so existing RMI-based administration flows can work correctly in a multi-site topology.
Packages / BundlesAffected package:
- open-xchange-admin
New bundles:
- com.openexchange.admin.rmi.site
- com.openexchange.provisioning.grpc.client
- com.openexchange.provisioning.grpc.common
- com.openexchange.provisioning.grpc.server
Functional Changes:
- Introduces site-aware wrappers for existing RMI services.
- Adds a gRPC-based inter-site communication layer for administrative/provisioning operations.
- Determines the responsible site based on existing multi-site / segment ownership information
- Executes requests locally when the current site is write-active. Forwards requests to the responsible remote site when the current site is not write-active.
New Endpoint / API Surface: This change introduces a new gRPC provisioning API surface for inter-site communication. The gRPC contracts are defined in the provisioning proto repository and include service definitions such as:
- UserService
- ContextService
- GroupService
- ResourceService
- UtilService
- JobManager
- SchemaService
- DeputyPermissionService
- SecondaryAccountService
- ChronosService
- ContactStorageService
- DBMigrationService
- ExternalAccountService
- PushService
- LoginCounterService
- ResourceCacheService
- ConsistencyService
- Login2ContextService
- FileChecksumsService
- ExtendedUpdateTaskService
- RemoteAuthService
- GABRestorerService
- ShareService
Operational / Deployment Impact:
- Introduces inter-site gRPC communication between middleware deployments.
- The gRPC server listens on port 8066.
- Client channels are established based on the configured URI of the target site.
- The implementation currently uses plaintext gRPC transport and assumes transport security is handled externally, e.g. by trusted network boundaries, service mesh, or external TLS termination.
- Active-active deployments must ensure network reachability between sites for this port / endpoint.
Compatibility:
- Existing RMI-facing administration flows remain available.
- The feature changes execution behavior by allowing remote forwarding when the local site is not write-active.
- No database schema change are required.
- No new feature-dedicated properties have been introduced.
Risks / Notes:
- Inter-site routing failures can now affect administrative operations if the responsible site is unreachable.
- Logging and troubleshooting should take into account that a call may execute on a different site than the one initially contacted.
Packaging/Bundles
SCR-1703
Summary: Introduce dedicated RMI bundles for database migration and external account services
Effective: 8.51.23 and later
For the active-active preparation work, the new bundles com.openexchange.database.migration.rmi and com.openexchange.external.account.rmi are introduced. This SCR extends: SCR-1697
These bundles separate the RMI-facing services for database migration and external account operations from their existing implementation bundles com.openexchange.database.migration and com.openexchange.external.account. This was done to cut dependencies and provide dedicated RMI bundles for the site-aware RMI / gRPC forwarding infrastructure.
The new bundles are part of package {}open-xchange-admin{}.
8.51.22
Database
SCR-1720
Summary: Re-run utf8 to utf8mb4 conversion on already-upgraded schemas (inherited per-column charset was skipped)
Effective: 8.51.22 and later
Warning
Update Task com.openexchange.capabilities.groupware.CapabilityConvertUtf8ToUtf8mb4TaskV2 com.openexchange.datatypes.genericonf.storage.impl.GenConfConvertUtf8ToUtf8mb4UpdateTaskV2 com.openexchange.download.limit.rdb.FileAccessConvertUtf8ToUtf8mb4UpdateTaskV2 com.openexchange.file.storage.rdb.groupware.FileStorageConvertUtf8ToUtf8mb4TaskV2 com.openexchange.filestore.sproxyd.groupware.SproxydConvertToUtf8mb4V2 com.openexchange.jslob.storage.db.groupware.JsonStorageTableUtf8Mb4UpdateTaskV2 com.openexchange.oauth.impl.internal.groupware.OAuthAccountsTableUtf8Mb4UpdateTaskV3 com.openexchange.passwordchange.history.impl.groupware.PasswordChangeHistoryConvertToUtf8mb4V2 com.openexchange.pns.subscription.storage.groupware.PnsSubscriptionTablesUtf8Mb4UpdateTaskV2 com.openexchange.push.impl.credstorage.rdb.groupware.CredConvertUtf8ToUtf8mb4TaskV2 com.openexchange.push.malpoll.groupware.MALPollConvertToUtf8mb4V2 com.openexchange.ajax.requesthandler.converters.preview.cache.groupware.PreviewTableUtf8Mb4UpdateTaskV2 com.openexchange.groupware.infostore.database.impl.InfostoreReservedPathsConvertUtf8ToUtf8mb4UpdateTaskV2 com.openexchange.groupware.update.tasks.AdminTablesUtf8Mb4UpdateTaskV2 com.openexchange.groupware.update.tasks.AggregatingContactsConvertUtf8ToUtf8mb4TaskV2 com.openexchange.groupware.update.tasks.AttachmentConvertUtf8ToUtf8mb4TaskV2 com.openexchange.groupware.update.tasks.ContactTablesUtf8Mb4UpdateTaskV2 com.openexchange.groupware.update.tasks.ContextAttributeConvertUtf8ToUtf8mb4TaskV2 com.openexchange.groupware.update.tasks.FolderConvertUtf8ToUtf8mb4TaskV2 com.openexchange.groupware.update.tasks.IDConvertToUtf8mb4TaskV2 com.openexchange.groupware.update.tasks.IndexedFoldersConvertToUtf8mb4V2 com.openexchange.groupware.update.tasks.InfostoreConvertUtf8ToUtf8mb4TaskV2 com.openexchange.groupware.update.tasks.LdapConvertUtf8ToUtf8mb4TaskV2 com.openexchange.groupware.update.tasks.LegacyCalendarTablesUtf8Mb4UpdateTaskV2 com.openexchange.groupware.update.tasks.MailAccountConvertUtf8ToUtf8mb4TaskV2 com.openexchange.groupware.update.tasks.MiscConvertUtf8ToUtf8mb4TaskV2 com.openexchange.groupware.update.tasks.OAuthAccessorConvertToUtf8mb4V2 com.openexchange.groupware.update.tasks.ObjectUseCountPermissionTableUtf8Mb4UpdateTaskV2 com.openexchange.groupware.update.tasks.ReminderTableUtf8Mb4UpdateTaskV2 com.openexchange.groupware.update.tasks.ResourceTablesUtf8Mb4UpdateTaskV2 com.openexchange.groupware.update.tasks.SequenceTablesUtf8Mb4UpdateTaskV2 com.openexchange.groupware.update.tasks.SettingsConvertUtf8ToUtf8mb4TaskV2 com.openexchange.groupware.update.tasks.TaskConvertUtf8ToUtf8mb4TaskV2 com.openexchange.net.ssl.management.storage.SSLCertificateManagementTableUtf8Mb4UpdateTaskV2 com.openexchange.tools.oxfolder.property.sql.OXFolderUserPropertyConvertUtf8ToUtf8mb4TaskV2 com.openexchange.snippet.mime.groupware.MimeSnippetTablesUtf8Mb4UpdateTaskV2 com.openexchange.snippet.rdb.groupware.RdbSnippetTablesUtf8Mb4UpdateTaskV2 com.openexchange.subscribe.database.SubscriptionsTablesUtf8Mb4UpdateTaskV2
Problem
The utf8 to utf8mb4 conversion update tasks (base class com.openexchange.groupware.update.AbstractConvertUtf8ToUtf8mb4Task) only converted columns whose SHOW CREATE TABLE definition carried an explicit CHARACTER SET utf8 / COLLATE utf8\_... clause. Columns that inherit their character set from the table default (no explicit per-column clause) are reported as utf8 by information\_schema but produce no clause to rewrite, so they were dropped from the ALTER TABLE. The subsequent table-default change then pinned utf8 onto those columns explicitly, leaving their stored data on utf8 (3-byte). Example: after the upgrade prg\_contacts.field01 stays varchar\(320\) CHARACTER SET utf8 COLLATE utf8\_unicode\_ci instead of becoming utf8mb4.
Fix (base class)
AbstractConvertUtf8ToUtf8mb4Task now also detects inherited-charset columns and injects an explicit CHARACTER SET utf8mb4 COLLATE ... after the data type, so the generated MODIFY COLUMN actually re-encodes the data. Detection and rewrite additionally handle the MariaDB utf8mb3 alias (and mb4Collation no longer produces utf8mb4mb3). The 767-byte InnoDB key limit stays covered: newly detected indexed columns flow through the existing 191-char index-prefix / VARCHAR-shrink handling unchanged.
Why a redo is required
Update tasks are recorded once per schema by class name, so the corrected base class does not re-run on installations where the original conversion already executed. To re-apply the now-correct conversion automatically, each registered concrete conversion task gets a thin "V2" twin (the OAuth accounts task, which already had a V2, gets a V3). Each twin extends its predecessor, depends on it, and therefore re-executes the same - now fixed - conversion on the next update. tablesToConvert\(\) / before\(\) / after\(\) are inherited unchanged, so per-table key handling stays intact. The conversion is idempotent: already-converted tables/columns are no-ops.
Operators can additionally re-run an individual task ad hoc via forceupdatetask \-t .
Out of scope
Liquibase-driven configDb/globalDb conversions (subclasses of AbstractLiquibaseUtf8mb4Adapter) are tracked by Liquibase changeset, not by class name, and are not covered here.
New redo update tasks (38)
com.openexchange.capabilities.impl **
com.openexchange.capabilities.groupware.CapabilityConvertUtf8ToUtf8mb4TaskV2re-runsCapabilityConvertUtf8ToUtf8mb4Taskcom.openexchange.datatypes.genericonf.storage **
com.openexchange.datatypes.genericonf.storage.impl.GenConfConvertUtf8ToUtf8mb4UpdateTaskV2re-runsGenConfConvertUtf8ToUtf8mb4UpdateTaskcom.openexchange.download.limit **
com.openexchange.download.limit.rdb.FileAccessConvertUtf8ToUtf8mb4UpdateTaskV2re-runsFileAccessConvertUtf8ToUtf8mb4UpdateTaskcom.openexchange.file.storage.rdb **
com.openexchange.file.storage.rdb.groupware.FileStorageConvertUtf8ToUtf8mb4TaskV2re-runsFileStorageConvertUtf8ToUtf8mb4Taskcom.openexchange.filestore.sproxyd **
com.openexchange.filestore.sproxyd.groupware.SproxydConvertToUtf8mb4V2re-runsSproxydConvertToUtf8mb4com.openexchange.jslob.storage.db **
com.openexchange.jslob.storage.db.groupware.JsonStorageTableUtf8Mb4UpdateTaskV2re-runsJsonStorageTableUtf8Mb4UpdateTaskcom.openexchange.oauth.impl **
com.openexchange.oauth.impl.internal.groupware.OAuthAccountsTableUtf8Mb4UpdateTaskV3re-runsOAuthAccountsTableUtf8Mb4UpdateTaskV2com.openexchange.passwordchange.history.impl **
com.openexchange.passwordchange.history.impl.groupware.PasswordChangeHistoryConvertToUtf8mb4V2re-runsPasswordChangeHistoryConvertToUtf8mb4com.openexchange.pns.subscription.storage **
com.openexchange.pns.subscription.storage.groupware.PnsSubscriptionTablesUtf8Mb4UpdateTaskV2re-runsPnsSubscriptionTablesUtf8Mb4UpdateTaskcom.openexchange.push.impl **
com.openexchange.push.impl.credstorage.rdb.groupware.CredConvertUtf8ToUtf8mb4TaskV2re-runsCredConvertUtf8ToUtf8mb4Taskcom.openexchange.push.malpoll **
com.openexchange.push.malpoll.groupware.MALPollConvertToUtf8mb4V2re-runsMALPollConvertToUtf8mb4com.openexchange.server **
com.openexchange.ajax.requesthandler.converters.preview.cache.groupware.PreviewTableUtf8Mb4UpdateTaskV2re-runsPreviewTableUtf8Mb4UpdateTask**com.openexchange.groupware.infostore.database.impl.InfostoreReservedPathsConvertUtf8ToUtf8mb4UpdateTaskV2re-runsInfostoreReservedPathsConvertUtf8ToUtf8mb4UpdateTask**com.openexchange.groupware.update.tasks.AdminTablesUtf8Mb4UpdateTaskV2re-runsAdminTablesUtf8Mb4UpdateTask**com.openexchange.groupware.update.tasks.AggregatingContactsConvertUtf8ToUtf8mb4TaskV2re-runsAggregatingContactsConvertUtf8ToUtf8mb4Task**com.openexchange.groupware.update.tasks.AttachmentConvertUtf8ToUtf8mb4TaskV2re-runsAttachmentConvertUtf8ToUtf8mb4Task**com.openexchange.groupware.update.tasks.ContactTablesUtf8Mb4UpdateTaskV2re-runsContactTablesUtf8Mb4UpdateTask**com.openexchange.groupware.update.tasks.ContextAttributeConvertUtf8ToUtf8mb4TaskV2re-runsContextAttributeConvertUtf8ToUtf8mb4Task**com.openexchange.groupware.update.tasks.FolderConvertUtf8ToUtf8mb4TaskV2re-runsFolderConvertUtf8ToUtf8mb4Task**com.openexchange.groupware.update.tasks.IDConvertToUtf8mb4TaskV2re-runsIDConvertToUtf8mb4Task**com.openexchange.groupware.update.tasks.IndexedFoldersConvertToUtf8mb4V2re-runsIndexedFoldersConvertToUtf8mb4**com.openexchange.groupware.update.tasks.InfostoreConvertUtf8ToUtf8mb4TaskV2re-runsInfostoreConvertUtf8ToUtf8mb4Task**com.openexchange.groupware.update.tasks.LdapConvertUtf8ToUtf8mb4TaskV2re-runsLdapConvertUtf8ToUtf8mb4Task**com.openexchange.groupware.update.tasks.LegacyCalendarTablesUtf8Mb4UpdateTaskV2re-runsLegacyCalendarTablesUtf8Mb4UpdateTask**com.openexchange.groupware.update.tasks.MailAccountConvertUtf8ToUtf8mb4TaskV2re-runsMailAccountConvertUtf8ToUtf8mb4Task**com.openexchange.groupware.update.tasks.MiscConvertUtf8ToUtf8mb4TaskV2re-runsMiscConvertUtf8ToUtf8mb4Task**com.openexchange.groupware.update.tasks.OAuthAccessorConvertToUtf8mb4V2re-runsOAuthAccessorConvertToUtf8mb4**com.openexchange.groupware.update.tasks.ObjectUseCountPermissionTableUtf8Mb4UpdateTaskV2re-runsObjectUseCountPermissionTableUtf8Mb4UpdateTask**com.openexchange.groupware.update.tasks.ReminderTableUtf8Mb4UpdateTaskV2re-runsReminderTableUtf8Mb4UpdateTask**com.openexchange.groupware.update.tasks.ResourceTablesUtf8Mb4UpdateTaskV2re-runsResourceTablesUtf8Mb4UpdateTask**com.openexchange.groupware.update.tasks.SequenceTablesUtf8Mb4UpdateTaskV2re-runsSequenceTablesUtf8Mb4UpdateTask**com.openexchange.groupware.update.tasks.SettingsConvertUtf8ToUtf8mb4TaskV2re-runsSettingsConvertUtf8ToUtf8mb4Task**com.openexchange.groupware.update.tasks.TaskConvertUtf8ToUtf8mb4TaskV2re-runsTaskConvertUtf8ToUtf8mb4Task**com.openexchange.net.ssl.management.storage.SSLCertificateManagementTableUtf8Mb4UpdateTaskV2re-runsSSLCertificateManagementTableUtf8Mb4UpdateTask**com.openexchange.tools.oxfolder.property.sql.OXFolderUserPropertyConvertUtf8ToUtf8mb4TaskV2re-runsOXFolderUserPropertyConvertUtf8ToUtf8mb4Taskcom.openexchange.snippet.mime **
com.openexchange.snippet.mime.groupware.MimeSnippetTablesUtf8Mb4UpdateTaskV2re-runsMimeSnippetTablesUtf8Mb4UpdateTaskcom.openexchange.snippet.rdb **
com.openexchange.snippet.rdb.groupware.RdbSnippetTablesUtf8Mb4UpdateTaskV2re-runsRdbSnippetTablesUtf8Mb4UpdateTaskcom.openexchange.subscribe **
com.openexchange.subscribe.database.SubscriptionsTablesUtf8Mb4UpdateTaskV2re-runsSubscriptionsTablesUtf8Mb4UpdateTask
8.51.19
Configuration
SCR-1719
Summary: New configuration options for virtual-thread request processing
Effective: 8.51.19 and later
New configuration options introduced together with virtual-thread support for the Grizzly HTTP worker pool and selected request-driven fan-out sites.
com.openexchange.http.grizzly.virtualThreadsEnabledWhether the Grizzly HTTP worker pool processes incoming requests on Java virtual threads instead of the bounded platform-thread pool. When enabled, each HTTP request is handled by a dedicated virtual thread; blocking operations during request processing (database, IMAP, file storage, ...) park the virtual thread instead of occupying a scarce platform worker. The network selectors remain on platform threads. The number of concurrently executing virtual threads is capped bycom.openexchange.threadpool.virtual.maxConcurrency. Requires a Java runtime with virtual-thread support (JDK 21 or later). Default true. Not reloadable, not config-cascade aware. File: grizzly.properties.com.openexchange.unifiedinbox.maxConcurrentAccountsThe maximum number of mail accounts a single Unified Mail operation processes concurrently. Unified Mail folder views fan out across the user's subscribed accounts (listing, searching, deleting, flag and color-label updates, message copy); this property caps how many of those per-account sub-tasks run in parallel, protecting the backing mail systems and their connection pools when a user has many accounts. The sub-tasks run on virtual threads. A value less than or equal to 0 (zero) is ignored and the default is used. Default 10. Not reloadable, not config-cascade aware. File: unifiedinbox.properties.
8.51.8
CLT
SCR-1716
Summary: Added 'checktablelayout' command-line tool
Effective: 8.51.8 and later
checktablelayout command-line tool
Added checktablelayout command-line tool to check existent database schemas against a reference schema newly created from up-to-date `CreateTableService`s.
usage: checktablelayout [-n <schema> ... ]( -a) [-t <table> ...] [-d] [-y] [-i] [-k] -A <masterAdmin> -P
<masterAdminPassword> [-p <RMI-Port>] [-s <RMI-Server>] [--responsetimeout <responseTimeout>] |
[-h]
-A,--adminuser <adminUser> Admin username
-a,--all Inspect all known (non-global) schemas
-d,--dry-run Only report deviations; never prompt and never modify anything
-h,--help Prints this help text
-i,--include-indexes Also generate statements for diverging non-primary indexes
-k,--keep-reference Keep the throw-away reference schema instead of dropping it at the end
-n,--schema <schema> The name of a target schema to inspect; may be repeated
-p,--port <rmiPort> The optional RMI port (default:1099)
-P,--adminpass <adminPassword> Admin password
--responsetimeout <timeout> The optional response timeout in seconds when reading data from server (default: 0s;
infinite)
{-}s,{-}-server <rmiHost> The optional RMI server (default: localhost)
{-}t,{-}-table <table> Restrict the analysis to the given table name(s); may be repeated
{-}y,{-}-yes Assume 'yes' for every prompt (non-interactive); applies all fixable deviations
Checks the table layout of one or more schemas against the canonical layout (as produced by the CreateTableService
implementations) and interactively reconciles deviating tables. Use '--dry-run' to only report deviations.
Operational notes for checktablelayout:
- Database privileges: the configured database account must be allowed to CREATE and DROP a database/schema, because the tool provisions a throw-away reference schema (created from the up-to-date
CreateTableServices) and drops it again at the end (unless\-k/\-\-keep\-referenceis given). - DDL impact: reconciliation runs
ALTER TABLEstatements against the target schema. On large tables this can lock the table and take a while, and MySQL/MariaDB DDL is not transactional and cannot be rolled back. Running during a maintenance window is recommended. - Safety guarantees: only tables that exist in both the target and the reference schema are altered. Tables that exist only in the target (or only in the reference) and columns that exist only in the target are report-only and are never dropped. Changes that might truncate or drop data (VARCHAR length shrink, base-type change, NOT NULL addition) are flagged; for such tables an additional
safechoice applies only the non-risky changes.\-\-dry\-runreports deviations without modifying anything. - All target schemas are compared against a single reference schema that is provisioned on the database pool of the first inspected schema; the inspected schemas should therefore reside on database servers of the same version.
Packaging/Bundles
SCR-1715
Summary: Added new bundles for table layout checking toolkit
Effective: 8.51.8 and later
Added following new bundles for table layout checking toolkit
com.openexchange.database.tablelayout.cltContains the actualchecktablelayoutcommand-line toolcom.openexchange.database.tablelayout.implThe implementation of the propagated RMI servicecom.openexchange.database.tablelayout.rmiThe RMI interface providing methods needed bychecktablelayoutcommand-line tool