Skip to content

fix(email): decode IMAP folder names from modified UTF-7 (#3514)#3544

Open
maxmilian wants to merge 2 commits into
odysseus-dev:devfrom
maxmilian:fix-3514-imap-utf7
Open

fix(email): decode IMAP folder names from modified UTF-7 (#3514)#3544
maxmilian wants to merge 2 commits into
odysseus-dev:devfrom
maxmilian:fix-3514-imap-utf7

Conversation

@maxmilian

Copy link
Copy Markdown
Contributor

Summary

IMAP mailbox names are encoded in modified UTF-7 (RFC 3501), but nothing decoded them, so folders with non-Latin names rendered as their raw wire form (e.g. &BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1- instead of Cyrillic). imaplib does no decoding and Python ships no imap4-utf-7 codec.

This adds a stdlib-only src/imap_utf7 codec and establishes one invariant: folder names are kept decoded everywhere in the Python layer, and _q() — the single mailbox-quoting chokepoint for SELECT/COPY/MOVE/APPENDre-encodes to modified UTF-7 on the way to the server. Decoding is applied where names are read from the LIST response (_folder_name_from_list_line, the /email/folders endpoint, and the \Sent/\Drafts/\Junk detectors), so non-ASCII folders both display correctly and stay selectable (no display-only regression). ASCII names are unchanged by encode/decode.

Files: new src/imap_utf7.py; routes/email_routes.py, routes/email_helpers.py, mcp_servers/email_server.py (decode on read, encode in _q).

Note: the report's expected/actual labels were swapped (&BB4EQgQ,…- actually decodes to Отправленные/“Sent”, not Входящие), but the underlying bug — no MUTF-7 decoding — is exactly as described.

Target branch

  • This PR targets dev, not main.

Linked Issue

Closes #3514

Type of Change

  • Bug fix
  • Feature
  • Refactor
  • Documentation

Checklist

  • I searched open issues and open PRs — this is not a duplicate.
  • This PR targets dev, not main.
  • The change is limited in scope to the linked issue.
  • I ran the app end-to-end against a live IMAP account with non-ASCII folders. (No server with Cyrillic folders on hand; covered by unit tests using the real RFC 3501 wire form instead.)

How to Test

Backend-only, no UI changes. Run the codec + IMAP quoting tests:

python -m pytest tests/test_imap_utf7.py tests/test_imap_mailbox_quoting.py

Or check the round-trip directly:

from src.imap_utf7 import decode_imap_utf7, encode_imap_utf7
decode_imap_utf7("&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-")   # -> 'Отправленные'
encode_imap_utf7("Отправленные")                          # -> '&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-'

To verify against a real account: add an IMAP account that has a folder with a non-Latin name and open the folder list — it now shows the decoded Unicode name, and selecting/reading that folder still works (the name is re-encoded before it hits the server).

Testing

  • python -m pytest tests/test_imap_utf7.py tests/test_imap_mailbox_quoting.py → 17 passed (9 new codec tests + existing quoting tests, which still pass since ASCII names are unchanged).
  • python -m py_compile on all four changed files → clean.

@github-actions github-actions Bot added the ready for review Description complete — ready for maintainer review label Jun 9, 2026
@maxmilian
maxmilian marked this pull request as ready for review June 9, 2026 00:53
@alteixeira20 alteixeira20 added the bug Something isn't working label Jun 12, 2026
maxmilian and others added 2 commits July 15, 2026 22:19
…v#3514)

IMAP mailbox names arrive in modified UTF-7 (RFC 3501), so a Cyrillic
folder showed up as its raw `&BB4EQgQ,...-` wire form in the folder list.
imaplib does no decoding and Python ships no imap4-utf-7 codec.

Add a stdlib-only `src/imap_utf7` codec and establish one invariant: folder
names are kept decoded everywhere in the Python layer, and `_q()` — the single
mailbox-quoting chokepoint for SELECT/COPY/MOVE/APPEND — re-encodes to modified
UTF-7 on the way to the server. Decoding happens where names are read from the
LIST response (`_folder_name_from_list_line`, the /folders endpoint, and the
\Sent/\Drafts/\Junk detectors), so non-ASCII folders both display correctly and
stay selectable. ASCII names are unchanged by encode/decode (verified by the
existing quoting tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Use base64 validate=True so a terminated run of non-Base64 characters
raises and falls back to the verbatim slice, instead of b64decode silently
stripping it to empty — matching the documented 'left verbatim' behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@maxmilian
maxmilian force-pushed the fix-3514-imap-utf7 branch from 8a5d1c6 to 880afe5 Compare July 15, 2026 14:20
@maxmilian

Copy link
Copy Markdown
Contributor Author

Re-verified on a rebase onto today's dev (c80462e) — still cleanly applicable and, as far as I can tell, still the only Modified-UTF-7 handling in the tree (no decoder landed upstream since this was opened; #3514 remains open).

  • tests/test_imap_utf7.py + tests/test_imap_mailbox_quoting.py → 17 passed
  • full email/IMAP-related selection (-k "email or imap") → 213 passed

Happy to adjust scope or squash if the maintainers prefer a different shape for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ready for review Description complete — ready for maintainer review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IMAP folder names encoded in Modified UTF-7 are not decoded

2 participants