-
released this
2026-08-22 12:25:27 -05:00 | 12 commits to main since this releaseTwo defects found the same way the last three were: a person used the connector and
asked what an answer meant. Checking the Gmail spam folder produced{"messages": [], "count": 0}— read, reasonably, as "the Spam folder is clear". It held 29 messages. Then
inspecting one of them failed twice with aTypeErrorabout a type nobody had heard of.Fixed
-
A folder name that matched nothing was answered with an empty result instead of an
error.folders=["SPAM"]reached IMAP unchanged;SELECTrefused it;search_messages
caught the refusal per folder — correctly, because one bad label must not lose the rest
of a search — and the caller was handed a clean, successful, empty answer. The real label
is[Gmail]/Spam.The bug is not that the guess failed. It is that failing was indistinguishable from
succeeding, which is this project's recurring defect in its purest form: nothing in the
response could tell "this folder is empty" from "this folder does not exist", so there
was no way to be suspicious of it.list_folderswas the only route to the exact
strings, and nothing required calling it first.Names are now resolved against the readable labels before any command is sent, in four
tiers — the exact name, then case-insensitively, then with the[Gmail]/prefix
optional, then by RFC 6154 role, sospam,junk,binandarchiveland on the right
label on an account in any language. A name that still matches nothing is refused
with the closest real label named: "There is no folder named 'Spem'… Did you mean
'[Gmail]/Spam'?" The four tiers are ordered so a user label literally calledSpam
outranks the role folder it shadows.Resolution only ever considers labels
MAIL_FOLDERSalready allows, so it is not a way
around the allowlist, and the handle path — where amessage_idnames its own folder —
is deliberately left matching exactly. -
A single 8-bit byte in a header took
get_message_securityout entirely. The error
wassequence item 0: expected str instance, Header found, and it repeated because
nothing about it suggested retrying was pointless.Message.getdoes not always return a string. The compat32 policy wraps any header whose
raw bytes are not ASCII in anemail.header.Header, and that is the ordinary shape of
spam — an unencoded em dash in aFromor aList-Unsubscribeis a syntax error the
RFCs forbid and bulk senders emit anyway. So the tool whose entire job is judging
suspicious mail was lost to the malformation that makes mail suspicious.Two more failures sat behind it, neither reported yet and both reachable from the same
message:decode_headerraisedLookupError: unknown encoding: unknown-8bit— which is
the read path, not the security path — and_unsubscriberaisedAttributeErroron
Header.strip. Every header now leaves the message throughmail/headers.py, which
flattensHeader,strand absent alike, and falls back to UTF-8 for any charset label
Python cannot look up rather than raising.The bytes are decoded, not replaced.
str(Header)renders every non-ASCII byte as
U+FFFD;decode_headerhands the original bytes back, and they are nearly always UTF-8,
so the character the sender wrote is what a reader sees. A header that is both 8-bit
and RFC 2047 needs two passes to get there — the firstdecode_headershort-circuits
on aHeaderand leaves=?utf-8?B?…?=sitting in the output as literal text.
Notes
-
The Gmail fake refused nothing before this.
select_folderaccepted any name, so the
silent-empty defect could not be reproduced against it however many tests were written —
the same lesson as 0.29.6's crowded label, one file along. It now answers
NO [NONEXISTENT] Unknown Mailboxthe way the server does, and serves whole-message bytes
soget_messageandget_message_securityrun end to end for the first time. -
Verified by reverting. Each new test was run against the unpatched code: the tool
returns{'messages': [], 'count': 0}for["SPAM"], and the malformed message raises
TypeError,LookupErrorandAttributeErrorin three separate places. -
The header fix is in
mail/, so the iCloud tenant gets it too — it parses the same
messages with the same functions and had the same crash waiting in it. -
icloudmailstill has the folder defect. Its_search_targetsmatches names
literally in exactly the same way. Not fixed here: its folder story is different enough —
wildcards, no SPECIAL-USE on Drafts — that the resolver is not liftable unchanged, and
guessing at it without a live pass is how the last one shipped.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-