> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://agentinbox.space/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://agentinbox.space/_mcp/server.

# Извлечение ответов из писем с Talon

> Как извлекать новое содержимое из ответов в треде, отрезая цитаты, с точностью около 93.8%.

## Зачем Talon?

В переписке накапливаются цитаты, которые заслоняют новый текст. В автоматической обработке почты нужен только новый фрагмент, а не вся история.

**Talon** выделяет чистый ответ за счёт сопоставления шаблонов и разбора структуры HTML/текста.

### Сценарии

* **AI-агенты почты:** новые реплики пользователя без полного треда
* **Автоматизация:** разбор ответов на предмет действий
* **Анализ тредов:** вклад каждого участника отдельно
* **Inbox:** обрабатывать только новую информацию в ответах

### Почему Talon

#### HTML из клиентов

Gmail, Outlook, Apple Mail, Thunderbird и др.

#### Высокая точность

93.8% на 64 реальных тестах

#### Несколько языков

Английский, японский, шведский, польский, голландский, немецкий

#### Скорость

\~1.92 ms в среднем, \~488 писем/с

---

## Как устроен Talon

Два подхода в зависимости от формата письма.

### Текст (конвейер из 6 этапов)

1. **Классификация строк:** метки `'t'` текст, `'m'` цитата, `'s'` разделитель, `'e'` пустая
2. **Шаблоны:** regex по последовательностям меток
3. **Извлечение:** удаление цитат, остаётся новый текст

Распознаётся:

* префиксы `>`
* заголовки ответов («On \[date] \[name] wrote:»)
* пересылки («-----Original Message-----»)

### HTML (8 этапов)

1. **Структурное удаление:** известные блоки цитат (Gmail, blockquote, Outlook)
2. **Запасной путь:** нестандартный HTML → строки → те же текстовые правила → вырезание в HTML

### Режим

**Удаление цитат** (основной)

* убирает процитированные ответы из треда
* без отдельной инициализации
* правила и шаблоны

---

## Быстрый старт

#### Установка Talon

Через pip; для Python 3.11+ нужен обходной путь (см. следующий шаг):

```bash
pip install talon
```

#### Обход для Python 3.11+

Замена зависимости cchardet:

```python
# Import workaround BEFORE importing talon
import sys
import chardet
sys.modules['cchardet'] = chardet

# Now safe to import talon
import talon
from talon import quotations
```

> **Warn**
>
> Без этого обхода на Python 3.11+ установка/импорт могут ломаться.

#### Извлечь ответ

Текст и HTML:

**`Plain Text`**

```python title="Plain Text"
from talon import quotations

email = """Great work on the project!

On Mon, Apr 11, 2011 at 6:54 PM, Bob wrote:
> Can you review the document?
> Need feedback by Friday.
"""

clean_reply = quotations.extract_from_plain(email)
# Result: "Great work on the project!"
```

**`HTML`**

```python title="HTML"
from talon import quotations

html_email = """
<html><body>
<div>Thanks for the update!</div>
<div class="gmail_quote">
  <div>On Mon, Alice wrote:</div>
  <blockquote>Original message here</blockquote>
</div>
</body></html>
"""

clean_html = quotations.extract_from_html(html_email)
# Returns: <html><body><div>Thanks for the update!</div></body></html>
```

---

## Производительность и точность

Тесты на 64 реальных письмах из разных клиентов и языков.

### Сводка

| Метрика                    | Значение           |
| -------------------------- | ------------------ |
| **Всего тестов**           | 64 письма          |
| **Успех**                  | 60 (93.8%)         |
| **Провал**                 | 4 (6.2%)           |
| **Среднее время**          | 1.92 ms            |
| **Пропускная способность** | 488.6 писем/с      |
| **Мин / макс**             | 0.13 ms – 21.55 ms |

### Покрытие

* **22 HTML:** Gmail, Outlook, Apple Mail, Thunderbird, Mail.ru, Hotmail
* **42 plain text:** разные форматы ответов
* **6+ языков:** английский, японский, шведский, польский, голландский, немецкий
* **Мобильные клиенты:** iPhone, Android, подписи «Sent from»

### Время по сложности

| Тип письма              | Среднее время | Сложность |
| ----------------------- | ------------- | --------- |
| Простой текстовый ответ | 0.2–0.5 ms    | Низкая    |
| HTML Gmail/Outlook      | 2–4 ms        | Средняя   |
| Сложные треды           | 4–22 ms       | Высокая   |

### Скорость и точность

