Skip to content

Attachment filenames with RFC 2047 encoded-words or invalid path characters cause extraction crash #4

Closed

Description

@thomasmaerz

Bug

Extraction crashes with [Errno 2] No such file or directory when an attachment filename contains RFC 2047 encoded-words or characters invalid for filesystem paths.

Evidence

ERROR	attachments	860B24CB-FEF5-4651-9B07-388D74C1D77C.olk15MsgAttachment	[Errno 2] No such file or directory: '/Users/thomasmaerz/olk15-export/output_fresh/attachments/860B24CB-FEF5-4651-9B07-388D74C1D77C/ =?UTF-8?B?MV9sZWFzZV/np5/os4PlkIjntIQ=?=.1.pdf'

The filename has two problems:

  1. RFC 2047 encoded-word not decoded — =?UTF-8?B?MV9sZWFzZV/np5/os4PlkIjntIQ=?= is a base64-encoded UTF-8 string (decodes to Chinese characters) that should be decoded before writing to disk
  2. Leading space — the filename starts with a space character, which can cause path resolution issues on some filesystems

Root Cause

parsers/attachment.py:58-64 extracts the filename from MIME headers as a raw string without:

  • Decoding RFC 2047 encoded-words (=?charset?encoding?text?= format)
  • Sanitizing characters that are invalid or problematic in filesystem paths

The raw filename is then passed to writer.py:71 which does (att_dir / filename).write_bytes(data) — no validation or sanitization.

Proposed Fix

  1. In parsers/attachment.py, use email.header.decode_header() to decode RFC 2047 encoded-words in filename values
  2. In writer.py, add a _sanitize_filename() helper that:
    • Strips leading/trailing whitespace
    • Replaces path separators (/, \\) and other invalid characters (:, *, ?, ", <, >, |)
    • Truncates to a reasonable max length (e.g. 200 chars)
    • Appends a counter suffix on collision
  3. Add a test case with the Chinese-encoded PDF filename

Activity

  1. thomasmaerz commented on Apr 7, 2026

    @thomasmaerz
    OwnerAuthor

    Fix Applied

    This issue has been resolved with the following changes:

    Root Cause

    The attachment parser (parsers/attachment.py) extracted filenames from MIME headers as raw strings without decoding RFC 2047 encoded-words or RFC 5987 percent-encoded filenames. The raw filename was then passed directly to writer.py which wrote to disk without sanitization.

    Changes Made

    1. Added _decode_filename() function in parsers/attachment.py that:

      • Decodes RFC 2047 base64 and quoted-printable encoded-words
      • Decodes RFC 5987 percent-encoded filenames
      • Strips leading/trailing whitespace and surrounding quotes
    2. Added _sanitize_filename() function in writer.py that:

      • Normalizes Unicode with NFC
      • Replaces path separators and invalid filesystem characters
      • Truncates to 200 chars preserving extension
      • Handles filename collisions
    3. Wired both functions into the attachment parsing and writing pipeline

    Verification

    • All 54 tests pass
    • The problematic attachment (860B24CB-FEF5-4651-9B07-388D74C1D77C) now extracts successfully with a decoded Chinese filename
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions