Support: markdown escaping leaks into the text/plain part of outbound email replies
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 39.9k
- Forks
- 3.4k
- Avg merge
- 6h 51m
- Merged PRs (30d)
- 232
Description
Outbound email replies from the Support inbox are sent as multipart/alternative. The text/html part renders correctly, but the text/plain part contains markdown escape sequences as literal backslashes.
In products/conversations/backend/tasks.py, the outbound body is built as:
if comment.rich_content:
html_body = rich_content_to_html(comment.rich_content)
txt_body = rich_content_to_markdown(comment.rich_content, include_images=False)
text/plain isn't markdown, so escapes intended for a markdown renderer are delivered verbatim. Captured from a live reply — the two parts of the same message:
Content-Type: text/plain; charset="utf-8"
ok\. tell me more
Content-Type: text/html; charset="utf-8"
<p>ok. tell me more</p>
Note the ok\. in the plain-text alternative.
Impact. Anyone reading the text/plain part sees the backslashes: plain-text mail clients, assistive tech falling back to that part, and anything downstream parsing it. Agents typing ordinary prose in the rich editor hit this on every reply — it isn't specific to short messages, and it's invisible to the agent because the composer and the HTML part both look right.
We observed it on a period and haven't characterised which other characters the serializer escapes.
Suggested fix. Generate the text/plain alternative with a plain-text serializer (or unescape after serializing), and keep markdown output for the paths where a markdown renderer actually consumes it.
Debug info
PostHog Cloud (US) · Support email channel, Mailgun transport · observed 2026-09-03
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in products/conversations/backend/tasks.py at the rich_content branch, then trace rich_content_to_markdown and the corresponding HTML serializer. Verify how the multipart email body is assembled and which serializer is intended for plain text. Done means the text/plain part contains no markdown escape sequences while the text/html part remains unchanged; cover the observed period case and any other escaping behavior identified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100