Add attachments command - #2
Open
nitsanavni wants to merge 12 commits into
Open
Conversation
Adds gmail archive <message-id>... which removes the INBOX label, matching Gmail archive behavior. Adds gmail.modify scope to support this. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The archive branch swapped the HTML-to-markdown dependency from html_to_markdown to markdownify. markdownify is declared in neither pyproject.toml nor uv.lock, so `gmail read` raised ModuleNotFoundError on any HTML email. The swap is also unrelated to the archive feature. Claude-Session: https://claude.ai/code/session_01XN4T96G5R4UczQpgA2nqES
An invalid message ID raised HttpError out of the loop, so IDs before it were already archived while IDs after it silently never ran. Report the failure, continue the batch, and exit non-zero. Claude-Session: https://claude.ai/code/session_01XN4T96G5R4UczQpgA2nqES
Adding gmail.modify invalidates every existing token, but the old token still refreshes cleanly, so the API rejected archive with an opaque 403. Credentials.from_authorized_user_info() overrides a token's scopes with the ones passed in, so creds.scopes cannot detect this - read the granted scopes from the token file and re-consent when any required scope is absent. Claude-Session: https://claude.ai/code/session_01XN4T96G5R4UczQpgA2nqES
Adds gmail attachments <message-id> [-o output-dir] to save attachments from an email to disk. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adding cmd_attachments pushed commands.py to 304 lines, over the project's 300-line limit. Move it to its own module, matching account_commands.py. Pure move - behavior is unchanged. Claude-Session: https://claude.ai/code/session_01XN4T96G5R4UczQpgA2nqES
Attachment filenames come from the email, so the sender controls them.
'output_dir / filename' honored both traversal names ('../../.ssh/authorized_keys')
and absolute names ('/etc/cron.d/pwn') - pathlib discards the left operand
entirely when the right one is absolute. Anyone who could email the user could
write a file anywhere the user could write.
Keep only the final path component, and skip names that sanitize to nothing.
Claude-Session: https://claude.ai/code/session_01XN4T96G5R4UczQpgA2nqES
The loop only scanned payload['parts'], so attachments inside a nested multipart/related or multipart/alternative - which is how most mail clients structure messages - reported "No attachments found." get_body() in commands.py already recurses for the same reason; mirror it. Claude-Session: https://claude.ai/code/session_01XN4T96G5R4UczQpgA2nqES
Three write-path problems: '-o some/new/dir' raised FileNotFoundError because the directory was never created; two attachments sharing a filename silently clobbered each other; and a missing 'data' field raised KeyError. Claude-Session: https://claude.ai/code/session_01XN4T96G5R4UczQpgA2nqES
Covers the path-traversal containment, nested-part discovery, filename collisions, and output-dir creation. Verified these fail against the pre-fix behavior. Claude-Session: https://claude.ai/code/session_01XN4T96G5R4UczQpgA2nqES
saadiq
force-pushed
the
add-attachments-command
branch
from
July 14, 2026 03:46
6411372 to
315d707
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
gmail attachments <message-id> [-o output-dir]command to download email attachments to disk--outputflagTest plan