v2.0.7
Sixth adversarial review round, following up on real-mailbox testing of v2.0.6. Eight confirmed findings, fixed and verified with new regression tests (299 β 310).
Fixed
list_draftscould permanently brick the MCP session on a large attachment. It has no filter and returns every draft unconditionally;DraftRecord.attachmentscarries full base64 content, and the response serializes the whole payload twice (text and structuredContent), so one large attachment on any draft could exceed the MCP stdio client's read buffer on every call β including the next session's startup listing. Attachment content is now redacted (filename/type/size only) inlist_drafts;get_draftis unaffected.- An unparseable
Dateheader crashedtoSummary()for the whole folder. imapflow leavesenvelope.dateas the raw header string (not anInvalid Date) when it can't parse it; calling.toISOString()on that unconditionally threw, abortinggetEmails/searchEmails/sync/getEmailByIdfor every message in the folder over one bad message. - Multi-word indexed search returned 0 results when the words weren't adjacent. The SQL/FTS5 layer correctly ANDs each word as its own term, but the post-filter required the entire query as one literal substring β dropping any match whose words were merely out of order or separated by other words.
dateFromwas compared as a raw string in the SQL candidate pre-filter, unlikedateTowhich was already normalized β adateFromwith a timezone offset, a bare date, or an English date string could silently exclude matching messages via a wrong lexicographic comparison.isHtml:truesent raw, pre-sanitization HTML as the text/plain part of the message β content the HTML sanitizer had just stripped (script tags,javascript:URIs) still reached plain-text-preferring clients intact.- A CLI boolean flag placed before a positional argument swallowed it (
search --json invoicedropped the query entirely) β the parser had no notion of which flags are boolean. getThreads({query})built partial or wrongly-excluded threads. A query matching only a reference chain's root (which has no persisted thread_id and no reference headers of its own) built a thread from the root alone; fixing that then surfaced that the outer filter checked only the thread's latest-message subject, wrongly excluding threads whose matching message wasn't the most recent one.- Folder names containing
%or,broke indexing and folder resolution. A bare%in a folder/label name crasheddecodeURIComponent()insiderecordSnapshot(), rolling back the entire index snapshot; a folder name containing a comma was always split as a multi-folder list instead of resolving to itself.