fix: use RFC 2231 encoding for non-ASCII attachment filenames - #502
Conversation
When creating Gmail drafts with attachments whose filenames contain
non-ASCII characters (e.g. umlauts like ü, ö, ä), Gmail displays
"noname" instead of the actual filename.
The root cause is that Content-Disposition was built via string
formatting (f'attachment; filename="{safe_filename}"'), which embeds
raw non-ASCII bytes in the header. Gmail cannot parse these and falls
back to "noname".
Fix: pass the filename as a keyword argument to add_header(), which
makes Python's email library automatically apply RFC 2231 encoding
(filename*=utf-8''...) for non-ASCII names while keeping ASCII
filenames unchanged.
Fixes taylorwilsdon#500
|
Caution Review failedThe pull request is closed. ℹ️ Recent review infoConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe change updates Gmail attachment filename handling by using the email library's header helper: Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
gmail/gmail_tools.py (1)
330-343: LGTM! Correct fix for RFC 2231 encoding.Using
add_headerwith thefilenamekeyword argument is the proper way to handle non-ASCII filenames. Python's email library will automatically apply RFC 2231 encoding (e.g.,filename*=utf-8''Pr%C3%BCfbericht.pdf) for non-ASCII characters while leaving ASCII-only filenames in simple format.One minor suggestion for consistency: consider also stripping null bytes (
\x00) from the filename, as is done forfrom_namesanitization on lines 359-361.,
🔧 Optional: Add null byte stripping for consistency
safe_filename = ( (filename or "attachment") .replace("\r", "") .replace("\n", "") + .replace("\x00", "") )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@gmail/gmail_tools.py` around lines 330 - 343, The filename sanitization should also strip null bytes like the from_name sanitization does; update the safe_filename computation (the expression assigning safe_filename used before part.add_header and referencing (filename or "attachment")) to additionally remove "\x00" (e.g., .replace("\x00", "") ) so non-ASCII handling via add_header remains and null bytes are consistently stripped.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@gmail/gmail_tools.py`:
- Around line 330-343: The filename sanitization should also strip null bytes
like the from_name sanitization does; update the safe_filename computation (the
expression assigning safe_filename used before part.add_header and referencing
(filename or "attachment")) to additionally remove "\x00" (e.g.,
.replace("\x00", "") ) so non-ASCII handling via add_header remains and null
bytes are consistently stripped.
|
Lgtm better than the copilot auto pr mess haha thanks! |
|
Thanks for the review! Happy to make any adjustments if needed. |
There was a problem hiding this comment.
Pull request overview
This pull request fixes issue #500 where Gmail displays "noname" for email attachments with non-ASCII filenames (e.g., German umlauts like ü, ö, ä). The root cause was that Content-Disposition headers were constructed using string formatting, which embedded raw non-ASCII bytes that Gmail cannot parse.
Changes:
- Modified attachment filename handling to use RFC 2231 encoding via
add_header()keyword arguments - Updated filename sanitization to remove control characters (\r, \n, \x00) instead of escaping quotes and backslashes
- Changed default filename from empty string to "attachment" for better fallback behavior
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Use add_header with keyword argument so Python's email | ||
| # library applies RFC 2231 encoding for non-ASCII filenames | ||
| # (e.g. filename*=utf-8''Pr%C3%BCfbericht.pdf). Manual | ||
| # string formatting would drop non-ASCII characters and cause | ||
| # Gmail to display "noname". | ||
| safe_filename = ( | ||
| (filename or "") | ||
| (filename or "attachment") | ||
| .replace("\r", "") | ||
| .replace("\n", "") | ||
| .replace("\\", "\\\\") | ||
| .replace('"', r"\"") | ||
| .replace("\x00", "") | ||
| ) | ||
|
|
||
| part.add_header( | ||
| "Content-Disposition", f'attachment; filename="{safe_filename}"' | ||
| "Content-Disposition", "attachment", filename=safe_filename | ||
| ) |
There was a problem hiding this comment.
The attachment handling logic, including the RFC 2231 encoding fix for non-ASCII filenames, lacks test coverage. Consider adding tests to verify:
- Non-ASCII filenames are properly encoded (e.g., "Prüfbericht.pdf" produces filename* header)
- ASCII-only filenames remain unchanged
- Edge cases like filenames with control characters
- Filenames that become empty after sanitization
This is important to prevent regressions of the fix for issue #500.
| # (e.g. filename*=utf-8''Pr%C3%BCfbericht.pdf). Manual | ||
| # string formatting would drop non-ASCII characters and cause | ||
| # Gmail to display "noname". |
There was a problem hiding this comment.
The comment states that manual string formatting "would drop non-ASCII characters", but more accurately, it embeds them as raw bytes that Gmail cannot parse. Consider updating the comment to:
"Manual string formatting would embed non-ASCII characters as raw bytes, which Gmail cannot parse and causes it to display 'noname'."
This is more technically accurate about what's happening.
| # (e.g. filename*=utf-8''Pr%C3%BCfbericht.pdf). Manual | |
| # string formatting would drop non-ASCII characters and cause | |
| # Gmail to display "noname". | |
| # (e.g. filename*=utf-8''Pr%C3%BCfbericht.pdf). Manual string | |
| # formatting would embed non-ASCII characters as raw bytes, | |
| # which Gmail cannot parse and causes it to display "noname". |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Summary
Fixes #500 — Gmail displays "noname" for attachments whose filenames contain non-ASCII characters (e.g.
Prüfbericht Q1.pdf).Root Cause
Content-Dispositionwas constructed via string formatting:This embeds raw non-ASCII bytes directly in the MIME header. Gmail cannot parse them and falls back to "noname".
Fix
Pass the filename as a keyword argument to
add_header():Python's
emaillibrary then automatically applies RFC 2231 encoding for non-ASCII filenames:ASCII-only filenames remain unchanged (
filename="Statusbericht Projekt.pdf").Verification
The backslash/quote escaping that was previously applied is no longer needed —
add_header()handles all quoting and encoding internally.Summary by CodeRabbit