feat: add --attach flag to send and reply commands - #3
Open
nitsanavni wants to merge 11 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
Support sending file attachments via repeatable --attach flag. When attachments are provided, builds a MIMEMultipart message with the text body and base64-encoded file parts. Without attachments, behavior is unchanged (plain MIMEText). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Attachment support pushed commands.py to 298 lines, leaving no room under the project's 300-line limit for the error handling the feature still needs. Move the message-building helpers into their own module. Pure move - behavior is unchanged. Claude-Session: https://claude.ai/code/session_01XN4T96G5R4UczQpgA2nqES
build_message() can now return a MIMEMultipart, but set_optional_recipients() and encode_message() were still annotated as taking MIMEText, so every call with an attachment was a type error. Add a Message alias and use it throughout. Claude-Session: https://claude.ai/code/session_01XN4T96G5R4UczQpgA2nqES
A missing or unreadable --attach path raised FileNotFoundError out of build_message(). Report every bad path with a clear message and exit 1, and do it before authenticate() so a typo doesn't drag the user through OAuth first. Also reject messages over Gmail's 25MB limit, which otherwise fail with an opaque API error. The check measures the RFC822 message rather than the base64url 'raw' field: attachments are already base64-encoded inside the message, so 'raw' runs ~1.8x the original file and would reject legal sends (a 17MB file is a 23MB message - fine - but a 30.6MB 'raw'). Claude-Session: https://claude.ai/code/session_01XN4T96G5R4UczQpgA2nqES
saadiq
force-pushed
the
add-send-attachments
branch
from
July 14, 2026 03:49
1df4306 to
f8a03de
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
--attachflag to bothsendandreplycommands viaadd_compose_argsbuild_messagehelper incommands.py: when attachments are provided, builds aMIMEMultipartmessage with the text body and base64-encoded file parts; without attachments, returns plainMIMETextas beforemimetypes.guess_typefor content type detection, falls back toapplication/octet-streamTest plan
gmail send --helpshows--attachflaggmail reply --helpshows--attachflag--draft --attach /tmp/test-attachment.txt-- draft appeared in Gmail with attachment🤖 Generated with Claude Code