Электронная почта выглядит как простой ввод, но в реальной автоматизации ведет себя как ненадежный поток событий: повторы, дубликаты, причуды кодировки, многочастные тела сообщений и непоследовательные заголовки. Если вы передаете входящую почту в LLM-агент, систему QA или пайплайн данных, “чистые email” — это не красивое форматирование. Это дедупликация, детерминированная нормализация и хранение с сохранением происхождения.
Это руководство описывает практический дизайн пайплайна, который превращает входящую почту в стабильные, запрашиваемые записи, которым можно доверять, без хрупкого парсинга HTML или угадывания с “sleep(10)”.
Что означают “чистые email” в пайплайне
Для работы пайплайна “чистая” запись email обычно имеет следующие свойства:
- Стабильные идентификаторы: вы можете последовательно ссылаться на “это сообщение” при повторах вебхуков, циклах опроса и переобработке.
- Нормализованная структура: заголовки, адреса, тела сообщений и вложения представлены предсказуемыми типами и кодировками.
- Четкая линия происхождения: вы всегда можете проследить производное поле (например, OTP) до исходного сообщения и точной логики извлечения.
- Идемпотентный прием: пайплайн может безопасно обрабатывать доставку “по крайней мере один раз”.
- Безопасное потребление агентами: LLM видят минимизированное, обезвреженное представление, а не сырой HTML и недоверенные заголовки.
Полезная ментальная модель — рассматривать прием email как поток кликов или платежные события: вам нужен лог только для добавления, каноническое нормализованное представление и производные таблицы для быстрого потребления.
Шаг 1: Правильная дедупликация (сообщение, доставка, артефакт)
Email-пайплайны часто терпят неудачу, потому что команды дедуплицируют на неправильном уровне.
Три уровня дедупликации
Дедупликация доставки (транспортный уровень)
Одно и то же сообщение может быть доставлено несколько раз из-за повторов SMTP, greylisting, повторов вебхуков или гонок опроса.
Дедупликация сообщений (идентичность содержимого)
Две доставки могут представлять одно и то же логическое сообщение. Вам нужна одна каноническая запись.
Дедупликация артефактов (то, что вам действительно нужно)
В процессах верификации “то, на что вы действуете” часто является OTP или магической ссылкой. Вы хотите потребить артефакт один раз, даже если получили сообщение несколько раз.
Ключи дедупликации, которые действительно работают
Ни одно поле не является универсально надежным. Используйте многоуровневую стратегию и сохраняйте всех кандидатов.
| Уровень | Цель | Хорошие кандидаты для ключей дедупликации | Примечания |
|---|---|---|---|
| Доставка | Не обрабатывать одну и ту же доставку дважды |
provider_delivery_id (если доступен), id события вебхука, (inbox_id, message_id, delivered_at)
|
Вебхуки обычно работают по принципу “по крайней мере один раз”, поэтому нужно предполагать дубликаты. |
| Сообщение | Одна строка на логический email | RFC Message-ID (нормализованный), хеш сырого источника, (inbox_id, internal_message_id)
|
Message-ID может отсутствовать или дублироваться в реальности, держите запасной вариант. |
| Артефакт | Семантика “потребить один раз” | sha256(artifact_type + canonical_value + context) |
Лучший вариант для OTP и URL верификации. |
Практический алгоритм дедупликации
Используйте детерминированную последовательность:
-
Если ваш провайдер дает стабильный внутренний
message_id, используйте его как первичный ключ внутри inbox. - Сохраните RFC
Message-ID(нормализованный) и хеш содержимого (например, хеш сырого источника или канонизированного подмножества). - Выполните upsert канонической записи сообщения по первичному ключу и запишите каждое событие доставки в отдельную таблицу.
- При извлечении артефактов вычислите
artifact_hashи примените ограничение уникальности для гарантии потребления один раз.
Это основа идемпотентности: вы принимаете дубликаты, но состояние вашей базы данных остается корректным.
Шаг 2: Нормализация email в детерминированную форму
Нормализация — это место, где скрывается большинство “болезней пайплайна”. Цель не в том, чтобы идеально смоделировать каждый угол MIME, а в том, чтобы создать стабильный контракт для автоматизации.
Нормализация адресов без нарушения крайних случаев
Распространенные ошибки:
- Приведение всего адреса к нижнему регистру, что может быть неправильным для некоторых локальных частей.
- Рассмотрение отображаемых имен как надежных идентификаторов.
- Парсинг адресов с помощью регулярных выражений.
Предпочтите библиотеку парсинга почты и нормализуйте консервативно:
- Приводите к нижнему регистру только домен.
- Сохраняйте локальную часть как получено.
- Сохраняйте как разобранную структуру, так и исходную строку.
Прагматичный объект нормализованного адреса выглядит так:
| Поле | Тип | Пример |
|---|---|---|
original |
string | "Jane Doe" <[email protected]> |
address |
string | [email protected] |
local |
string | Jane.Doe+qa |
domain |
string | example.com |
display_name |
string или null | Jane Doe |
Нормализация заголовков с моделью доверия
Заголовки — это ввод, контролируемый атакующим. Хорошее нормализованное представление:
- Сохраняет сырой блок заголовков (для криминалистической отладки).
- Создает разобранную карту, которая обрабатывает сложенные строки и дублирующиеся заголовки.
- Разделяет поля “высокого доверия для дедупликации/трассировки” (как
Message-ID) от “полей UI низкого доверия” (какSubject).
Если вы хотите получить представление о том, насколько запутанным может быть сырой email, просмотрите основной формат в RFC 5322.
Нормализация тел для автоматизации (сначала текст)
Для пайплайнов и LLM-агентов:
- Предпочитайте
text/plain, когда доступно. - Сохраняйте HTML, но не делайте вашу автоматизацию зависимой от хрупких HTML-селекторов.
- Рассмотрите создание поля “безопасного текста” путем удаления пикселей отслеживания, сжатия пробелов и ограничения длины.
Нормализация временных меток с намерением
Email содержит несколько временных меток:
- Заголовок
Date:: предоставляемый отправителем, может быть неправильным. - Транспортные временные метки: время получения вашего провайдера, обычно самое надежное.
Сохраняйте как минимум:
-
received_at(время получения провайдером, каноническое для упорядочивания) -
date_header(опционально, для отображения или диагностики)
Нормализация вложений как метаданные + указатель содержимого
Не сбрасывайте вложения в логи или промпты агентов.
Дружественная к хранению модель:
- Сохраняйте метаданные вложений (имя файла, content-type, размер).
- Сохраняйте хеш для целостности.
- Сохраняйте байты в объектном хранилище, ссылаясь по ключу.
Шаг 3: Хранение для переобработки, а не только для “счастливого пути”
Пайплайн, который нельзя воспроизвести — это пайплайн, которому нельзя доверять.
Рекомендуемые уровни хранения
Большинство команд в итоге получают три уровня:
- Сырые: исходный источник RFC 5322 (или сырая полезная нагрузка провайдера), неизменяемый.
- Нормализованные: каноническое JSON-представление, используемое нижестоящими системами.
- Производные: артефакты, извлеченные для конкретных рабочих процессов, такие как OTP, URL верификации, ID тикетов.
Эта структура упрощает повторный запуск нормализации или извлечения при изменении шаблонов.
Минимальная реляционная схема
Вот практическая базовая схема (работает в Postgres, MySQL и т.д.):
| Таблица | Назначение | Ключевые колонки |
|---|---|---|
email_messages |
Одна строка на логическое сообщение |
pk, inbox_id, provider_message_id, rfc_message_id, received_at, normalized_json, raw_ref
|
email_deliveries |
Каждая попытка доставки / событие |
pk, message_pk, delivered_at, source (webhook/poll), event_id
|
email_artifacts |
Записи производных для одноразового потребления |
pk, message_pk, artifact_type, artifact_value, artifact_hash (уникальный), extracted_at
|
Две важные операционные заметки:
- Поставьте ограничение уникальности на
(inbox_id, provider_message_id)или ваш выбранный первичный ключ сообщения. - Поставьте ограничение уникальности на
artifact_hashдля семантики одноразового потребления.
Сохранение и конфиденциальность по дизайну
Email может содержать секреты и персональные данные. Даже в QA команды случайно направляют похожий на продакшн контент в тестовые inbox.
Рассматривайте сохранение как первоклассную часть “чистых email”:
- Сохраняйте сырые данные минимальное окно, необходимое для отладки и воспроизведения.
- Редактируйте или токенизируйте чувствительные поля в логах.
- Шифруйте в покое, если храните сырой контент.
Шаг 4: Надежный прием (сначала вебхуки, опрос как резерв)
Даже “идеальная нормализация” терпит неудачу, если прием нестабилен.
Надежный паттерн:
- Сначала вебхуки для событий с низкой задержкой.
- Опрос как резерв для устойчивости, когда вебхуки не работают, очереди забиваются или ваша конечная точка недоступна.
Доставка вебхуков обычно работает по принципу “по крайней мере один раз”, поэтому ваш обработчик должен быть идемпотентным.
Псевдокод приема вебхуков (идемпотентный)
def handle_webhook(event):
verify_signature(event) # отклонить поддельные или повторные запросы
msg = event["message"]
inbox_id = msg["inbox_id"]
provider_message_id = msg["id"] # стабильный id провайдера (пример)
# 1) Upsert сообщения (идемпотентно)
message_pk = upsert_email_message(
inbox_id=inbox_id,
provider_message_id=provider_message_id,
rfc_message_id=normalize_message_id(msg.get("headers", {}).get("message-id")),
received_at=msg["received_at"],
normalized_json=msg,
raw_ref=msg.get("raw_ref"),
)
# 2) Записать событие доставки (только добавление)
insert_delivery_event(
message_pk=message_pk,
event_id=event["event_id"],
delivered_at=event["delivered_at"],
source="webhook",
)
# 3) Извлечь артефакты (потребить один раз)
for artifact in extract_artifacts(msg):
insert_artifact_if_new(message_pk, artifact)
Эта структура означает, что повторы вебхуков не создают дубликаты, и извлечение остается безопасным.
Пакетная обработка для пропускной способности
Если вы принимаете большой объем (CI-флоты, много запусков агентов или обратные заливки), API пакетов имеют значение. Пакетный прием позволяет вам:
- Уменьшить накладные расходы на сообщение.
- Применить последовательное противодавление.
- Повторно запускать задания извлечения на срезе сообщений.
Шаг 5: Создание “LLM-безопасного представления” email
LLM — мощные потребители, но email — это недоверенный ввод и распространенный вектор prompt-инъекций. “Чистые email” для агентов означают предоставление минимизированного контракта.
Типичное представление, ориентированное на агента:
-
message_id,inbox_id,received_at -
from,to(разобранные адреса) -
subject(опционально) -
text(только обычный текст, с ограничением длины) -
artifacts(уже извлеченные OTP или URL из разрешенного списка)
Держите сырой HTML и полные заголовки вне контекста агента, если у вас нет очень конкретной причины.

