Repository navigation
One body, one format: body_format replaces body_html on the compose tools - #22
Merged
Merged
Conversation
…ools Choosing HTML meant passing body AND body_html -- the same message written twice, where the second copy is the one that rots: an edit to the HTML leaves yesterday's sentence in the plain-text half, and nobody proofreading the mail sees it. The compose tools (mail_send, mail_create_draft, mail_edit_draft) now take one `body` plus `body_format` = text (the default) | html. tools/_common.as_bodies splits it into the (text, html) pair MailProvider still takes, so the wire is unchanged: multipart/alternative, text first. The provider-level body_html is untouched, which is where a caller wanting a hand-written plain-text alternative still has one -- the case this deliberately drops one level up. The derived half is html_text.html_to_text: blocks to line breaks, list items to dashes, entities to characters. That same function now serves the read path too. It used to be a private copy in imap.py that collapsed every message to a single line and left `&` sitting in the text. An unrecognised format is refused, not guessed -- "markdown" would otherwise leave as literal asterisks. tests/test_body_format.py pins the split, the flattening and the refusal. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q8d2HEM2snepz9KrWXTF77
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q8d2HEM2snepz9KrWXTF77
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
mail_send,mail_create_draftandmail_edit_draftnow take onebodyplusbody_format=text(the default) |html, in place of the oldbody+body_htmlpair.Why
Choosing HTML meant writing the same message twice, and the second copy is the
one that rots: an edit to the HTML leaves yesterday's sentence in the
plain-text half, where nobody proofreading the mail will see it. Two arguments
for one decision.
How
tools/_common.as_bodies(body, body_format)splits the one body into the(text, html)pairMailProviderstill takes. The wire is unchanged --multipart/alternative, text first. The provider-levelbody_htmlisuntouched, so the admin package's Graph backend needs no change.
html_text.html_to_textderives the plain-text half: blocks to line breaks,list items to dashes, entities to characters. That is the trade being made,
and it is named in
CLAUDE.md-- worse than an alternative written by hand,better than one that disagrees with the HTML. A caller who wants to write it
themselves still can, one level down in the provider.
in
imap.pythat collapsed every message to a single line and left&sitting in the text.
markdownwould otherwiseleave as literal asterisks.
body_format="html"; themultipart/relatedplacement in
mime._add_partsis unchanged.Breaking
body_htmlis gone from the MCP tool surface (it remains onMailProvider).The admin package registers this same tool layer, so the two ship together via
SQUIRREL_MCP_REF.Tests
tests/test_body_format.pypins the split, the flattening and the refusal;tests/test_attachments_inline.pyupdated to the new argument. Lint, types andthe 295-test unit suite are green locally; the GreenMail e2e only touches the
provider-level API, which is unchanged.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Q8d2HEM2snepz9KrWXTF77
Generated by Claude Code