Email reply parser

Just the reply, never the thread under it

Every email that reaches AI Inbx is cut into what the sender wrote, what they quoted and their signature. stripped_text is the part that is new, answers typed inside the quote included.

Priya’s reply from Outlook, cut into segments.

RE: Ticket #4127: CSV export failssegments
  1. written
    Hi Sam, answers below.
  2. signature
    Thanks,Priya NairOperations lead, Lumen Health+44 20 7946 0321
  3. quoted
    From: Yourapp Support <support@mail.yourapp.com>Sent: Tuesday, September 22, 2026 10:14To: Priya Nair <priya@lumenhealth.com>Subject: RE: Ticket #4127: CSV export fails Hi Priya, Sorry the export failed. Three things will help us find it: Which browser are you on?
  4. written
    Edge, latest version.
  5. quoted
    Does it fail for every date range?
  6. written
    Only for ranges longer than 90 days.
  7. quoted
    Roughly how many rows are in the export?
  8. written
    About 40,000.
  9. quoted
    Thanks,SamYourapp Support

What she wrote, as your code reads it.

stripped_text
Hi Sam, answers below. > Which browser are you on?Edge, latest version. > Does it fail for every date range?Only for ranges longer than 90 days. > Roughly how many rows are in the export?About 40,000.

Threads

Outlook marks nothing. The thread does.

Outlook quotes under a header block with no > on any line, so answers typed inside look like quote. When the message being answered is on the thread, each line copied from it is quote, and what is left is hers.

Threads
From: Yourapp Support <support@mail.yourapp.com>Sent: Tuesday, September 22, 2026 10:14To: Priya Nair <priya@lumenhealth.com>Subject: RE: Ticket #4127: CSV export fails
  • Hi Priya,in Sam’s message
  • Sorry the export failed. Three things will help us find it:in Sam’s message
  • Which browser are you on?in Sam’s message
  • Edge, latest version.written
  • Does it fail for every date range?in Sam’s message
  • Only for ranges longer than 90 days.written
  • Roughly how many rows are in the export?in Sam’s message
  • About 40,000.written
  • Thanks,in Sam’s message
  • Samin Sam’s message
  • Yourapp Supportin Sam’s message

Signatures

A signature once, not on every reply

The first time a sender signs on a thread, the signature stays in stripped_text: it is where their name, role and number are. Once an earlier mail of theirs carries it, it is dropped.

Signatures
Opened the ticket09:40
Hi, The CSV export on the Reports page has failed three times today.
Thanks,Priya NairOperations lead, Lumen Health+44 20 7946 0321
kept
Answered Sam11:02
Hi Sam, answers below. > Which browser are you on?Edge, latest version.

…

Signature dropped: the ticket already has it.dropped

Forwards

A forward keeps what it forwards

A forward, or a reply to mail sent before the inbox was connected, answers nothing on file, so its quote is new to the thread. That quote is the content, so stripped_text keeps it and segments still marks it as quoted.

Forwards

Sam, this is the vendor thread I mentioned. Can you take it?

---------- Forwarded message ---------From: Marek Havel <marek@datagrid.cz>Date: Mon, 21 Sep 2026 at 16:02Subject: Export limitsTo: Priya Nair <priya@lumenhealth.com> Hi Priya, Exports over 25,000 rows are split into several files on our side. Marek
segmentsquotedstripped_textkept

Clients

The quote starts differently in every client

Attribution lines in English, German, French, Spanish, Italian, Dutch, Portuguese and more, wrapped or not. Outlook’s header block, forward separators, and the quote markup of Gmail, Outlook, Apple Mail, Yahoo and Thunderbird.

Clients
  • On Tue, 22 Sep 2026 at 10:14, Sam <support@mail.yourapp.com> wrote:English
  • Am 22.09.2026 um 10:14 schrieb Sam <support@mail.yourapp.com>:German
  • Le mar. 22 sept. 2026 à 10:14, Sam <support@mail.yourapp.com> a écrit :French
  • El mar, 22 sept 2026 a las 10:14, Sam (<support@mail.yourapp.com>) escribió:Spanish
  • Il giorno mar 22 set 2026 alle ore 10:14 Sam <support@mail.yourapp.com> ha scritto:Italian
  • Op di 22 sep 2026 om 10:14 schreef Sam <support@mail.yourapp.com>:Dutch
  • Von: Yourapp Support <support@mail.yourapp.com>Outlook, German
  • -------- Original message --------Separator
  • Sent from my iPhoneSignature