Где Mailhook вписывается в пайплайн чистых email
Если вы создаете автоматизацию вокруг одноразовых inbox (для LLM-агентов, QA или процессов верификации), Mailhook предоставляет примитивы, которые хорошо соответствуют приведенному выше пайплайну:
- Создавайте одноразовые inbox через API.
- Получайте email как структурированный JSON.
- Доставляйте события через вебхуки реального времени.
- Используйте опрос как резервный механизм получения.
- Проверяйте подписанные полезные нагрузки для безопасности вебхуков.
- Обрабатывайте сообщения пакетами.
- Выбирайте общие домены или приносите собственный домен.
Для точных полей запроса/ответа и канонического контракта интеграции используйте машиночитаемую справку Mailhook: llms.txt. Вы также можете начать с основного сайта Mailhook.
Финальный чек-лист для “чистых email”
Если вы реализуете только несколько вещей, сделайте их этими:
- Дедуплицируйте по дизайну: разделяйте события доставки от канонических сообщений и применяйте ограничения уникальности.
- Нормализуйте детерминированно: консервативная нормализация адресов, разобранные заголовки с обработанными дубликатами, тела с приоритетом текста.
- Сохраняйте для воспроизведения: сохраняйте сырые данные (кратко) плюс нормализованный JSON и выводите артефакты в таблицу одноразового потребления.
- Предполагайте “по крайней мере один раз”: обработчики вебхуков должны быть идемпотентными.
- Держите агентов на поводке: давайте LLM минимизированное представление email и извлеченные артефакты, а не сырой HTML.
Чистые email — это не просто более красивые данные, это разница между пайплайнами, которые вы можете масштабировать, и пайплайнами, за которыми вы следите.