Reply & Attachment Extraction
Reply & Attachment Extraction
Every reply carries the conversation before it: an “On Tuesday, Priya wrote:” line, the quoted history, a “Sent from my iPhone” line, an unsubscribe footer. If you pass text straight to an LLM, your agent pays for that history on every turn and can mistake an old quoted request for a new one.
AgentMail does this extraction for you. Every message has extracted_text and extracted_html alongside the raw text and html. Every attachment with extractable text has a text_url. You don’t need Talon, email-reply-parser, or any other parsing library.
Reply extraction
AgentMail computes extracted_text and extracted_html when it stores a message, for received and sent messages alike. They are returned wherever the message body is:
Given this plain-text reply:
extracted_text is:
Read the extracted field first, and fall back to the full body when it’s absent:
To stay within delivery size limits, events for larger messages leave out the body fields, including extracted_text and extracted_html. WebSocket events reach that limit sooner than webhooks. If the fields are missing from an event, call Get Message.
What gets removed
- Quoted history. “On … wrote:” lines in English and many other languages, including French, Spanish, German, Portuguese, Italian, Dutch, Polish, Russian, Chinese, and Arabic. Also
>quoted lines, pastedFrom:/Sent:/To:/Subject:header blocks,-----Original Message-----dividers, and the quote markup that Gmail, Outlook, and Apple Mail add to HTML replies. - Trailing boilerplate. “Sent from my iPhone” and “Get Outlook for iOS” lines, unsubscribe and “manage preferences” footers, “view in browser” links, confidentiality notices, and legal disclaimers. Extraction cuts at the first such line, so everything below it is removed too.
The sender’s own signature is kept, including a -- signature that their email client placed below the quoted history.
Messages that are kept whole
Some messages contain quoted text that your agent needs, so extraction keeps them whole:
- Bounces, in both
extracted_textandextracted_html. Delivery failure notices quote your original message back, and that copy shows which message failed. - Inline replies, in
extracted_text. When the sender answers between quoted lines, cutting at the first quote would lose their answers.extracted_htmlstill cuts at the first quote, so preferextracted_textwhen you pass content to a model.
Don’t rely on extraction to keep forwarded content. Depending on the sender’s email client, extracted_text and extracted_html can drop the forwarded email and keep only the note above it. When your agent processes forwarded mail, read text or html.
When to use text and html instead
- The extracted field is absent. A message with no HTML part has no
extracted_html, and event payloads for large messages leave out body fields. Fall back to the full body, as in the example above. - You need the original. Use
textorhtmlto archive a message, to show it to a person, or when the quoted context matters to the task. - The result looks wrong. Extraction is rule-based. An unusual layout can occasionally leave quoted text in, or remove content that follows a line that looks like boilerplate.
Building LLM context from a thread
Get Thread returns every message with its extracted content, so you can build a compact transcript without resending quoted history on every turn. Within a page, messages are ordered oldest to newest. The first page holds the newest messages, and next_page_token fetches older ones.
Token budgeting is up to you. For long threads, keep the most recent messages in full and summarize or drop older ones before sending the transcript to your model.
Attachment text extraction
AgentMail also extracts plain text from attachments, so your agent can read a PDF invoice or a spreadsheet without running a document parser. Get Attachment returns text_url, a signed URL for the extracted text, alongside download_url for the original file. Both expire at expires_at, so fetch a fresh attachment response when you need the URLs again rather than storing them.
Files larger than 10 MB are not extracted, and extracted text is cut off at 250,000 characters.
The thread-level Get Attachment endpoint returns text_url too.
Attachment text is extracted right after the message is stored, so a request made the moment a message.received event arrives can come back without text_url. When text_url is absent, the file is unsupported, has no text, or hasn’t finished extracting. Use download_url if you need the file right away.
Run the extractor yourself
The reply extractor that produces extracted_text and extracted_html is open source: agentextract on npm, under the MIT license. Use it to process mail that doesn’t come through AgentMail, or to check how a message will be extracted. It’s a TypeScript package built on pattern matching, with no ML model or DOM parser.
The package also exports extractAttachment for attachment text. Its README includes a benchmark against Talon and TalonJS.
If you followed our earlier guide to running Talon, you can remove it: extracted_text and extracted_html are already on every message.