| Библиотека | Среднее время | Точность | Когда                           |
| ---------- | ------------- | -------- | ------------------------------- |
| **Talon**  | 1.92 ms       | 93.8%    | Продакшен с HTML                |
| quotequail | 0.96 ms       | \~85%    | Умеренные требования            |
| Свой regex | 0.1 ms        | \~70%    | Только текст, критична скорость |

**Вывод:** \~2 ms в среднем для бэкенда обычно пренебрежимо мало; даже \~21 ms быстрее типичного сетевого запроса.

---

## Ограничения

4 из 64 тестов не прошли. Ниже разбор.

#### Провалившиеся кейсы (4)

### Кейс 1: сложный тред со смешанным содержимым

**Вход**:

```text
Thank you, Sonya Johnson.

I have sent an invite for 10:30am Monday PDT (today). I
hope you can join.

Regards,

Christopher Edwards


On Mon, Jun 3, 2024 at 12:53 AM Cody Hart <omerritt@example.com> wrote:

> Hi Christopher Edwards,
>
> 10.30 AM pacific is good for me.
>
> Thanks & Regards,
>
> Cody Hart
```

**Ожидалось:** только первые 5 строк (до `Christopher Edwards`)

**Фактически:** весь текст, включая цитату с «On Mon, Jun 3...» и строки `>`

**Время:** 2.55 ms

**Причина:** подпись перед цитатой сбивает эвристики

---

### Кейс 2: встроенные ответы внутри цитаты

**Вход**:

```text
On Tue, Apr 29, 2014 at 4:22 PM, Example Dev <sugar@example.com> wrote:

> okay. Well, here's some stuff I can write.
>
> And if I write a 2 second line you and maybe reply under this?
>
> Or if you didn't really feel like it, you could reply under this line.

I will reply under this one

>
> okay?
>

and under this.

>
> -- Tim
```

**Ожидалось:** только `I will reply under this one` и `and under this.`

**Фактически:** весь фрагмент, включая заголовок «On Tue, Apr 29...» и цитаты

**Время:** 0.48 ms

**Причина:** встроенные ответы между строками `>` не распознаны как новый текст

---

### Кейс 3: пересылка Gmail (HTML)

**Вход**:

```html
<html><head></head><body><div dir="ltr">test<div><br /></div><div>blah</div>
<div><br /><div class="gmail_quote">---------- Forwarded message ----------<br />
From: <b class="gmail_sendername">Foo Bar</b>
<span dir="ltr">&lt;<a href="mailto:foo@bar.example">foo@bar.example</a>&gt;</span><br />
Date: Thu, Mar 24, 2016 at 5:17 PM<br />
Subject: The Subject<br />
To: John Doe &lt;<a href="mailto:john@doe.example">john@doe.example</a>&gt;<br />
<br /><br /><div dir="ltr">Some text<div><br /></div><div><br /></div></div>
</div><br /></div></div></body></html>
```

**Ожидалось:** только `testblah` (до маркера пересылки)

**Фактически:** остаётся «---------- Forwarded message ----------» и тело пересылки

**Время:** 3.41 ms

**Причина:** HTML-заголовки пересылки Gmail не вырезаются как цитата

---

### Кейс 4: пересылка Thunderbird (HTML)

**Вход**:

```html
<html><body bgcolor="#FFFFFF" text="#000000">
<p><br /></p>
<div class="moz-forward-container"><br /><br />
-------- Forwarded Message --------
<table class="moz-email-headers-table">
  <tbody>
    <tr><th>Subject:</th><td>Re: Example subject</td></tr>
    <tr><th>Date:</th><td>Tue, 3 May 2016 14:54:27 +0200 (CEST)</td></tr>
    <tr><th>From:</th><td>John Doe &lt;johndoe@example.com&gt;</td></tr>
  </tbody>
</table>
<br /><br />
<div>Dear John,</div>
<div><br /></div>
<div>This is a test.</div>
</div></body></html>
```

**Ожидалось:** пусто (только пересылка, без нового текста)

**Фактически:** остаётся «-------- Forwarded Message --------» и пересылаемое содержимое

**Время:** 4.34 ms

**Причина:** класс Thunderbird `moz-forward-container` не распознан

---

**Итог:** 3 из 4 провалов — пересылки. Обычные ответы — точность 98%+.

#### Успешные примеры

### Пример 1: простой ответ Gmail

**Вход**:

```text
Awesome! I haven't had another problem with it.

On Aug 22, 2011, at 7:37 PM, defunkt<reply@reply.github.com> wrote:




> Loader seems to be working well.
```

**Результат Talon:** `Awesome! I haven't had another problem with it.`

**Время:** 0.2 ms

**Почему сработало:** шаблон «On \[date] \[name] wrote:» и маркеры `>`

---

### Пример 2: Outlook с линией-разделителем

