These are the results of checking two things that shipped today against a live Stalwart 0.16.22, using a throwaway account whose test objects were removed afterwards.
It reports a create, an update and a destroy exactly.
A card created and destroyed since the given state nets out to nothing.
An unrecognized state gets invalidArguments, not cannotCalculateChanges. syncCards already falls back to a full load on any error, so no code change is needed.
What Stalwart honors: a single range, including suffix (bytes=-5) and open-ended (bytes=995-) forms, with 206 and a correct Content-Range.
Everything else: several ranges, or a range past the end, get the whole file with 200, never 416.
The gap: Stalwart sends no Accept-Ranges, and the proxy only forwarded the header when upstream sent one. Chrome's PDF viewer only reads a file in pieces when the first response advertises Accept-Ranges, so large PDFs still downloaded whole.
The fix:
/api/blob now always sends Accept-Ranges: bytes. A server that ignores a range answers with the whole file, which browsers handle normally.
The mock matches Stalwart: no Accept-Ranges, and 200 with the whole file instead of 416.
KNOWN-ISSUES.md records both results.
Related issues
None.
Translations
Adds none.
Testing
account.test.ts, through the proxy and mock:
a full download carries Accept-Ranges: bytes;
a single range returns 206;
a range past the end returns 200 with the whole file.
npm test -w server (251 tests) and tsc are clean.
The live results above came from direct JMAP calls in a browser session signed in as the throwaway account.
## Summary
These are the results of checking two things that shipped today against a live Stalwart 0.16.22, using a throwaway account whose test objects were removed afterwards.
**`ContactCard/changes` (#384) works.**
- It reports a create, an update and a destroy exactly.
- A card created and destroyed since the given state nets out to nothing.
- An unrecognized state gets `invalidArguments`, not `cannotCalculateChanges`. `syncCards` already falls back to a full load on any error, so no code change is needed.
**Byte ranges on downloads (#386).**
- **What Stalwart honors:** a single range, including suffix (`bytes=-5`) and open-ended (`bytes=995-`) forms, with `206` and a correct `Content-Range`.
- **Everything else:** several ranges, or a range past the end, get the whole file with `200`, never `416`.
- **The gap:** Stalwart **sends no `Accept-Ranges`**, and the proxy only forwarded the header when upstream sent one. Chrome's PDF viewer only reads a file in pieces when the first response advertises `Accept-Ranges`, so large PDFs still downloaded whole.
**The fix:**
- `/api/blob` now always sends `Accept-Ranges: bytes`. A server that ignores a range answers with the whole file, which browsers handle normally.
- The mock matches Stalwart: no `Accept-Ranges`, and `200` with the whole file instead of `416`.
- **KNOWN-ISSUES.md** records both results.
## Related issues
None.
## Translations
Adds none.
## Testing
- `account.test.ts`, through the proxy and mock:
- a full download carries `Accept-Ranges: bytes`;
- a single range returns `206`;
- a range past the end returns `200` with the whole file.
- `npm test -w server` (251 tests) and `tsc` are clean.
- The live results above came from direct JMAP calls in a browser session signed in as the throwaway account.
**Merged** 2026-09-16 as coffey-labs/ihasmail@4c1ceca8e9dc
<sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
These are the results of checking two things that shipped today against a live Stalwart 0.16.22, using a throwaway account whose test objects were removed afterwards.
ContactCard/changes(#384) works.invalidArguments, notcannotCalculateChanges.syncCardsalready falls back to a full load on any error, so no code change is needed.Byte ranges on downloads (#386).
bytes=-5) and open-ended (bytes=995-) forms, with206and a correctContent-Range.200, never416.Accept-Ranges, and the proxy only forwarded the header when upstream sent one. Chrome's PDF viewer only reads a file in pieces when the first response advertisesAccept-Ranges, so large PDFs still downloaded whole.The fix:
/api/blobnow always sendsAccept-Ranges: bytes. A server that ignores a range answers with the whole file, which browsers handle normally.Accept-Ranges, and200with the whole file instead of416.Related issues
None.
Translations
Adds none.
Testing
account.test.ts, through the proxy and mock:Accept-Ranges: bytes;206;200with the whole file.npm test -w server(251 tests) andtscare clean.Merged 2026-09-16 as coffey-labs/ihasmail@4c1ceca8e9
Rebuilt from: git history, session transcript.