Compared

How replies usually get stripped

Every approach below reads one message and guesses where the quote begins. That works for the reply typed above the quote, which is most of them. It breaks on the reply people send to a list of questions.

ApproachWhat it readsWhere it stops
A regexThe text part, down to the first “On … wrote:” or “>”.Everything under that line goes, answers included. Every client and language needs a pattern of its own.
email_reply_parserGitHub’s Ruby plain-text parser and its Python, Node, Go and PHP ports: quote markers, “On … wrote:” (English only in the original), signature lines.Priya’s Outlook reply comes back as her opening and signature, the three answers gone. Answers between “>” lines survive without their questions.
talonMailgun’s Python library: plain text or HTML for quotes, and rules or a trained classifier for signatures.The same Outlook reply loses the same three answers. A reply answered between “>” lines comes back whole, quote and all.
Postmark StrippedTextReplyThe plain-text part of replies that carry In-Reply-To or References.Documented as English only, and not filled from an HTML-only reply.
Mailgun stripped-textThe text part with quoted parts and the signature block removed, with stripped-html and stripped-signature beside it.The fields are left out of the payload when the parse fails.
AI InbxThe client’s markup, then the quote markers, then the message being answered, when the thread has it.With nothing on file to compare against, it keeps the quote rather than guess. It reads mail that reaches AI Inbx, not a body you post to it.

Set up

Three fields on every email

1email.receivedthe reply, as a comment on the ticket
if (event.type === "email.received" && event.data.category === "human") {  const email =    event.data.email ?? (await aiinbx.emails.retrieve(event.data.email_id))  await tickets.comment(event.data.thread_id, email.stripped_text)}
2segmentsthe whole message, quote folded
for (const segment of email.segments) {  if (segment.kind === "quoted") view.fold(segment.text)  else view.show(segment.text)}
3stripped_htmlthe same cut, with its formatting
// null when there is no HTML part, or its markup could not be cutrender(email.stripped_html ?? email.html)

Questions

How do I extract only the latest reply from an email thread?

Read stripped_text on the email. It is the part the sender wrote in this message: the conversation their client quoted underneath is removed, and so is a signature the thread already has. If you want the quote too, segments returns the whole body cut into written, quoted and signature parts, in order.

Why does my regex miss replies from Outlook?

Outlook puts no > in front of quoted lines. It writes a From, Sent, To and Subject block and pastes the earlier message under it, so a parser cutting at that block also cuts any answer typed below it. AI Inbx compares those lines with the message being answered, when that message is on the thread, and keeps the ones that are new.

What happens to answers typed between the quoted lines?

They stay in stripped_text, in the order they were typed, each introduced by the quoted question or sentence above it, so it still reads as an answer. The rest of the quote is removed. In segments they are written parts sitting between quoted ones.

How do I remove the signature from an email?

stripped_text leaves it out once the thread already has it from that sender. Sign-offs, the RFC signature separator and lines like Sent from my iPhone mark where a signature starts. The first signature a sender uses on a thread is kept, because that is where their name, role and phone number are; segments marks it as signature either way.

Does it work for replies written in other languages?

Yes. Attribution lines such as Am … schrieb, Le … a écrit and El … escribió are recognised along with the English one, and so are translated Outlook headers like Von and Gesendet. Answers typed into an unmarked quote are found by comparing words with the message being answered, so they are found in any language that puts spaces between words.

Can I post an email body and get the reply back?

No. There is no standalone parse call: the cut is made on mail that reaches AI Inbx, received on your domain or in a connected Gmail or Outlook mailbox, and on mail you send through it. Every email read in full, from GET /emails/{id} or a full webhook payload, then carries text, html, stripped_text, stripped_html and segments.

What if the message being answered was never on file?

Then the quote is kept in stripped_text, because nothing you hold has it: a forward, or a reply to mail sent before the mailbox was connected. segments still marks it as quoted, so you can fold it yourself.

Give your product an inbox. The hard parts are already handled.

Get started