Мёртвые адреса — это налог на доставляемость живых
Почтовый провайдер не оценивает каждое ваше письмо по отдельности. Он смотрит на весь поток с вашего домена и IP разом: какая доля улетает в bounce, какая помечается как спам, сколько получателей вообще открывают и кликают. Эта агрегированная репутация решает, куда попадёт следующее письмо — в «Входящие», в «Промоакции» или в спам. И решает она это для всей рассылки сразу, а не персонально для каждого адресата.
Отсюда неприятный вывод: каждый невалидный или давно молчащий ящик в вашем списке тратит репутационный бюджет живых подписчиков. Вы отправили 100 000 писем, из них 15 000 ушло на адреса, где никто не читает почту год, и ещё 3 000 просто отскочило от несуществующих ящиков. Gmail видит поток с низким engagement и заметным bounce — и понижает inbox placement для всех, включая тех 40 000 человек, которые вас реально ждут. Мёртвая часть базы буквально забирает доставляемость у живой.
С 1 февраля 2024 года это перестало быть темой для дискуссий. Gmail и Yahoo ввели единые требования для отправителей от 5000 писем в день на один домен, и они обязательны:
- Spam complaint rate < 0.3% по данным Google Postmaster Tools. Реальная рабочая цель — держаться ниже 0.1%; на 0.3% уже начинается throttling.
- One-click unsubscribe обязателен: заголовки
List-Unsubscribe: <https://...>, <mailto:...>вместе сList-Unsubscribe-Post: List-Unsubscribe=One-Click(RFC 8058), и отписка должна отрабатывать в течение двух дней. - SPF, DKIM и DMARC настроены и выровнены по домену (минимум запись DMARC с
p=noneи рабочим alignment).
Sunset-политика — это не гигиена ради аккуратности. Это защита канала от собственного балласта. Дальше — как построить её инженерно, а не на глаз.
Активность в 2026 — это клик, а не открытие
Если ваша сегментация неактивных строится на open rate, она сломана. С сентября 2021 года Apple Mail Privacy Protection префетчит все трекинг-пиксели через свой прокси — вне зависимости от того, открыл человек письмо или нет. Open rate по аудитории Apple Mail завышается на 50–70%, а геолокация по IP из пикселя становится мусором (запрос идёт с прокси Apple). Добавьте сюда Gmail Image Proxy, который кэширует картинки ещё до открытия письма, и корпоративные security-сканеры, которые на входе дёргают каждую ссылку, — и «открытие» превращается в сигнал, который с равной вероятностью означает живого человека или робота-антивирус.
Что считать реальным сигналом активности:
- клик по ссылке в письме (
last_click_at); - транзакционное действие — логин, покупка, вход в личный кабинет;
- ответ на письмо.
Клики тоже не стерильны: те же security-сканеры генерируют фантомные клики, поэтому транзакционное действие остаётся самым чистым сигналом. Но клик несравнимо ближе к живому человеку, чем открытие. Открытия хранить можно — но только как справочную колонку last_open_at, а не как основание для решений. Если вы построите sunset на открытиях, вы вычистите как раз активных читателей (которые кликают, но не «открывают» из-за клиента без загрузки картинок) и оставите ботов Apple, которые прилежно «открывают» каждое письмо. Решение по адресу принимает только last_click_at.
Модель жизненного цикла: recency-бакеты
Никакого ML для начала не нужно. Достаточно RFM-lite — разбить базу по дате последнего клика на четыре бакета. Для еженедельной рассылки рабочие пороги:
- Active — клик за последние 0–90 дней;
- Cooling — 90–180 дней;
- Dormant — 180–365 дней;
- Sunset — 365+ дней без клика.
Пороги подстраиваются под частоту отправки. Ежедневная рассылка — окна уже (человек, не кликавший 60 дней при семи письмах в неделю, уже холодный). Квартальный ньюслеттер — окна шире, там и год молчания нормален. Ключевое правило: переход в Sunset запускает ре-энгейджмент, а не мгновенный DELETE. Sunset — это состояние, а не команда удаления.
Классификация bounce по SMTP-кодам
Bounce нельзя разбирать «на глаз» по тексту письма. SMTP-код детерминирован — по нему строятся жёсткие правила. Вот строка из лога Postfix для типичного hard bounce:
postfix/smtp[2841]: 9F3A2: to=<[email protected]>, relay=mx.example.com[93.184.216.34]:25,
delay=1.2, dsn=5.1.1, status=bounced (host mx.example.com said: 550 5.1.1
<[email protected]>: Recipient address rejected: User unknown)Ключевое поле — dsn=5.1.1 и код 550 5.1.1. Правила разбора:
- Hard bounce —
550 5.1.1(нет такого пользователя),550 5.1.2(домен не принимает почту). Suppress немедленно, ноль ретраев. Адрес мёртв, повторять бессмысленно и вредно для репутации. - Soft / временный — любые
4.x.x:421(rate-limited),450,452(too many recipients). Экспоненциальный бэкофф, ретраи по расписанию. Это не про адрес, это про момент. - Mailbox full —
452 5.2.2/552. Серая зона: ретраить ограниченно, но suppress после 5 отказов подряд за 72 часа. Заброшенный переполненный ящик — почти всегда мёртвый. - Reputation / auth block —
550 5.7.1,550 5.7.26. Это не про адрес, это про вас. Провайдер отверг письмо из-за вашей аутентификации или репутации. Suppress здесь — грубейшая ошибка новичка: вы выбросите валидные адреса и спрячете реальную проблему. Чинить DKIM/DMARC/SPF, а не вычищать список.
Sunset-политика в SQL
Хранить plaintext удалённых адресов не нужно и с точки зрения GDPR вредно. Правильный подход — permanent suppression по SHA-256-хешу: при каждой отправке адрес хешируется и проверяется по suppression_list через LEFT JOIN. Так вы никогда не перешлёте письмо на подавленный адрес, но и не храните персональные данные тех, кого удалили по «праву на забвение».
Структура таблицы подавления минимальна: email_hash (SHA-256 hex, первичный ключ), reason (hard_bounce | complaint | unsub | sunset | disposable) и created_at.
-- кандидаты в Sunset: активны когда-то, но без клика 365+ дней, ещё не подавлены
SELECT s.id, s.email
FROM subscribers s
LEFT JOIN suppression_list sup
ON sup.email_hash = encode(digest(lower(s.email),'sha256'),'hex')
WHERE s.last_click_at < now() - interval '365 days'
AND s.status = 'active'
AND sup.email_hash IS NULL;
-- permanent suppression: храним хеш, а не plaintext удалённого адреса
INSERT INTO suppression_list (email_hash, reason, created_at)
VALUES (encode(digest(lower($1),'sha256'),'hex'), 'hard_bounce', now())
ON CONFLICT (email_hash) DO NOTHING;ON CONFLICT DO NOTHING даёт идемпотентность — один и тот же адрес можно «подавлять» сколько угодно раз без ошибок. А проверка через LEFT JOIN ... WHERE sup.email_hash IS NULL на каждой выборке гарантирует, что подавленный адрес физически не попадёт в очередь отправки, даже если он всё ещё лежит в subscribers.
Ре-энгейджмент: три письма, жёсткий дедлайн
Бесконечная серия «мы скучаем» — это не ре-энгейджмент, а медленное самоубийство репутации: вы полгода долбите незаинтересованных, накапливая жалобы. Рабочая схема жёсткая и короткая:
- 3 письма за 14 дней. Первое — прямой вопрос «вы ещё с нами?». Второе (день 7) — что человек теряет. Третье (день 13) — явный дедлайн: «если не подтвердите до завтра, мы отключим рассылку».
- One-click resubscribe в каждом письме — крупная кнопка, ведущая на клик-эндпоинт.
- Кликнул → возвращаем в
active, обнуляем счётчик. Не кликнул →suppressсreason = 'sunset'.
Важно: подавление — это смена статуса и запись хеша, а не DELETE строки. Строка subscribers нужна для дедупликации будущих импортов — если тот же адрес зальют повторно из другого источника, вы не начнёте слать ему заново. И не отправляйте ре-энгейджмент на hard-bounced адреса — они уже мертвы, это только жжёт репутацию.
Про ожидания: реактивация 3–8% на dormant-сегменте — это норма, а не провал. Если вернулось 5% — вы вернули реальных людей и очистили остальные 95% от балласта. Это выигрыш, а не потеря базы.
Ловушки и почему SMTP-верификация опасна
Спам-ловушки бывают двух видов, и второй прямо объясняет порог в 365 дней:
- Pristine traps — адреса, которых никогда не существовало, посеянные провайдерами и антиспам-организациями по вебу. Попадают в базу через парсинг и покупные списки. Один такой адрес — сигнал провайдеру, что вы собираете почту нечисто.
- Recycled traps — реальный когда-то ящик, заброшенный владельцем. Провайдер держит его в статусе «нет пользователя» примерно 12 месяцев, а затем реактивирует как ловушку. Вот почему порог Sunset именно 365+ дней: адрес, молчащий год, с высокой вероятностью уже стал recycled-ловушкой.
Теперь про соблазн «просто проверить адреса» через SMTP-пробинг (RCPT TO без DATA). Это ненадёжно и опасно одновременно:
- catch-all домены отвечают
250 OKна любой адрес — ложный positive, вы считаете мёртвый адрес живым; - greylisting возвращает
451на совершенно валидный ящик — ложный negative, вы выбрасываете живого; - массовый пробинг с вашего sending-IP детектится провайдерами как directory harvest attack (перебор адресов) и роняет репутацию IP быстрее, чем любая грязная рассылка.
Для evilmail это фундаментально: temp/disposable-домены — это фабрика recycled-ловушек и одноразовых ящиков по определению. Гигиена начинается на этапе сбора, а не рассылки. Фильтруйте disposable-домены на входе — проверка MX плюс список известных временных провайдеров до записи в базу. Отсеять мусорный адрес на форме регистрации в сто раз дешевле, чем вычищать его последствия из репутации домена.
Чек-лист гигиены перед каждым большим сендом
- Opt-in подтверждён — в списке только те, кто явно подписался (double opt-in по возможности).
- List-Unsubscribe + List-Unsubscribe-Post присутствуют, one-click отписка отрабатывает за < 2 дней.
- Suppression_list вычтен — выборка идёт через
LEFT JOIN ... IS NULL, подавленные не в очереди. - Disposable-домены отфильтрованы на этапе сбора (MX + список известных temp-провайдеров).
- Hard-bounce из прошлой рассылки уже перенесены в suppression с
reason = 'hard_bounce'. - Spam rate в Postmaster Tools < 0.3% (цель < 0.1%) за последнюю неделю.
- DMARC `p=quarantine` или `reject` с выровненным DKIM; SPF проходит.
- Sunset-переходы отработаны — dormant-сегмент прогнан через ре-энгейджмент, молчащие подавлены, а не удалены.


