Skip to content

Download only the parts a tool uses - #48

Merged
odrobnik merged 2 commits into
mainfrom
claude/lean-fetch
Oct 7, 2026
Merged

odrobnik merged 2 commits into
mainfrom
claude/lean-fetch

Conversation

@odrobnik

@odrobnik odrobnik commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Stacked on #47 (base claude/imap-connection-race): it reuses #47's header-only fetch and extra connections. Merge #47 first; GitHub then retargets this PR to main.

Problem

SwiftMail's fetchMessages(using:) fetches each message's structure and then every part, attachments included. Four tools went through it although none of them uses attachment data:

  • listMessages (post list) only shows header data,
  • fetchMessage (post fetch without --eml) shows the text and HTML bodies and lists attachments by name and type,
  • exportPDF (post pdf) renders the text or HTML body,
  • downloadAttachment (post attachment) needs one part.

So listing a folder, or reading an email with a 77 MB video attached, downloaded the video.

Fix

  • listMessages fetches header data only (fetchMessageInfosBulk, in chunks of 200) and runs on an extra connection, like search.
  • fetchMessage and exportPDF start from the message's outline (header data plus structure, fetchOutline) and download only Message.bodies (downloading(_:of:uid:using:)). Attachments are still listed from the structure.
  • downloadAttachment chooses the part (by cid, by filename, or the first attachment) from the outline and downloads only that part. Errors are unchanged.
  • collectHeaders(from:) is gone; nothing uses it any more.

Tests

  • swift test: 61 tests, 0 failures (3 live tests skipped without credentials).
  • New LeanFetchLiveTests (read-only; runs only with POST_LIVE_TEST_SERVER): compares the listing and fetchMessage results for the newest 8 messages with full downloads, and a downloaded attachment with the full download's part (POST_LIVE_TEST_ATTACHMENT=<mailbox>:<uid>). Passed on two accounts' INBOX and Sent and on a PDF attachment.
  • ConcurrentMailboxAccessLiveTests from Stop concurrent requests from running in each other's mailbox #47, which now also exercises the listing on an extra connection, still passes.

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c82b077726

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/PostServer/PostServer.swift Outdated
Comment thread Sources/PostServer/PostServer.swift
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-07T16:26:19.931749Z c82b077 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

odrobnik and others added 2 commits October 7, 2026 18:36
SwiftMail's fetchMessages(using:) downloads every part of a message,
attachments included. Listing, post fetch, attachment downloads and
PDF export all went through it, so listing a folder or reading the text
of an email with a 77 MB video downloaded the video.

- listMessages fetches header data only, on an extra connection like
  search.
- fetchMessage and exportPDF fetch the structure, then only the text and
  HTML bodies; attachments are still listed by name and type.
- downloadAttachment picks the part from the structure and downloads
  only that part.

LeanFetchLiveTests compares the results with full downloads on a real
account; it runs only with POST_LIVE_TEST_SERVER set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fetchMessage expanded the requested UID set into an array and fetched
it 200 UIDs at a time, so a range like 1-1000000 meant a million-element
array and 5,000 FETCH commands. It now sends the set as given in one
UID FETCH, and the server answers only for messages that exist.
SwiftMail's fetchMessages expanded such ranges as well, in
chunked(size:).

The header fetch uses SwiftMail's default info set, which includes the
full header section, so additional headers are still filled. The doc
comment that said otherwise is corrected; the live test now compares
additional headers too and fetches a wide range.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@odrobnik
odrobnik changed the base branch from claude/imap-connection-race to main October 7, 2026 16:36
@odrobnik
odrobnik merged commit 8ca5741 into main Oct 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant