App Suite Middleware
8.51.199
Changed defaults
SCR-1998
Summary: More carrier threads for virtual threads by default
Effective: 8.51.199 and later
The middleware now starts with -Djdk.virtualThreadScheduler.parallelism=256, the number of carrier threads its virtual threads run on, unless a JAVA_OPTS_* value already sets it. A virtual thread that loads a class is pinned to its carrier: with no more carriers than CPU cores, requests loading the same class at once could pin them all while the holder of a class loader lock waited for a carrier, and the middleware stopped answering. Carrier threads are ordinary platform threads, and idle ones cost little. Set the option in JAVA_OPTS_OTHER or in ox-scriptconf.sh to choose another value.
8.51.198
Configuration
SCR-1900
Summary: New lean configuration property com.openexchange.push.dovecot.unregisterOnMissingSession
Effective: 8.51.198 and later
In order to keep Dovecot Push registrations from piling up for users whose session has ended, the new lean configuration property com.openexchange.push.dovecot.unregisterOnMissingSession is introduced. When Dovecot notifies about a new message for a user for which no session can be resolved, the middleware drops that user's push registration through DoveAdm. It defaults to true, is reloadable and not config-cascade aware.
The registration is kept if it may still be wanted, that is if a permanent push listener or push notification subscriptions exist for that user. A configured DoveAdm end-point (com.openexchange.dovecot.doveadm.endpoints) is required; without one no registration is dropped. Set the property to false to restore the previous behavior.
See the property documentation for further details.
SCR-1892
Summary: New configuration option for caching the master administrator's password verification on provisioning calls
Effective: 8.51.197 and later; also delivered in 8.51.198
Provisioning calls are session-less and verify the master administrator's password against mpasswd on every call; with the default BCRYPT hash that costs about 100 ms of CPU per call and caps the master-level throughput. A successful verification is now remembered per node for a configurable time, so that further calls with the same credentials skip the password hash. Only a keyed hash of the password under a random per-node key is kept in memory; a wrong password always pays the full check, and reloading mpasswd with a changed hash invalidates the remembered verification. In addition, the duration of administrator authentication is exposed as Micrometer timer appsuite.provisioning.auth.duration with tags mode (master or context) and status.
com.openexchange.admin.masterPasswordVerificationTtlSecondsSpecifies how long (in seconds) a successful verification of the master administrator's password is remembered on a node. A value less than or equal to0(zero) disables the cache and verifies the password hash on every call. Default300. Reloadable, not config-cascade aware. No dedicated properties file.
8.51.197
Configuration
SCR-1892
Summary: New configuration option for caching the master administrator's password verification on provisioning calls
Effective: 8.51.197 and later
Provisioning calls are session-less and verify the master administrator's password against mpasswd on every call; with the default BCRYPT hash that costs about 100 ms of CPU per call and caps the master-level throughput. A successful verification is now remembered per node for a configurable time, so that further calls with the same credentials skip the password hash. Only a keyed hash of the password under a random per-node key is kept in memory; a wrong password always pays the full check, and reloading mpasswd with a changed hash invalidates the remembered verification. In addition, the duration of administrator authentication is exposed as Micrometer timer appsuite.provisioning.auth.duration with tags mode (master or context) and status.
com.openexchange.admin.masterPasswordVerificationTtlSecondsSpecifies how long (in seconds) a successful verification of the master administrator's password is remembered on a node. A value less than or equal to0(zero) disables the cache and verifies the password hash on every call. Default300. Reloadable, not config-cascade aware. No dedicated properties file.
8.51.195
Behavioral Changes
SCR-1885
Summary: Cache invalidations cross remote Redis sites
Effective: 8.51.195 and later
With remote Redis sites enabled (com.openexchange.redis.sites.enabled), cache invalidations are now repeated on the remote sites' Redis storages, and the messages that invalidate node-local caches of contexts, users, resellers and cache events are published there as well. Two middleware clusters attached to one config database therefore no longer serve stale contexts, users or database assignments after a provisioning change on the other cluster until the cache entries expire. Remote sites are best-effort: an unreachable site is logged, counted in appsuite.redis.remote.failures.total and skipped with a back-off; it never fails the provisioning call. Deployments that only share the databases should set com.openexchange.redis.sites.scope to invalidation to keep sessions on their site. No admin action for deployments without remote sites.
Configuration
SCR-1884
Summary: New configuration options for remote Redis sites
Effective: 8.51.195 and later
Options for using remote Redis sites for cache invalidation, e.g. between two middleware clusters attached to one config database.
com.openexchange.redis.sites.scopeWhat the configured remote sites are used for.all: sessions are replicated to the remote sites and looked up there, and cache invalidations are repeated there.invalidation: cache invalidations only; the sessiond sees no remote sites, so sessions stay on their site. Useinvalidationfor clusters that merely share the databases. Defaultall. Not reloadable, not config-cascade aware. File:redis.properties.com.openexchange.redis.[site].cache.enabledWhether the remote site denoted by[site](one of the identifiers listed incom.openexchange.redis.sites) runs a dedicated Redis instance for cache data. If enabled, that instance is configured through the[site].cacheinfix, e.g.com.openexchange.redis.[site].cache.hosts, and cache invalidations are repeated there; otherwise they are repeated on the remote site's regular Redis instance. Defaultfalse. Not reloadable, not config-cascade aware. File:redis.properties.
8.51.190
Configuration
SCR-1877
Summary: New configuration option for contact auto-complete result limiting
Effective: 8.51.190 and later
In order to bound the size of a contact auto-complete response, a new lean configuration property is introduced for the contacts module.
com.openexchange.contact.autocomplete.maxResultsDefines the maximum number of contacts returned by anaddressbooks?action=autocompleterequest that does not supply aright_hand_limitof its own. Such a request previously returned every matching contact, so a query of one or two characters could read and transfer a large part of the address book. A value of 0 (zero) or less disables the limit. Default 100. Reloadable, config-cascade aware. File: contact.properties.
Related change in the same area: a client-supplied right_hand_limit is now applied to auto-complete requests for every sort order. It was previously discarded whenever sort was omitted or set to one of the special sort orders, which are the ones App Suite uses for contacts.
8.51.188
API - HTTP-API
SCR-1875
Summary: New optional parameter applyDefaultAlarms for the iCal import request
Effective: 8.51.187 and later; also delivered in 8.51.188
The iCalendar import request import?action=ICAL accepts the new optional parameter applyDefaultAlarms. When set to true, alarms contained in the imported iCalendar data are skipped for appointments, and the calendar user's configured default alarms (defaultAlarmDate and defaultAlarmDateTime) are applied instead. It has no effect on tasks.
The appointment imported by the following request ends up with the user's default alarms, although the iCalendar data carries no VALARM component:
POST /ajax/import?action=ICAL&folder=cal%3A%2F%2F0%2F31&applyDefaultAlarms=true
Content-Type: multipart/form-data; boundary=--boundary
--boundary
Content-Disposition: form-data; name="file"; filename="appointment.ics"
Content-Type: text/calendar
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp//Booking//EN
BEGIN:VEVENT
UID:5a1c0f6e-3d21-4a77-9d1f-1e0b7c2a9f44
DTSTAMP:20260901T100000Z
DTSTART:20270301T100000Z
DTEND:20270301T110000Z
SUMMARY:Flight to Berlin
END:VEVENT
END:VCALENDAR
--boundary--
This addresses appointments that do not originate from the user's own calendar, e.g. one added from a mail attachment: such data usually carries either no alarm at all or an alarm chosen by whoever created the file, so the user ends up without the reminders they configured. Since the server cannot tell where the data came from, the client decides. The change is purely additive - without the parameter, alarms are imported as before, which keeps export/import round trips within the calendar module intact.
See the import request documentation for further details.
8.51.187
API - HTTP-API
SCR-1875
Summary: New optional parameter applyDefaultAlarms for the iCal import request
Effective: 8.51.187 and later
The iCalendar import request import?action=ICAL accepts the new optional parameter applyDefaultAlarms. When set to true, alarms contained in the imported iCalendar data are skipped for appointments, and the calendar user's configured default alarms (defaultAlarmDate and defaultAlarmDateTime) are applied instead. It has no effect on tasks.
The appointment imported by the following request ends up with the user's default alarms, although the iCalendar data carries no VALARM component:
POST /ajax/import?action=ICAL&folder=cal%3A%2F%2F0%2F31&applyDefaultAlarms=true
Content-Type: multipart/form-data; boundary=--boundary
--boundary
Content-Disposition: form-data; name="file"; filename="appointment.ics"
Content-Type: text/calendar
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp//Booking//EN
BEGIN:VEVENT
UID:5a1c0f6e-3d21-4a77-9d1f-1e0b7c2a9f44
DTSTAMP:20260901T100000Z
DTSTART:20270301T100000Z
DTEND:20270301T110000Z
SUMMARY:Flight to Berlin
END:VEVENT
END:VCALENDAR
--boundary--
This addresses appointments that do not originate from the user's own calendar, e.g. one added from a mail attachment: such data usually carries either no alarm at all or an alarm chosen by whoever created the file, so the user ends up without the reminders they configured. Since the server cannot tell where the data came from, the client decides. The change is purely additive - without the parameter, alarms are imported as before, which keeps export/import round trips within the calendar module intact.
See the import request documentation for further details.
8.51.180
Configuration
SCR-1854
Summary: New property com.openexchange.calendar.useNoReplyAddressForNotifications
Effective: 8.51.180 and later
In order to let deployments whose no-reply relay is not authorized for the users' mail domains pass SPF and DMARC checks, the new lean configuration property com.openexchange.calendar.useNoReplyAddressForNotifications is introduced. If enabled, the configured no-reply address replaces the From header of calendar notification mails to internal recipients that are transported via the no-reply account, and the Sender and Reply-To headers are dropped. It defaults to false, is reloadable and config-cascade aware.
External iMIP messages are never affected, as their From header has to stay aligned with the ORGANIZER property. Note that the property keys on the recipient being internal, not on the message kind: with com.openexchange.calendar.useIMipForInternalUsers enabled, internal users receive full iMIP messages and those are rewritten as well, which RFC-conformant calendar clients may reject. Enable both only if internal recipients read their invitations in App Suite.
It applies wherever the no-reply account is used, which is not limited to com.openexchange.calendar.preferNoReplyForNotifications: guests, users without webmail permission, restricted sessions and impersonation sessions take that account on their own, so mails triggered by them change as well. The value is evaluated for the acting user, not for the organizer. No operator action is required by default. See the property documentation for further details.
8.51.171
API - HTTP-API
SCR-1844
Summary: New deputy module action reverseIds that lists the granting users without resolving grant details
Effective: 8.51.171 and later
The deputy module gained the action GET /ajax/deputy?action=reverseIds, a light-weight counterpart to action=reverse. It lists the users that appointed the requesting user as their deputy, but resolves neither the granted folders nor the permission bits. Resolving those requires consulting every module involved; for the mail module that is a server-wide GETMETADATA sweep per mail account, whose cost grows with the number of mailboxes visible to the user. This action is answered from the deputy storage alone.
Each element of the returned array carries:
grantorId- the identifier of the granting user, or0for a cross-context grantor whose bare identifier has no meaning in the requesting user's contextgrantorIdentifier- the qualified identifier as<userId>@<contextId>grantorEntityInfo- pre-resolved entity information for rendering the grantordeputyIds- the identifiers of the deputy permissions this user grantedsendOnBehalfOf- whether at least one of those grants permits sending on the granting user's behalf, aggregated across that user's grants because the addresses belong to the granter rather than to an individual grantgrantorAddresses- the addresses to send from, present only whensendOnBehalfOfistrue; the full listing applies the same gate
Example request:
GET /ajax/deputy?action=reverseIds&session=<session-id>
Example response:
{
"data": [
{
"grantorId": 3,
"grantorIdentifier": "3@1",
"grantorEntityInfo": {
"identifier": "3@1",
"type": "user",
"display_name": "Jane Doe",
"entity": 3,
"contact": {
"first_name": "Jane",
"last_name": "Doe",
"email1": "jane.doe@example.org"
}
},
"deputyIds": [
"a3fff8061eae4078817533438c090a9b",
"0c1d7f52a1b04e6f9d2c8e3b5a7f1042"
],
"sendOnBehalfOf": true,
"grantorAddresses": [
"jane.doe@example.org",
"j.doe@example.org"
]
}
]
}
Purely additive: action=reverse is unchanged. Note that an orphaned grant, one whose module no longer backs a permission, is still listed by action=reverseIds - detecting and removing it is what the full listing does when it consults the modules.
On 8.51 and 8.50 the action is available in a reduced form: sendOnBehalfOf and grantorAddresses are present, but grantorIdentifier and grantorEntityInfo are not - those lines do not carry the qualified grantor identity internally. A client that has to work across all four lines should key on grantorId there.
8.51.170
Configuration
SCR-1843
Summary: New configuration options for capping how long IMAP responses are read from the primary and secondary account
Effective: 8.51.170 and later
A slow IMAP server can keep a request thread reading responses for minutes. The lean property com.openexchange.imap.readResponsesTimeout caps that, but has so far only been applied to external mail accounts. It can now be applied to the primary and to secondary accounts as well, through their own options - which, unlike the general one, carry no default and therefore never impose a cap unless an operator asks for it.
com.openexchange.imap.primary.readResponsesTimeoutThe maximum time in milliseconds spent reading the responses of a single IMAP command on the primary account. When it elapses, the command is aborted and reported to the client as a connection error. A value less than or equal to0is ignored, as is a non-numeric one. No default: while the option is absent no read responses timeout is applied at all. Reloadable, config-cascade aware. File:imap.properties.com.openexchange.imap.secondary.readResponsesTimeoutThe same for secondary accounts. A value less than or equal to0is ignored, as is a non-numeric one. No default: while the option is absent no read responses timeout is applied at all. Reloadable, config-cascade aware. File:imap.properties.
External accounts are unaffected and keep evaluating com.openexchange.imap.readResponsesTimeout with its default of 60000.
8.51.161
Configuration
SCR-1825
Summary: New configuration option for Redis Sentinel authentication
Effective: 8.51.161 and later
In order to connect to a password-protected Redis Sentinel, a new configuration option has been added.
com.openexchange.redis.sentinel.passwordSpecifies the password used to authenticate against the Redis Sentinel nodes. Only effective ifcom.openexchange.redis.modeis set tosentinel. Sentinel authentication is separate from the credentials for the Redis nodes themselves, which remain configured throughcom.openexchange.redis.usernameandcom.openexchange.redis.password. An empty value means the Sentinel nodes require no authentication. Set it only if the Sentinel nodes actually require authentication; otherwise they reject theAUTHcommand and the topology look-up fails. For a special Redis instance the option is available ascom.openexchange.redis.[instanceId].sentinel.password, with[instanceId]beingcacheor the identifier of a remote site. Default empty. Not reloadable, not config-cascade aware. File: redis.properties.
8.51.158
General
SCR-1822
Summary: Added command-line tool threaddump that covers virtual threads
Effective: 8.51.157 and later; also delivered in 8.51.158
The new command-line tool threaddump writes a thread dump of the middleware that includes virtual threads. The middleware runs its HTTP work on virtual threads, which neither jstack nor the Thread.print diagnostic command lists. It therefore uses Thread.dump_to_file through JMX, which needs no jcmd binary - the runtime image ships none. The middleware writes the file itself, so the path given via -f is resolved on the middleware's host. That dump performs no deadlock analysis, hence --print-classic prints the classic dump as a second, separate dump on the terminal. Further options are --format (plain or json, where json carries no lock information) and --overwrite.
$ threaddump -f /tmp/threads.txt
Thread dump successfully written to file /tmp/threads.txt on the middleware's host
$ head /tmp/threads.txt
7
2026-08-14T06:54:19.525073364Z
25.0.4+-wolfi-r0
#3 "main" RUNNABLE 2026-08-14T06:54:19.525200Z
at ...
#28 "OXWorker-0007" virtual BLOCKED 2026-08-14T06:54:19.525300Z
at ...
- waiting to lock <java.lang.Object@2df9b86>
8.51.157
General
SCR-1822
Summary: Added command-line tool threaddump that covers virtual threads
Effective: 8.51.157 and later
The new command-line tool threaddump writes a thread dump of the middleware that includes virtual threads. The middleware runs its HTTP work on virtual threads, which neither jstack nor the Thread.print diagnostic command lists. It therefore uses Thread.dump_to_file through JMX, which needs no jcmd binary - the runtime image ships none. The middleware writes the file itself, so the path given via -f is resolved on the middleware's host. That dump performs no deadlock analysis, hence --locks additionally prints the classic dump, which does. Further options are --format (plain or json, where json carries no lock information) and --overwrite.
$ threaddump -f /tmp/threads.txt
Thread dump successfully written to file /tmp/threads.txt on the middleware's host
$ head /tmp/threads.txt
7
2026-08-14T06:54:19.525073364Z
25.0.4+-wolfi-r0
#3 "main" RUNNABLE 2026-08-14T06:54:19.525200Z
at ...
#28 "OXWorker-0007" virtual BLOCKED 2026-08-14T06:54:19.525300Z
at ...
- waiting to lock <java.lang.Object@2df9b86>
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