Skip to content

fix: use RFC 2231 encoding for non-ASCII attachment filenames - #502

Merged
taylorwilsdon merged 3 commits into
taylorwilsdon:mainfrom
stakeswky:fix/non-ascii-attachment-filenames
Feb 24, 2026
Merged

fix: use RFC 2231 encoding for non-ASCII attachment filenames#502
taylorwilsdon merged 3 commits into
taylorwilsdon:mainfrom
stakeswky:fix/non-ascii-attachment-filenames

Conversation

@stakeswky

@stakeswky stakeswky commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #500 — Gmail displays "noname" for attachments whose filenames contain non-ASCII characters (e.g. Prüfbericht Q1.pdf).

Root Cause

Content-Disposition was constructed via string formatting:

part.add_header('Content-Disposition', f'attachment; filename="{safe_filename}"')

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():

part.add_header('Content-Disposition', 'attachment', filename=safe_filename)

Python's email library then automatically applies RFC 2231 encoding for non-ASCII filenames:

Content-Disposition: attachment; filename*=utf-8''Pr%C3%BCfbericht%20Q1.pdf

ASCII-only filenames remain unchanged (filename="Statusbericht Projekt.pdf").

Verification

from email.mime.base import MIMEBase
from email import encoders

part = MIMEBase('application', 'pdf')
part.set_payload(b'test')
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment', filename='Prüfbericht Q1.pdf')
print(part['Content-Disposition'])
# → attachment; filename*=utf-8''Pr%C3%BCfbericht%20Q1.pdf  ✅

The backslash/quote escaping that was previously applied is no longer needed — add_header() handles all quoting and encoding internally.

Summary by CodeRabbit

  • Bug Fixes
    • Attachments with non-ASCII filenames now display correctly instead of appearing unnamed.
    • Filename handling improved: non-ASCII characters preserved, CR/LF/null chars removed, backslash/quote escaping avoided.
    • A sensible default filename ("attachment") is used when none is provided and encoding is handled properly for safe display.

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
@coderabbitai

coderabbitai Bot commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2526b87 and 252487f.

📒 Files selected for processing (1)
  • gmail/gmail_tools.py

📝 Walkthrough

Walkthrough

The change updates Gmail attachment filename handling by using the email library's header helper: part.add_header('Content-Disposition', 'attachment', filename=safe_filename). Filenames are sanitized (remove CR/LF/null) and default to "attachment" when missing, allowing RFC 2231 encoding for non-ASCII names.

Changes

Cohort / File(s) Summary
Attachment filename encoding
gmail/gmail_tools.py
Replaced manual Content-Disposition header string construction with part.add_header(..., filename=...); sanitize filename by removing CR/LF/NULL, ensure non-empty safe_filename default "attachment", stop manual backslash/quote escaping to let the email lib emit RFC 2231-encoded filename* for non-ASCII names.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰
I nudged a header, kept names bright,
Gave umlauts back their proper light.
No more "noname" in Gmail's view,
Attachments shine — their names come through.
A little hop, a tidy fix, hooray!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description covers the root cause, fix, and verification with code examples. However, it does not follow the required template with Type of Change, Testing, and Checklist sections. Add the required sections from the template: Type of Change (mark Bug fix), Testing, and Checklist to ensure consistency and clarity.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: implementing RFC 2231 encoding for non-ASCII attachment filenames, which is the core fix in this PR.
Linked Issues check ✅ Passed The PR successfully addresses issue #500 by implementing RFC 2231 encoding for non-ASCII filenames, handling the Content-Disposition header correctly and preserving ASCII-only filename behavior.
Out of Scope Changes check ✅ Passed The changes are focused on fixing the Content-Disposition header encoding issue. Minor null byte stripping in filename handling is a reasonable part of filename sanitization and not out of scope.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
gmail/gmail_tools.py (1)

330-343: LGTM! Correct fix for RFC 2231 encoding.

Using add_header with the filename keyword 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 for from_name sanitization 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.

@taylorwilsdon

Copy link
Copy Markdown
Owner

Lgtm better than the copilot auto pr mess haha thanks!

@stakeswky

Copy link
Copy Markdown
Contributor Author

Thanks for the review! Happy to make any adjustments if needed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Comment thread gmail/gmail_tools.py Outdated
Comment thread gmail/gmail_tools.py
Comment on lines +330 to 344
# 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
)

Copilot AI Feb 24, 2026

Copy link

Choose a reason for hiding this comment

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

The attachment handling logic, including the RFC 2231 encoding fix for non-ASCII filenames, lacks test coverage. Consider adding tests to verify:

  1. Non-ASCII filenames are properly encoded (e.g., "Prüfbericht.pdf" produces filename* header)
  2. ASCII-only filenames remain unchanged
  3. Edge cases like filenames with control characters
  4. Filenames that become empty after sanitization

This is important to prevent regressions of the fix for issue #500.

Copilot uses AI. Check for mistakes.
Comment thread gmail/gmail_tools.py
Comment on lines +332 to +334
# (e.g. filename*=utf-8''Pr%C3%BCfbericht.pdf). Manual
# string formatting would drop non-ASCII characters and cause
# Gmail to display "noname".

Copilot AI Feb 24, 2026

Copy link

Choose a reason for hiding this comment

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

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.

Suggested change
# (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".

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@taylorwilsdon
taylorwilsdon merged commit 8d2b23a into taylorwilsdon:main Feb 24, 2026
4 of 5 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.

draft_gmail_message: Non-ASCII characters in attachment filenames result in "noname" display in Gmail

3 participants