**Вход**:

```text
Outlook with a reply directly above line
________________________________________
From: CRM Comments [crm-comment@example.com]
Sent: Friday, 23 March 2012 5:08 p.m.
To: John S. Greene
Subject: [contact:106] John Greene

A new comment has been added to the Contact named 'John Greene':

I am replying to a comment.
```

**Результат:** `Outlook with a reply directly above line`

**Время:** 0.51 ms

**Почему:** линия подчёркиваний и заголовки From/Sent как разделитель

---

### Пример 3: HTML Outlook

**Вход**:

```html
<html>
  <body>
    <div>Reply</div>
    <span id="OLK_SRC_BODY_SECTION">
      <div>
        <span>From: </span>Bob &lt;<a href="mailto:bob@example.com">bob@example.com</a>&gt;<br />
        <span>Date: </span>Tue, 01 Nov 2011 18:54:39 -0700<br />
        <span>To: </span>Rob &lt;<a href="mailto:rob@example.com">rob@example.com</a>&gt;<br />
        <span>Subject: </span>Test<br />
      </div>
      <div>Hi</div>
    </span>
  </body>
</html>
```

**Результат:** `Reply`

**Время:** 4.02 ms

**Почему:** удалён блок Outlook `OLK_SRC_BODY_SECTION`

#### Talon и более простые библиотеки

Talon тяжелее, но покрывает HTML и сложные кейсы.

* Talon: \~1.92 ms (с HTML)
* email-reply-parser: \~0.03 ms (в основном текст)

Для сервера задержка Talon обычно мала по сравнению с сетью.

#### Пересылки

Пересылки, особенно HTML, — слабое место:

* Текстовые пересылки часто ок
* HTML может оставлять заголовки пересылки
* Обходной путь: извлечение из plain text или постобработка маркеров forward

---

### Обработка ошибок

Оборачивайте разбор в try/except:

```python
from talon import quotations

def safe_extract(email_body, is_html=False):
    try:
        if is_html:
            return quotations.extract_from_html(email_body)
        else:
            return quotations.extract_from_plain(email_body)
    except Exception as e:
        # Fallback: вернуть исходное тело
        print(f"Talon extraction failed: {e}")
        return email_body
```

### Тестирование

Проверяйте на своих реальных форматах:

```python
# Create a test suite with your actual email patterns (Gmail, Outlook, Apple Mail)
test_emails = [
    "path/to/gmail_reply.html",
    "path/to/outlook_reply.txt",
    "path/to/forward.html"
]

for email_file in test_emails:
    with open(email_file) as f:
        content = f.read()
        result = quotations.extract_from(content)
        print(f"{email_file}: {len(result)} chars extracted")
```

> **Tip**
>
> Прогоняйте реальные письма из тех клиентов, что у ваших пользователей: уникальные шаблоны бывают вне обучающей выборки Talon.

---

## Вариант на JavaScript

Для TypeScript/JavaScript — **[TalonJS](https://github.com/quentez/talonjs)** (порт Talon).

### Сравнение

| Решение          | Точность | Скорость | Когда                 |
| ---------------- | -------- | -------- | --------------------- |
| **Python Talon** | 93.8%    | 1.92 ms  | Максимальная точность |
| **TalonJS**      | 90.6%    | 1.88 ms  | Node/TS без Python    |

TalonJS чуть быстрее в бенчмарке и удобен в JS-стеке.

### Быстрый старт

#### Установка TalonJS

```bash
npm install talonjs
```

#### Извлечение ответов

**`Plain Text`**

```typescript title="Plain Text"
import * as talon from 'talonjs';

const email = `Great work on the project!

On Mon, Apr 11, 2011 at 6:54 PM, Bob wrote:
> Can you review the document?
> Need feedback by Friday.
`;

const result = talon.quotations.extractFromPlain(email);
const cleanReply = result.body.trim();
// Output: "Great work on the project!"
```

**`HTML`**

```typescript title="HTML"
import * as talon from 'talonjs';

const htmlEmail = `
  <div>Thanks for the update!</div>
  <div class="gmail_quote">
    On Mon, Alice wrote: <blockquote>Original</blockquote>
  </div>
`;

const result = talon.quotations.extractFromHtml(htmlEmail);
const cleanReply = result.body.trim();
// Returns: "<div>Thanks for the update!</div>"
// Note: TalonJS returns clean HTML, not plain text
```

> **Tip**
>
> **TalonJS или Python Talon:**
>
> * **TalonJS** — если стек TS/JS и достаточно \~90.6% точности
> * **Python Talon** — если нужна максимальная точность или уже Python
> * Разница \~3 п.п. для многих сценариев приемлема