perf(icloud): respect iCloud Mail IMAP connection & message-size limits #471

Merged
JMR-dev merged 3 commits from feat-363-icloud-imap-limits into main 2026-07-09 04:04:19 +00:00
3 Commits
Author SHA1 Message Date
Jason Ross d926320123 Merge branch 'main' into feat-363-icloud-imap-limits 2026-07-08 22:36:10 -05:00
JMR-dev abfa60ba86 Merge origin/main into feat-363-icloud-imap-limits (combine iCloud connection-cap + Gmail bandwidth-tracker in MailBackfiller) 2026-07-08 20:23:18 -05:00
JMR-dev 8a70b329ab perf(icloud): respect iCloud Mail IMAP connection & message-size limits
Adds two iCloud-specific, provider-scoped policies that build on the
existing shared throttling framework (#360's AccountThrottleGate, #356's
BackfillPacer) without refactoring either:

- IcloudConnectionLimiter: a per-account permit gate capping an iCloud
  account at 5 simultaneous connections (Apple documents 5-8; pinned to
  the conservative low end). Wired into MailBackfiller around both
  connection-opening call sites (the header-page fetch and the
  body/attachment prefetch loop - the "1 + K + attachments" per-page
  connection count issue #363 describes). A no-op passthrough for every
  other provider, so it composes cleanly with #360's reactive backoff
  (already consulted first, per account) and #356's slice pacing
  (BackfillWorker composes BackfillPacer.runPaced around
  MailBackfiller.runBackfill, so the cap sits one layer beneath the
  pacer's cooldown/cap in the same call graph).

- IcloudSendLimits: enforces Apple's ~20 MB outgoing message-size cap
  before SmtpSender ever opens a connection, estimating the actual
  encoded wire size (base64 inflates binary attachment bytes by ~4/3)
  rather than comparing raw file bytes, mirroring GraphSender's existing
  pre-send attachment-size guard. An over-cap send throws
  MessageTooLargeException, caught by SendWorker's existing runCatching
  and turned into a clean, PII-free outbox error - no crash, no raw
  provider rejection.

Both are new, self-contained files kept intentionally separate from a
shared cross-provider table, per the parallel-safety note on this ticket
(sibling issues #361/#362/#364 add their own provider's limits the same
way).

Touches two shared files: MailBackfiller.kt (new constructor dependency
+ two call sites wrapped in icloudConnectionLimiter.withPermit) and
SendWorker.kt (one guard call before smtpSender.send). Both are
minimal, additive edits — flagged for conflict-awareness with the
sibling provider tickets.

Also excludes MailBackfillerTest.kt from detekt's LargeClass rule
(config/detekt/detekt.yml), mirroring the existing MailRepositoryImplTest
exclusion: one cohesive single-SUT suite tipped over the LLOC boundary
by the new connection-cap wiring tests.

Closes #363
2026-07-08 19:31:03 -05:00