Как я победил спам в своих email аккаунтах
- понедельник, 25 мая 2026 г. в 00:00:20
Да, я победил спам! Не "в основном", а "полностью и окончательно". Без всяких "почти". По крайней мере, на 99.9% победил. Причем этот 0.1% - не спам, прорвавшийся через фильтры, а false positives, которые не "вытащил" обратно в Inbox.
Eсли интересно - читайте под катом.
Программы и методы этой статьи могут быть адаптированны к любому из трех типов почтовых сервисов:
Gmail (используется Google Script)
Hotmail, Outlook.com, Live.com (почтовый сервис Майкрософта, используется Graph API)
Любой email сервис, поддерживающий IMAP через Basic Authentication (Login-Password)
Собственно, false positives была проблема #1. В принципе, Gmail and Outlook.com хорошо справляются со спамом. Они отправляют его в Spam фолдер. В обоих сервисах у меня в этом фолдере в сутки было около 30 сообщений, но были случаи, когда это число доходило до 70.
В принципе ничего страшного, но ведь периодически (раз в неделю) надо заглядывать в Спам фолдер чтобы проверить, нет ли там false positive. А сделать это среди сотен спамовых сообщений не совсем тривиально.
В случае с Gmail-ом можно настроить фильтры и применять их к сообщениям таким образом, чтобы проблемый email отправлялся миную Спам сразу в Корзину. А вот Hotmail это не позволяет: если сервис решил, что сообщение - спам, к нему не применяются фильтры (созданные в веб интерфейсе).
Вторая проблема: оба сервиса не позволяют “уничтожать” сообщения сразу, минуя Корзину. Через фильтры можно только переместить спам-сообщение в Корзину, но не “прибить” его (кстати, mail.ru позволяет это сделать). Таким образом, даже при иделальной сортировке фильтрами в корзине скапливаются тысячи сообщений. Номинально оба сервиса говорят, что сообщения остаются в Корзине и Спаме 30 дней, но фактически это минимальный срок. В некоторых ситуациях они там могут сидеть месяцами (а то и годами), если их не вытирать вручную. Баг это или такой дизайн - я не знаю. А иметь сотни или тысячи стертых сообщений в Корзине - это вредно по разным причинам (Privacy, производительность, проблемы с поиском).
Третья проблема: имя и фамилия моей жены полностью совпадают с именем и фамилией нью-йоркского врача (женщины). Соответственно, жена получала кучу медицинского спама и не совсем спама (рассылки медицинских журналов и реклама вполне легитимных медицинских препаратов и лекарств для применения врачами). От чего-то удалось отписаться, но спам не прекращался.
Четвертая проблема: на аккаунт жены идут рассылки (судя по всему, медицинские) из европейских стран. Но мы не читаем по-венгерски, по-испански и по-французски!
После того, как жена заявила “или я или спам”, мне пришлось действовать.
Самым простым решением было бы написать простой сервис для доступа к емайлам через IMAP и делать фильтрацию программным путем в случаях, когда это невозможно сделать фильтрами. Естетственно, фильтрация будет производиться уже после получения письма, но если запускать cron job каждые 15 минут, то особой проблемы нет.
Иногда я получаю спам (на мой aol.com аккаунт), где английский Sender Name или Subject хитро закодирован и спам фильтры его не отлавливают, но с точки зрения человека все читается. Этот метод применяется если в теме письма, например, есть текст на английском и русском языке одновременно, но в случае с AOL спамом идет кодирование исключительно английского текста. Этот аккаунт в принципе не должен получать email-ы на зыках, отличных от английского.
В качестве тестирования IMAP кода я взял мой aol.com аккаунт и вот что получилось (спасибо Claude.ai за помощьв фильтрации). Я убрал некоторые элементы из кода для этой статьи, но принцип, думаю, понятен.
Вот код:
https://github.com/comrade-ogilvy/email-antispam-scripts/blob/main/imap/purge_aol_spam.py
Код по ссылке позволяет фильтровать символ “\u00ad” который используется в Subject-e исключительно спаммерами. Именно этот символ в моем случае для моего аккаунта в aol.com является гарантированным 100%-ым индикатором спама. Мало того, 99% спама были с этим символом.
Кроме того, теперь я могу полностью стереть сообщения с темой вроде “Привет, asmirnov” когда ваш email asmirnov@domain.tld, а вас зовут Александр Смирнов. Им не то что в Спам-фолдере делать нечего, их, по-хорошему, надо вообще не давать “приземлиться” в mailbox-e
BLOCKED_NAME_KEYWORDS = ["mylogin"] # matched against decoded display name (user's login) BLOCKED_SUBJECT_KEYWORDS = ["mylogin"] # matched against decoded subject BLOCKED_DOMAINS = ["comms.aol.net", "ankerdc.com"] # e.g. ["spam.com", malicious.net"] SOFT_HYPHEN = "\u00ad"
При желании, можно полностью стереть сообщение или переместить его в Корзину.
Но у этого метода есть свои недостатки: нужен сервер, на котором в том или ином виде будут находится логин-пароль, что не есть хорошо.
К счастью, у Гугла есть облачный сервис Google Script, который очень хорошо умеет работать с электронной почтой.
Логика кода та же, но не нужен отдельный VPS плюс не нужно писать пароль от вашего аккаунта в коде или где-то хранить его.
который очищает мой Спам фолдер от гарантированного спама (он несколько отличается от реально работающего лода, связано со спецификой моих email-ов, я убрал элементы, которые наверняка не будут интересны читателям Хабра) . В большинстве случаев - навсегда, даже без перемещения в корзину. Например, если у sender domain отсутствуют MX и A records (From: ghsdjfadjfdjgfd@iuwadjkrei.com), то я сразу стираю это сообщение. Это правило уничтожило где-то 90-95% спама
Есть и другие критерии:
Если сообщение в Спаме не от домена в моем (не РКН) белом списке, то переместить в Корзину.
Вот список:
var ALLOWED_TLDS = [ ".com", ".net", ".org", ".il", ".uа", ".ru", ".ca", ".cz", ];
Я, конечно получаю изредка легитимные сообщения из .uk или .es, но ни разу не было случая, что легитимное сообщение из .uk или .es было помечено Гуглом как спам (код по ссылке очищает именно Спам фолдер, а не Inbox). Пусть сразу идет в Корзину,
Eсли сообщение в моем (не РКН) черном списке, то отправить его в Корзину (хотя, надо наверное, стереть без следа)
Я точно знаю, что, к примеру, емайлы от veganinfo.com мне не нужны ни в каком варианте и никогда не будут нужны. Я не хочу их видеть и себя в mailbox-e. Но... в данном примере, я все-же решил не стирать немедленно такие сообщения. Их относительно мало и оно не являются проблемой. Пусть 3 дня поживут в Корзине.
Пример черного списка
var BLOCKED_DOMAINS = [ ".tk", "onlinecrm.marketing", "veganinfo.com", ];
После установки триггера скрипта на https://script.google.com на “запускать каждые 15 минут” в Спам фолдере остались, фактически только false positives. Их мало - максимум 5 в месяц, обычно меньше, но зато я их сейчас вижу без проблем.
Остальной спам сразу переходит в Корзину. Kорзина очищается этим же скриптом: остаются сообщения за последние 3 дня, мне так спокойнее.
function purgeDeletedFolder() { console.log("purgeDeletedFolder() started"); var threads = GmailApp.search('in:trash older_than:3d'); threads.forEach(function(thread) { Gmail.Users.Threads.remove('me', thread.getId()); }); console.log("purgeDeletedFolder() ended"); }
На каждое выполнение скрипта мне приходит отчет в Телеграм (на всякий случай).
function sendToTelegram() { var BOT_TOKEN = "xxxxxxxxx:zzzzzzzzzzz-wwwwwwwwwww"; var CHAT_ID = "-yyyyyyyyyyy"; var deleteRate = stats.processed > 0 ? ((stats.deleted / stats.processed) * 100).toFixed(2) : 0; var text = "Spam Cleanup Report\n\n" + "Processed: " + stats.processed + "\n" + "Deleted: " + stats.deleted + " (" + deleteRate + "%)\n" + "Permanently deleted: " + stats.permanently_deleted + "\n\n" + "SPF misaligned: " + stats.spf_misaligned + "\n" + "Infra abuse: " + stats.infra_abuse + "\n\n" + "Cache hits: " + stats.cache_hit; if (stats.permanently_deleted_list.length > 0) { text += "\n\n Permanently deleted:\n"; stats.permanently_deleted_list.slice(0, 20).forEach(function(e) { text += "• " + e + "\n"; }); if (stats.permanently_deleted_list.length > 20) { text += "...and more (" + stats.permanently_deleted_list.length + ")"; } } var url = "https://api.telegram.org/bot" + BOT_TOKEN + "/sendMessage"; UrlFetchApp.fetch(url, { method: "post", payload: { chat_id: CHAT_ID, text: text } }); }
Теперь займемся медицинским спамом.
Как я уже писал, жена получала много медицинского спама и спама с национальных европейских доменов. Фильтрация стандартными фильтрами по домену в Гугле проблематична. Например, если вы сделате фильтр для .de (Германия), то он отсеет также abc.de@domain.tld, что, очевидно, плохо. Фильтрация по медицинским терминам может отсеять легитимную переписку с врачем или родственником.
Поэтому, я скормил спам-сообщения жены Claude.ai и он выдал свои рекоммендации и сразу же их и реализовал. Идея в том, что медицинский спам рассылается ограниченным колличеством mass mailing сервисов, которые я с радостью заблокировал. Заодно заблокировал (как и в моем случае) спам, где отправитель - несуществующий домен. По какой-то причине, на аккаунте жены эти сообщения иногда прорывались сквозь фильтры. Теперь они идут в корзину каждые 15 минут. Опять-таки, по идее их надо уничтожать на месте, но мне не хотелось делать такие резкие движения не на моем аккаунте.
Код очистки Inbox-a жены
Интересный факт: вот эти "товарищи" ответственны за 75% спама в ящике жены (почти весь "легитимный" медицинский спам идет от них:
var MEDICAL_SPAM_DOMAINS = [ "info.haymarketmedicalnetwork.com", "haymarketmedicalnetwork.com", "haymarketmedia.com", "en25.com", // Oracle Eloqua marketing platform "mdedge.com", "healio.com", "medscape.com", "givingsight.org", // <-- add: Optometry Giving Sight "bloomerang-mail.com", // <-- add: their sending platform "nejm.org", // add/remove based on what she receives "aao.org" ];
Также отправил в Корзину все сообщения не из белого списка (жены, не РКН).
Вот этот белый список:
var ALLOWED_TLDS = [ ".com", ".net", ".org", ".gov", ".il", ".ua", ".ru", ".ca", ".cz", ".de", ];
А вот это -
var KNOWN_GOOD_DOMAINS = { "gmail.com": true, "googlemail.com": true, "outlook.com": true, "hotmail.com": true, "live.com": true, "outlook.co.il": true, "hotmail.co.il": true, "mail.com": true, "fastmail.com": true, "yahoo.com": true, "icloud.com": true, "aol.com": true, "walla.com": true, "walla.co.il": true, "ukr.net": true, "i.ua": true, "mail.ru": true, "yandex.com": true, "yandex.ru": true, "ceznum.cz": true, };
список почтовых сервисов, на которые не надо выполнять DNS запросы на A и MX записи. Используется, чтобы минимизировать колличество сетевого трафика из скрипта. Иначе можно и бан получить от Гугла в какой-то ситуации. Это не значит, что вся почта с этих доменов - легитимная. Это всего-лишь означает, что сами домены - легитимные.
Фильтрация спама на почтовом сервисе Майкрософта (Hotmail, outlook.com, live.com)
Третий пример: фильтрация спама на Hotmail-овском Спам фолдерe с целью его очистки для быстрого поиска false positives. Для этого используется Graph API, т.к. стандартная аутентификация по логину-паролю для IMAP-a больше не работает на сервисах Майкрософта.
Основная проблема Hotmail-a в том, что если Майкрософт решил, что сообщение - спам, то на него не действуют пользовательские фильтры, что не позволяет сразу удалять сообщения в Корзину в момент получения. Плюс относительно большое колличество false positives, которые надо перемещать в Inbox как минимум, вручную, а как максимум - программным путем.
Пример кода (я убрал из реального кода специфические моменты, которые неинтересны 99% хабраюзеров)
https://github.com/comrade-ogilvy/email-antispam-scripts/blob/main/hotmail-outlook/purge_hotmail_spam_folder.py
Я получал десятки спам-сообщений в день. После беседы с Claude выяснилось, что 90% спама идут с 6 доменов, еще 3-4% - от какого-то mailer-a который использует 4 дефиса “----” в поле From.
Что-то вроде abcde@-----mail.xyz.com
Такие email-ы сразу стираются, остальные (максимум 1-2 в день) заканчивают свою жизнь в Корзине. Фактически, на этом этапе в Спам фолдере остаются исключительно false positives.
В реальном коде (не в этом примере) гарантированно false positives сразу перемещаются в Inbox.
Отдельный вопрос: почему Майкрософт ничего не делает с этой spam farm? Она “работает” уже несколько лет, что стоит отфильтровать эти несчасные 6 или 7 доменов на своих серверах еще до того, как сообщение оказывается в почтовом ящике?
Ради интереса, я пересылю статистику по очищенным сообщениям на сервис временной почты yopmail.com. У него есть RSS интерфейс, что очень удобно для беглого просмотра статистики
Это - веб интерфейс

A это - RSS интерфейс моего RSS reader-a

Вроде всё. Если есть вопросы - пишите в комментарии или ЛС.
Отдельное спасибо Claude.de за анализ нескольких тысяч спам сообщений и рекоммендации и правки кода для программной фильтрации спама.
Автор выражает благодарность СhatGPT за генерацию изображения для обложки, Кириллу и Мефодию за буквы русского алфавита, а этрускам - за буквы латинского алфавита.
Весь код в репозитории по ссылкам опубликован по лицензии MIT. Делайте, что хотите, но я не несу ответсвенность за бесследно уничтоженные email-ы при использовании этого кода и за любые другие последствия его использования включая, но не ограничиваясь, сбои в работе компьютера, поломки жесткого диска, потерю работы, неназначение интервью и т.д.