Show the complete mailbox; sync_limit now caps body prefetch only

The local store was capped at sync_limit, so IMAP only ever listed the
newest N messages — a search in Thunderbird (the only search UI we have)
silently missed everything older. Now the syncer lists the *full* mailbox
metadata for every folder, and sync_limit governs only how many recent
message bodies are pre-warmed offline. Bodies outside that window are
fetched on demand the first time a client opens the message.

A one-time full-metadata sync (marker full_metadata_synced_v1) completes
the mailbox view on first launch after upgrade.

Crucially, an empty body is now stored as rfc2822 = None rather than a
rendered "(No body available)" placeholder: the placeholder looked like a
real body to the IMAP layer and suppressed the on-demand fetch. CachedMail
gains body_loaded to track whether the body (not just the headers) is final.

Validated live on a 19,322-message INBOX (26,965 mails total across
folders): full listing, on-demand body fetch (~0.1-0.4s), in-memory cache
on re-fetch.
This commit is contained in:
Anthony
2026-05-29 18:45:08 +02:00
parent c401349d24
commit 472eb7880e
7 changed files with 183 additions and 61 deletions
+9 -4
View File
@@ -82,18 +82,23 @@ export function ConfigPanel({ config, status, loading, onSave, onRestart }: Prop
/>
</div>
<div className="form-group">
<label>Mail to sync</label>
<label>Offline message bodies</label>
<small className="field-hint">
Your whole mailbox is always listed and searchable by subject, sender
and date. This only sets how many recent message <em>bodies</em> are
kept ready offline older ones load on demand when you open them.
</small>
<label className="checkbox-field">
<input
type="checkbox"
checked={fetchAll}
onChange={(e) => setFetchAll(e.target.checked)}
/>
<span>Fetch all mail (entire account, kept locally)</span>
<span>Keep every message body offline (full local copy)</span>
</label>
{fetchAll ? (
<small className="field-hint">
Downloads every mail from the start can be slow on large accounts.
Downloads every body slow + uses the most disk on large accounts.
</small>
) : (
<input
@@ -101,7 +106,7 @@ export function ConfigPanel({ config, status, loading, onSave, onRestart }: Prop
min={1}
value={syncLimit}
onChange={(e) => setSyncLimit(Math.max(1, Number(e.target.value)))}
placeholder="Max mails per folder"
placeholder="Bodies to keep offline (most recent)"
/>
)}
</div>