Skip to content

feat(smtp): quote original message in replies by default#48

Open
ilyasturki wants to merge 1 commit into
codefuturist:mainfrom
ilyasturki:feat/quote-original
Open

feat(smtp): quote original message in replies by default#48
ilyasturki wants to merge 1 commit into
codefuturist:mainfrom
ilyasturki:feat/quote-original

Conversation

@ilyasturki

Copy link
Copy Markdown

What

Adds a new quoteOriginal: boolean parameter (default true) to the reply_email MCP tool. When enabled (the default), the original message is appended below the user's reply body as a quoted block — the same convention every desktop client (Thunderbird, Outlook, Apple Mail) uses automatically.

Why

Until now reply_email sent only the user-supplied body, so the recipient saw a context-free reply ("Sorry for the delay, can we do this now?") with no reference to what was being replied to. This makes the MCP feel less polished than a regular mail client and forces the recipient to dig into the thread to remember what's being answered.

There is no existing issue for this — opening it as a feature PR.

Changes

  • New src/utils/quote.ts produces:
    • Plain text replies: On DATE, NAME <addr> wrote: attribution line followed by >-prefixed original body (Thunderbird/Mutt style).
    • HTML replies: same attribution, original body wrapped in <blockquote type="cite"> — recognized by every client as quoted material.
  • For text replies whose original was HTML-only, the HTML is stripped to plain text first via the same stripper used elsewhere in the codebase (emails.tool.ts).
  • For HTML replies whose original was text-only, the text is HTML-escaped and wrapped in <pre>.
  • Sender names and email addresses in the HTML attribution are properly escaped to prevent injection.

API

// reply_email tool now accepts:
{
  account: string;
  emailId: string;
  body: string;
  // ... existing params
  quoteOriginal?: boolean; // default true
}

Set quoteOriginal: false to send the bare body only (current behavior).

Tests

  • New quote.test.ts covers text/html quoting paths, name/address formatting, blank-line preservation, HTML escaping.
  • Extended smtp.service.test.ts with a replyToEmail quote_original suite (default-on, html path, explicit opt-out).
  • 160 tests pass (was 150).

Manual integration test

End-to-end: account A sends a seed mail to account B → account B calls reply_email with default quoteOriginal=true → account A receives a reply containing both the new body on top AND the original quoted below. Verified the rendered output in Thunderbird matches expectations.

Until now `reply_email` sent only the user-supplied body, so the
recipient saw a context-free reply ("Sorry for the delay, can we do
this now?") with no reference to what was being replied to. Every
desktop mail client (Thunderbird, Outlook, Apple Mail) prepends the
original message as quoted text by default — the MCP didn't.

- New tool parameter `quoteOriginal: boolean` (default `true`) on
  `reply_email`. Pass `false` to send the bare body only.
- New `src/utils/quote.ts` produces:
  - Plain text replies: "On DATE, NAME <addr> wrote:" attribution
    followed by `>`-prefixed original body (Thunderbird/Mutt style).
  - HTML replies: same attribution, original body wrapped in
    `<blockquote type="cite">` which every client recognizes as
    quoted material.
- For text replies whose original was HTML-only, the HTML is stripped
  to plain text first via the same stripper used elsewhere in the
  codebase. For HTML replies whose original was text-only, the text is
  HTML-escaped and wrapped in `<pre>`.
- Sender names and email addresses in the HTML attribution are
  properly escaped to prevent injection.

Tests:
- New `quote.test.ts` covers text/html quoting, name/address
  formatting, blank-line preservation, and HTML escaping.
- Extended `smtp.service.test.ts` with a `replyToEmail quote_original`
  suite (default-on, html path, explicit opt-out).
Copilot AI review requested due to automatic review settings May 25, 2026 18:52
@ilyasturki ilyasturki requested a review from codefuturist as a code owner May 25, 2026 18:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds reply-quoting support so replies include a standard “On , wrote:” attribution plus quoted original content, improving context for recipients.

Changes:

  • Introduces quoteOriginalAsText / quoteOriginalAsHtml utilities for generating quoted blocks.
  • Adds quoteOriginal parameter (default true) to the send/reply tool + SMTP reply path to optionally append the quote.
  • Adds unit tests for quoting helpers and SMTP reply behavior with/without quoting.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/utils/quote.ts Adds utilities to quote original emails as text or HTML.
src/utils/quote.test.ts Adds tests for text/HTML quote generation and escaping behavior.
src/tools/send.tool.ts Extends tool schema with quoteOriginal flag (default enabled).
src/services/smtp.service.ts Appends quoted original to reply body by default; supports opt-out.
src/services/smtp.service.test.ts Adds tests validating quoting behavior in SMTP reply flow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/utils/quote.ts
Comment on lines +70 to +72
if (original.bodyHtml) {
inner = original.bodyHtml;
} else if (original.bodyText) {
Comment thread src/utils/quote.ts
Comment on lines +54 to +60
const attribution = `On ${original.date}, ${formatSender(original.from)} wrote:`;
const body = original.bodyText ?? (original.bodyHtml ? stripHtml(original.bodyHtml) : '');
const quoted = body
.split('\n')
.map((line) => (line.length > 0 ? `> ${line}` : '>'))
.join('\n');
return `\n\n${attribution}\n${quoted}`;
Comment thread src/utils/quote.ts
* > line 2
*/
export function quoteOriginalAsText(original: Email): string {
const attribution = `On ${original.date}, ${formatSender(original.from)} wrote:`;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants