Темы писем с ИИ: что считать вместо открытий

Как создавать темы писем с ИИ и оценивать клики вместо открытий: полный учебный журнал, исключение машинного клика и границы сравнения двух отправок.

Темы писем с ИИ обсуждают чаще всего там, где спорят об open rate. При включённой защите почты Apple письмо может загружать удалённый контент в фоне при получении, а не в момент просмотра Protect email privacy in Mail on Mac. Значит, загрузка пикселя — событие доставки контента, а не подтверждённое чтение. Ниже — как готовить варианты темы и оценивать наблюдаемые отправки, не превращая счётчик открытий в доказательство интереса.

Сразу оговорюсь о статусе материала. Учебный пример ниже полностью вымышлен: это не клиентский кейс и не выполненный тест нейросети или почтового сервиса. Генерация тем через ИИ описана как приём, а не как проверенный результат. Все числа получены из приведённого журнала на 12 строк, и ни одно из них не подтверждает превосходство одной темы над другой.

Уточните, что измерено

Open rate считают по загрузке пикселя. Apple описывает, что при включённой защите удалённый контент загружается в фоне при получении сообщения Protect email privacy in Mail on Mac. Для метрики это означает: пиксель мог сработать без того, чтобы человек открыл и прочитал письмо.

Из этого не следует, что защита включена у всех получателей или что каждый пиксель всегда загружается. Описание Apple говорит об одном режиме работы, а не о доле аудитории. Поэтому в журнале ниже открытие называется raw-open — загрузка пикселя, и не приравнивается к чтению.

Разведите четыре разных события: raw-open (загрузка пикселя), подтверждённое чтение (его в наборе нет), уникальный клик по ссылке и целевое действие вроде заявки или покупки. Клик ближе к интересу, чем загрузка картинки, но и он не гарантирует человека. Считать клики к открытиям нельзя: у них разные знаменатели и разные смыслы.

Передайте полный журнал и правило темы

Журнал состоит из двух отправок по 6 получателей. Это учебные строки с вымышленными ID, без реальных адресов и URL.

id send_id delivery raw_open click_events known_machine_click window_mature
A1 A delivered true 2 false true
A2 A delivered true 1 true true
A3 A delivered true 1 false true
A4 A delivered true 0 false true
A5 A bounced false 0 false true
A6 A unknown false 0 false true
B1 B delivered true 1 false true
B2 B delivered true 0 false true
B3 B delivered false 0 false true
B4 B delivered false 0 false true
B5 B bounced false 0 false true
B6 B unknown false 0 false true

Правила чтения журнала:

  • Доли считать только среди delivery=delivered. Bounced и unknown показывать отдельно, unknown не означает ни подтверждённую доставку, ни подтверждённый отказ.
  • raw-open — событие загрузки пикселя, а не подтверждённое чтение.
  • raw_unique_clicks — получатели со статусом delivered и click_events > 0. adjusted_unique_clicks дополнительно исключает строки с known_machine_click=true. Отсутствие такой метки не доказывает, что клик человеческий.
  • Не делить клики на открытия. При нулевом знаменателе результат — null, а не 0%.
  • Без случайного назначения и заранее согласованного плана не объявлять тему причинным победителем.
  • Темы создавать только по бизнес-факту. Данных о заявках и продажах нет, conversion_rate = null.

Бизнес-факт для обеих тем: «В отчёт добавлена колонка «Источник». Иные свойства, польза, сроки и цены неизвестны.» Исходные темы: A — «В отчёте появилась колонка «Источник»»; B — «Новая колонка отчёта: «Источник»».

Условия отправок: A ушла 2026-10-01 в 09:00 +03:00 по списку A, B — 2026-10-08 в 09:00 +03:00 по другому списку B. Рандомизации нет. Тело, CTA и определение событий в учебном условии одинаковые, но разные списки и даты причинную сопоставимость не обеспечивают. Окно — первые 24 часа после delivery_at, строки уже собраны на зрелом окне. Каждый id — отдельный получатель в данной отправке; повторные click_events число получателей не увеличивают.

Скопируйте запрос

Промпт ниже самодостаточен: в нём есть задача, данные, правила, нулевой контроль и схема ответа. Его можно передать модели вместе с журналом, но ничего не отправляйте и не запускайте рассылку по результату.

Задача: по всем переданным inputs создай 2 новых кандидата тем без новых фактов, затем по rows посчитай A/B по rules: sent/delivered/bounced/unknown, raw_open, raw_unique_clicks, известные исключения, adjusted_click_rate. Верни основания исключений с ID и причинный decision. human_read_count / human_click_count / conversion_rate = null. Отдельно рассмотри контроль с нулём доставок. Ничего не отправляй.

Данные:
fictional: true
business_fact: "В отчёт добавлена колонка «Источник». Иные свойства, польза, сроки и цены неизвестны."
sent_subjects:
  A: "В отчёте появилась колонка «Источник»"
  B: "Новая колонка отчёта: «Источник»"
sends:
  A: {at: "2026-10-01T09:00:00+03:00", cohort: "Список A"}
  B: {at: "2026-10-08T09:00:00+03:00", cohort: "Другой список B"}
randomization: false
same_body: "Учебное условие: одинаковое тело, CTA и определение событий. Списки и даты разные, причинная сопоставимость не установлена."
window: "Первые 24 часа после delivery_at, строки уже собраны на полном зрелом окне. Каждый id — отдельный получатель в данной отправке; повторные click_events не увеличивают число получателей."
rows:
  - {id: "A1", send_id: "A", delivery: "delivered", raw_open: true, click_events: 2, known_machine_click: false, window_mature: true}
  - {id: "A2", send_id: "A", delivery: "delivered", raw_open: true, click_events: 1, known_machine_click: true, window_mature: true}
  - {id: "A3", send_id: "A", delivery: "delivered", raw_open: true, click_events: 1, known_machine_click: false, window_mature: true}
  - {id: "A4", send_id: "A", delivery: "delivered", raw_open: true, click_events: 0, known_machine_click: false, window_mature: true}
  - {id: "A5", send_id: "A", delivery: "bounced", raw_open: false, click_events: 0, known_machine_click: false, window_mature: true}
  - {id: "A6", send_id: "A", delivery: "unknown", raw_open: false, click_events: 0, known_machine_click: false, window_mature: true}
  - {id: "B1", send_id: "B", delivery: "delivered", raw_open: true, click_events: 1, known_machine_click: false, window_mature: true}
  - {id: "B2", send_id: "B", delivery: "delivered", raw_open: true, click_events: 0, known_machine_click: false, window_mature: true}
  - {id: "B3", send_id: "B", delivery: "delivered", raw_open: false, click_events: 0, known_machine_click: false, window_mature: true}
  - {id: "B4", send_id: "B", delivery: "delivered", raw_open: false, click_events: 0, known_machine_click: false, window_mature: true}
  - {id: "B5", send_id: "B", delivery: "bounced", raw_open: false, click_events: 0, known_machine_click: false, window_mature: true}
  - {id: "B6", send_id: "B", delivery: "unknown", raw_open: false, click_events: 0, known_machine_click: false, window_mature: true}

Правила:
1. Доли считать только среди delivery=delivered; bounced и unknown показывать отдельно. unknown не означает подтверждённую доставку или подтверждённый недоставленный статус.
2. raw-open — событие загрузки пикселя, не подтверждённое чтение.
3. raw_unique_clicks — delivered с click_events>0; adjusted_unique_clicks дополнительно исключает known_machine_click=true. Отсутствие такой метки не доказывает человека.
4. Не делить клики на open. Нулевой знаменатель даёт null. Без случайного назначения и согласованного плана не объявлять причинного победителя тем.
5. Создать 2 новых кандидата тем только по business_fact. Не обещать эффект и не выполнять отправку.
6. Данных о заявках и продажах нет; conversion_rate = null.

Нулевой контроль: sent 1, delivered 0, clicks 0.

Схема ответа: JSON с полями new_subject_candidates, A, B, excluded_ids, decision, unknowns, zero_denominator_control. Все расчётные поля и знаменатели указывать явно.

Эталон ответа для сверки. Новые кандидаты: «Колонка «Источник» теперь в отчёте» и «В отчёте — новая колонка «Источник»». Обе опираются только на бизнес-факт и не добавляют выгод, сроков или цен.

A: sent 6, delivered 4, bounced 1, delivery_unknown 1, raw_opens 4, raw_open_rate 1.0, raw_unique_clicks 3, known_machine_excluded 1, adjusted_unique_clicks 2, adjusted_click_rate 0.5.

B: sent 6, delivered 4, bounced 1, delivery_unknown 1, raw_opens 2, raw_open_rate 0.5, raw_unique_clicks 1, known_machine_excluded 0, adjusted_unique_clicks 1, adjusted_click_rate 0.25.

Decision: описательно у A больше зарегистрированных кликов после заданного исключения, но причинный победитель темы неизвестен — разные даты и списки, рандомизации нет. human_read_count, human_click_count и conversion_rate — null. Нулевой контроль: sent 1, delivered 0, clicks 0, click_rate null, долю не рассчитывать.

Сверка расчёта руками: 12 строк — это 2×6, в каждой отправке 4 delivered, 1 bounced и 1 unknown. У A пиксель загрузился у A1, A2, A3 и A4 — 4 из 4 доставленных. Кликали A1, A2 и A3, то есть 3 уникальных получателя. A1 кликнул дважды, но это по-прежнему один получатель. A2 несёт известную машинную метку и выбывает, остаются 2 из 4. У B пиксель загрузился у B1 и B2 — 2 из 4, кликал один B1, машинных меток нет, итог 1 из 4.

Сверьте знаменатель и все клики

Начните с доставки. Доля считается только от delivered, поэтому у A и B знаменатель 4, а не 6. Один bounced и один unknown в каждой отправке остаются в отчёте отдельной строкой и в знаменатель не попадают. Если unknown записать в доставленные, изменится сам знаменатель выбранной доли; если приписать ему неподтверждённый отказ, пострадают счётчики статусов, но сами доли от этого не обязательно изменятся. Unknown остаётся unknown.

Дальше разберите клики по получателям, а не по событиям. A1 с двумя click_events даёт одного уникального кликнувшего. Сложение событий завысило бы число людей, поэтому в журнале и в расчёте считают уникальные ID. Для A выходит 3 уникальных кликнувших на 4 доставки.

Теперь исключите известный машинный клик. A2 имеет known_machine_click=true, и это единственная строка, которую правило убирает: 3 − 1 = 2 уникальных получателя из 4, то есть 0.5. У B исключать нечего: 1 из 4, то есть 0.25. A1 в исключения не попадает, его второй клик просто не добавляет нового получателя.

Открытия покажите рядом с кликами и не смешивайте. У A raw_open_rate 4/4 = 1.0, у B 2/4 = 0.5. Это загрузки пикселя, а не прочтения. Конверсии неизвестны: в журнале нет ни заявок, ни оплат, поэтому conversion_rate = null.

Отдельно проверьте нулевой знаменатель. Если отправлено одно письмо, доставленных ноль и кликов ноль, доля не равна 0% — она не определена, click_rate = null. Такой набор отбрасывают для любых выводов, а не заносят как нулевой результат.

Негативный контроль: утверждение «A выиграла: 100% людей прочитали письмо, каждый клик настоящий» отклоняется. Raw-open не равно чтению, у A есть известный машинный клик, отсутствие метки не подтверждает человека, а отправки неслучайные.

Не объявляйте победителя по несопоставимым отправкам

Сравнение двух отправок не позволяет назвать лучшую тему, когда различаются даты и списки, а случайного назначения не было. Описательно у A больше уникальных кликов после исключения, но разница может объясняться составом аудитории, днём отправки или случайностью набора из нескольких строк. Причинной связи между текстом темы и кликами этот журнал не устанавливает.

Есть и содержательная граница. Отсутствие метки known_machine_click не доказывает, что клик человеческий, а машинная метка в наборе — учебное условие, а не обещание, что фильтр почтового сервиса ловит роботов полностью. Поэтому human_click_count остаётся null: число кликов, которые точно сделали люди, из этих строк не выводится.

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

Если понадобится настоящий тест тем, нужен отдельный план: случайное назначение получателей по вариантам, одинаковые условия отправки, заранее зафиксированное окно, определение целевого события и правило остановки. Здесь такой план не составляется, размер выборки не рассчитывается и победитель не объявляется.

Практический порядок для ваших будущих отправок: зафиксируйте бизнес-факт и создайте 2–3 темы без обещаний, которых нет в факте; соберите журнал получателей со статусами доставки и окном; дедуплицируйте клики по получателям; отделите известные машинные строки и покажите их отдельно; считайте доли только от доставленных и оставляйте null там, где знаменатель неизвестен или нулевой. В документации GigaChat сказано, что при составлении запроса на письмо нужно указать, кому оно адресовано и о чём должно говориться Генерация текста с помощью ГигаЧат. Это рекомендация, а не обязательное требование провайдера и не проверенный тест модели. Как устроена генерация текстов письма, разобрано в материале Email-рассылка с нейросетью. Как свести такие журналы в общий отчёт без потери знаменателей — в разборе Анализ маркетинговых данных с нейросетью.

Валерий Курземнек

Автор метода «Машиночитаемый маркетинг»

Что ещё почитать