К вопросу велосипедостроения в сфере электропочтового хранения

в 10:21, , рубрики: C#, email, mime, велосипедостроение, Программирование, системное администрирование, хранение данных

Волею судеб есть на моём попечении почтовый сервер. Маленький, ~20 пользователей. Работает стабильно, менять ПО нежелательно. И не нужно бы, но однажды логи бэкапа недвусмысленно намекнули – если продолжать в том же духе, на полный бэкап будет уходить вся ночь. И дело – в объёмах почтовых ящиков пользователей.

К вопросу велосипедостроения в сфере электропочтового хранения - 1


Проблема обозначена, надо решать. Путь напролом – закупить железо ещё мощнее – не в моём вкусе, да и бюджет не резиновый. Очевидный вариант: квоты. Но на практике это не слишком помогает. Клятвенные заверения «я всё почистил» при ближайшем рассмотрении превращаются в котиков, смешные картинки и семейные фотоархивы (в корпоративной почте, да). А количество криков «у меня срочно горит не работает сделайте немедленно» возрастает на порядок. Так недолго и веру в людей потерять.

К счастью, я не психолог, не тренер и не наставник. Моё дело – техника. Вот и подойдём с технической стороны.

Первое, что подумалось – самоуничтожающиеся сообщения. Грубо говоря, всё без отметки «важное» удаляется через N дней. На мой вкус, это должно быть «вшито» в стандарты электропочтового хранения. Но пока этого нет, а реализация показалась мне уж слишком масштабной.

Второй мыслью были копии. Знаете, эти сообщения, где вы не основной адресат. Приходит вам просто для сведения. Часть таких сообщений можно было бы удалять автоматически. Но, внезапно, тут пользователи разделились на два лагеря: «они все нужны вы что» и «а что это такое». Алгоритм автоматической сортировки с такими условиями я не осилил.

Что ж, не удалять, так копировать! Возьмём все копии и сделаем символические ссылки. Беглый анализ показал: даже обработка таким образом только ПОЛНЫХ дубликатов позволяет сэкономить ТРЕТЬ хранилища. Но, но, но. К сожалению, путь это тупиковый ввиду множества технических ограничений.

Подробности для интересующихся под спойлером

— не все архиваторы понимают симлинки;
— ПО сервера местами сходит с ума;
— сложности орг. характера и прав доступа.

К слову, в моём почтовом сервере настройки и общих бэкапов, и архивного хранения для пользователей – очень куцые. Так что пространство для манёвра было невелико.

Что же остаётся? С грустью глядел я на котиков

К вопросу велосипедостроения в сфере электропочтового хранения - 2

и прикидывал уже простенькую нейросеть, которая бы чистила почту за юзера. И тут… Позвольте, позвольте, а что вообще котики делают в письме? Помнится, письмо с вложением весит чуть не на треть больше одного вложения! А не переместить ли вложение?..

Так начался путь, где было «много открытий чудных». Знал бы я… Ну, вы понимаете. Капля неведения и отвага ведут нас к победам!

Итак: делаем хранение вложений отдельно от писем.

Главная ошибка, которую можно тут совершить – это открыть eml-файл в текстовом редакторе и решить, что там простой текст. Так я и поступил. И обрадовался. Щас батник напишу. Утилит командной строки для извлечения вложений полно: github.com/erikvdv1/eml-attachments или github.com/maiken2051/uudeview, навскидку. Есть проблемы с кодировками, но это не самое главное.

Самое главное: вынуть файл и создать на него ссылку – дело плёвое. А вот впихнуть эту ссылку в оригинальное письмо… Потому что там не текст. Там MIME.

Опытный читатель, конечно, посмеивается сейчас над незадачливым автором. Автор же открывал для себя прелести «стандарта». Самое главное, что я понял: для впадения в берсерка мухоморы не обязательны.

Примеры и ругань – под спойлером:

charset=UTF-8
charset = «UTF-8»
charset=«UTF-8»
charset=UTF-8;
charset=«UTF-8»;
charset = «UTF-8»;
Это вот у них одно и то же.

