feat(activesync): force Sync TruncationSize override - #96
Conversation
🔍 CI ResultsOverall: ❌ 12/12 lanes failed TL;DR: ❌ Quality issues: PHPStan: 243 unique errors in 11 lanes; PHP-CS-Fixer: 33 files. Summary by PHP Version
Quality Metrics
❌ Failed Lanesphp8.0-dev
php8.0-stable
php8.1-dev
php8.1-stable
php8.2-dev
php8.2-stable
php8.3-dev
php8.3-stable
php8.4-dev
php8.4-stable
php8.5-dev
php8.5-stable
CI powered by horde-components • View full results |
97e1b7d to
624c4fe
Compare
|
I have just tested this with Nine and a value of 500, and if my reading of the logs is correct, it appears to be ignored. EstimatedDataSize seems to be all over the place - and nowhere hear 500. Also slightly odd I found the following log fragment - which seems like a really large number for the body of an email: I will send over the logs in a minute |
|
Thanks for the retest with
|
| Client | Default Sync truncation | Re-fetches truncated body? | Effect of a server Sync cap |
|---|---|---|---|
| iOS Mail | already small | yes (on open) | safe; redundant for completeness |
| Nine | 50 KB | yes (button → ItemOperations) | safe; Sync can be made smaller, full body still available on demand |
| Gmail Android | 200 KB | no | unsafe for completeness (permanent clip) |
So: iOS is smart out of the box; Nine stays smart after server-side truncation because it can fetch the rest; Gmail is not smart about truncation / large bodies at all. That makes the knob a real bandwidth control for well-behaved clients, with Gmail as the documented exception (leave at 0 for Gmail-heavy fleets, or accept clipped bodies). Still happy to wait on @ralflang for the final keep/drop call on this PR.
|
Thank you for analysing the logs and the detailed reply. It's good news that server enforced truncation works correctly in Nine as well. I confirm the log captured on purpose just the sync run - I avoided opening any messages during the capture just to keep it all clear and avoid mixing things up in the log. I also agree that this feature looks useful and it would be worth merging it in. Just a side note that I have submitted a bug report through the Gmail in-app feedback regarding Gmail's inability to cope with the server sending truncated messages - even when that truncation was requested by Gmail itself. No idea if it will get picked up by the dev team - but I thought it worth a try. |
|
@TDannhauer is this ready for review? |
|
Yes it is. Strategically asked:
Do you vote for merge or discard? If just one mail app benefits? For Gmail we filed an issue with all the details, maybe they improve it and Gmail benefits as well soon. |
|
Could I add a slight spanner in the works if that's ok. Could this be merged with the other feature - which implements minimum truncation size - to simplify the configuration? Possibly rename it to "force-truncation-size" - or similar - which means that if enabled, the server forces truncation size in all circumstances - both when client asks for a lower value and when the client asks for a higher value than the server config. So it could benefit the other scenario as well - where truncation could be set to a really large value on the server side - to make sure non-compliant clients - such as Gmail - download messages in full always and don't truncate them. I can't really think of a scenario where it would be beneficial to have separately two different settings at the server end - both a minimum and a maximum truncation size, and let clients choose a value in between. I realise this has already been worked on for a while - sorry to barge in so late in the process. |
|
It is welcome feedback. We should be careful not to complicate matters for the installed base but I think it's worth having both behind one switch. I do the same with the upcoming strategy switch in IMP (see latest ralf-lang.de post on this). |
624c4fe to
4d33f22
Compare
|
rebased to latest FW_6_0 |
Replace maximum-only cap with forcetruncationsize: when set, the server always uses that byte value for Sync body export whether the client asked for more or less. ItemOperations Fetch stays uncapped. Still reads deprecated maximumtruncationsize from existing configs.
4d33f22 to
362f323
Compare
Thanks for your input! I agree to your proposal: Any kind of truncation requires a working "fetch full later", then is is arbitrary at which size it is truncated. Your proposal would simplify the required mind model of the responsible administrators: either rely completely on the client or define the truncation size server side. That's easier to understand than the "window size approach" where a client can freely decide itself, but just inside the window of minimum and maximum. I'll update the PR. |
|
That's brilliant - thank you for the change. It will make the setting easier to use and understand by admins I think. Even I was struggling after a while to remember how the minimum and maximum works and which clients are affected under which circumstances. Much appreciated! |
|
Please test the PR branch with Gmail and nine, I'll do with iOS, then we are ready for merge |
|
Hmm - I can't get the |
|
You need to update horde/base also, see horde/base#151 |
|
Hmm, not sure if I'm doing something wrong here: |
|
Ok - after much handholding by ChatGPT, it looks like |
|
I've just sent the logs for Gmail over email - please ignore version "A" as I've omitted the Gmail logs. Also just a note that I've updated Gmail this evening to version 2026.08.17.974752392.Release
Can you work out from the Gmail logs if Gmail simply closes the connection and doesn't accept the entire email the server is sending? I expected that by using a large |
|
Thanks for the B/C logs. What went wrongIn both B and C the server still used Gmail’s own Proof: Sync HTTP response size was ~200 KB for the large mails. With force 10000 it would be ~10 KB; with force 50 it would be ~1–2 KB. Most likely cause (given your earlier install path): the UI showed
into the real Also: Gmail did not close the connection early — Sync finished Status 1. It just never re-fetches truncated bodies. The inline-image wait is a separate Exact packages / branches to installYou need both PR branches:
Example (adjust VCS / alias as you already do for other composer require \
'horde/activesync:dev-feat/maximum-truncation-size' \
'horde/horde:dev-feat/force-truncation-size'Then in the Horde admin UI: open ActiveSync config → set Sanity check that the library has the force API: grep -n forceTruncationSize vendor/horde/activesync/lib/Horde/ActiveSync.phpRetest
Happy to look at another log pair after that. |
|
Thank you for the detailed reply and for spending time on checking the logs. Sorry for getting muddled up between kilobytes and bytes - there were lots of zeroes floating around! Please ignore log set Log set I also confirm (not included in the log) that sending an email with a 20 MB photo inserted inline works pretty much as expected:
Coming back to "forcetruncationsize", is there any chance of having a third option please:
It's just something which would make the feature easier and cleaner to use - but it isn't critical. It is always possible to put in something like 100 000 000 like I did - which should cover any email sizes. |
|
Thanks — Log E confirms the override is working end-to-end. Log EGmail still requested
That matches “downloaded and displayed in full in Gmail”. Earlier B/C failed because ActiveSync was on the wrong branch; with The inline-image behaviour you described (placeholder → attachment area busy → then “Show pictures”) is normal: Sync only announces the part; the ~MB download is a later “Always send full body” / infinite optionWe are not adding a third sentinel ( Reasons:
How to configure it
Examples for the Gmail-style case:
There is no need to guess “the largest email ever”; pick a ceiling you are willing to put on a single Sync export. Attachments / inline images stay on Thanks again for the careful retests — this unblocks merge from the Gmail side once Nine/iOS checks are done. |
|
ready to merge @ralflang |
|
I've just sent over logs 'F' which are for the Nine sync using 500 bytes as `forcetruncationsize'. Everything looks normal and Nine behaves as expected - the message is initially truncated, then clicking the button at the bottom of the window then loads the rest of the message and attachments. Probably not strictly needed - as Nine was already behaving properly in previous tests - but I thought I'd send them over for the sake of completeness. Thank you for all your work on this new feature. I think it will be a really useful capability on future Horde deployments. |
Summary
$conf['activesync']['sync']['forcetruncationsize'](default0= honor client): when set, the server always uses that byte value for Sync body export, whether the client asked for more or less.maximumtruncationsizefrom existing configs until horde/base admin UI is updated.Motivation
Per Sebastian's feedback and @ralflang's direction: one override knob instead of separate min/max settings. Low values reduce Sync traffic for well-behaved clients; high values can help Gmail (which never re-fetches). See
doc/clients.mdand the horde/base config description for fleet policy guidance.Related
BINARY.SIZEfix + client docs: merged via fix(activesync): ignore bogus BINARY.SIZE; document client truncation #98Test plan
TruncationCapTest(force overrides larger/smaller/unlimited client values; deprecated key fallback)500on Nine → truncated Sync + full body via ItemOperations button; force1048576on Gmail → bodies up to 1M complete on Sync