Разрывы строк посреди потока Base64. Откуда берутся – для меня до сих пор загадка.

И наоборот: отсутствие rnrn после заголовочной части.

В самом заголовке порядок полей по желанию левой пятки.

Старые письма допускают длину строки не более 80 символов, включая служебные.

В именах файлов могут быть разрывы строк (в теле письма, а не в самом имени).

Вообще разрывы строк могут быть где угодно, это при том, что в стандарте разрыв строки заявлен как конец текущего параметра.

Сам текст письма кодирован. Как конкретно он кодирован, остаётся на совести конкретного сервера, вариантов там куча (смердячая).

А, и в письме почти всегда есть и html-часть. То есть, если шлёшь «Привет» и там есть тэг br или p, то в письме всегда будет ДВЕ секции: с просто текстом и с тэгами. И текст задублирован. А вот здесь они «сэкономили» вычислительные мощности… Просто какой-то зверинец с Франкенштейном.

Имя файлов у них бывают так: filename="=?encoding?type?; а бывает так: filename*0*=encoding'' (ШТА??!!). Второе – это более новый стандарт, RFC5987. В стандарте прямо указано, что filename*0*=ENC и filename="=? одно и тоже. На этом месте я окончательно убедился, что они издеваются. Как это можно нормально обрабатывать, я не знаю.

Отдельно, как водится, отличился Apple. У них вообще какой-то свой стандарт. Забегая вперёд, долгие попытки обработать их код привели к единственно верному решению: «Error: Apple mail is not supported.»

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

Но унывать не стал. Документацию не читай@код пиши, и готово. Нет, серьёзно, я что-то должен был сделать, чтобы приблизить конец MIME.

Batch-скриптом не обошлось. Получилась утилита командной строки на C# и dotNet.

Утилита обладает двумя режимами работы:
Первый: просто извлекает вложения. При этом корректно работает с кодировками под Windows.

Второй: и тут главное веселье. Теперь мы таки можем хранить почтовые вложения отдельно от почты! Утилита создаёт новое письмо взамен старого: вложение вырезается, письмо переформатируется в простой HTML с кодировкой UTF без ограничения длины строки. За основу берётся секция text/plain. Если в секции html есть таблицы, то переносит их с сохранением форматирования внутри таблицы, но этот функционал работает так себе. В конец текста текущего письма (если это ответ или форвард) вставляются ссылки на сетевые ресурсы с путём к извлечённым файлам, в форматах file:/// и ftp://.

image

Система протестирована на 10000+ письмах и развёрнута на действующей инфраструктуре.

Выявленные плюсы:
+ было:

Резервное копирование
было начато в 01:00:08
и успешно завершилось 03:26:32

стало:

Резервное копирование
было начато в 01:00:09
и успешно завершилось 01:40:36

+ Сэкономлено 30+ % хранилища: файлы уходят из тяжеловесного Base64 и иже с ним в нормальный формат файловой системы, плюс множество дубликатов обнаружилось даже внутри отдельных ящиков.

+ Увеличивается скорость обработки ящиков сервером и почтовыми программами.

+ Пропадает «я открыла письмо из почты, 10 часов редактировала и оно не сохранилось»

+ Можно отказаться от квот.

+ Остаётся возможность найти вложение в почте, в отличие от простого переноса в файловое хранилище.

+ Приближаю конец MIME. Покайтесь, авторы!

Минусы решения:

— некоторые письма (но не вложения) всё же бьются. В основном не внутренне, а при просмотре в некоторых клиентах;
— в ftp постоянно ломятся какие-то черти;
— не все почтовые клиенты поддерживают открытие через file:///

Спорные моменты:

? Apple mail not supported. По мне – и Будда с ним;
? Бьются письма со сложным форматированием. Обычно это флаеры с Букинга или реклама;
? Если ftp-сервер на нестандартном порту, то могут быть проблемы с доступом. Решил почтовым ботом.

Таким вот тернистым путём задача была решена.

Спасибо за внимание!

Автор: LevOrdabesov

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js