Декодирование писем в формате TNEF в Postfix

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

Потом я обратил внимание на размер письма (несколько сотен килобайт) и на отображаемый в клиенте текст. Письмо было явно слишком большим для такого небольшого объёма информации. Я заглянул в исходный текст письма и обнаружил, что в нём имеется вложение с именем файла "winmail.dat" и MIME-типом "application/ms-tnef".

Я заинтересовался, а что же это вообще такое и обнаружил, что это изобретённый Microsoft новый формат для писем, а понимают его только почтовые клиенты Outlook и те клиенты, разработчики которых специально озаботились этой проблемой. Письмо открывалось с помощью изделия той же фирмы Microsoft - Outlook Express, но изделие молча игнорировало попытки старшего брата донести до него информацию.

Первым делом я нашёл рецепт отключения этой фичи в Outlook отправителя Файлы winmail.dat в письмах и отправил эту ссылку отправителю.

Предвидя возможные повторы этой проблемы и необходимость снова и снова отправлять эту ссылку разным людям, я поискал, а нельзя ли этот TNEF преобразовывать прямо на сервере? Нашёл следующую заметку Postfix + ytnef filter, которая, к слову, была написана всего полтора месяца назад. Так что если бы я столкнулся с проблемой раньше, возможно мне так и пришлось бы отправлять людям ссылку.

Там описывается настройка прокси-конвертера ytnef smtpd для FreeBSD. Поскольку у меня сервер работает под Debian Lenny, я решил выложить тут адаптированный вариант, а иначе просто ограничился бы ссылкой.

Итак, перво-наперво, ставим сам конвертер ytnef и python:

# aptitude install --with-recommends ytnef
# aptitude install python

Качаем архив со скриптом по ссылке и распаковываем его:

$ wget https://web.archive.org/web/20140625121553/http://www.viraj.org:80/ytnef_smtpd/ytnef_smtpd-1.1.tar.gz
$ tar xzvf ytnef_smtpd-1.1.tar.gz
$ cd ytnef_smtpd-1.1

Копируем скрипт туда, где ему положено лежать:

# cp ytnef_smtpd.py /usr/local/bin/
# chmod +x /usr/local/bin/ytnef_smtpd.py

И меняем настройки скрипта, которые находятся в нём самом-же. У меня в Postfix уже есть два прокси, первый сканирует письма на предмет наличия вирусов, а второй проставляет оценки уровня спама. Наша задача - встроить новый прокси в начало цепочки, чтобы сначала письмо преобразовывалось, а затем уже проверялось и оценивалось.

Приведу лишь изменённые строки:

LISTEN_PORT = 10028
REMOTE_PORT = 10026
YTNEF_BIN = '/usr/bin/ytnef'
FILE_BIN = '/usr/bin/file'
LOG_FILE = '/var/log/ytnef_smtpd.log'

Скрипт будет ожидать подключений к порту 10028, а преобразованное письмо будет отправлять на порт 10026, где его будет ловить уже антивирус.

Теперь создадим скрипт автозапуска /etc/init.d/ytnef_smtpd.sh (он немного отличается от оригинала):

#!/bin/sh

case "$1" in
  start)
    if [ -f /var/run/ytnef_smtpd.pid ]
    then
      echo "Script already launched. PID: "`cat /var/run/ytnef_smtpd.pid`"
    else
      echo "Starting ytnef smtpd..."
      /usr/local/bin/ytnef_smtpd.py &
      echo $! > /var/run/ytnef_smtpd.pid
      echo "...Done!"
    fi
    ;;
  stop)
    if [ -f /var/run/ytnef_smtpd.pid ]
    then
      echo "Shutting down ytnef smtpd..."
      kill -TERM `cat /var/run/ytnef_smtpd.pid`
      rm -f /var/run/ytnef_smtpd.pid
      echo "...Done!"
    else
      echo "ytnef smtpd not launched."
    fi
    ;;
  *)
    echo "Use start script for: { start | stop }" >&2
    exit 1
    ;;
esac

Пропишем его автозапуск и запустим:

# chmod +x /etc/init.d/ytnef_smtpd.sh
# update-rc.d ytnef_smtpd.sh defaults
# /etc/init.d/ytnef_smtpd.sh start

Теперь скрипт должен прослушивать порт 10028, это можно проверить следующей командой:

# netstat -nlp4 | grep 10028

Если это так, значит пока что всё идёт нормально.

Теперь нужно перенастроить Postfix, так чтобы он перенаправлял только что полученные письма на обработку ytnef smtpd.

В файле /etc/postfix/main.cf прописываем порт первого прокси в цепочке (в нашем случае это порт ytnef smtpd - 10028):

content_filter = scan:127.0.0.1:10028

И если до этого у вас не было прокси, добавляем в файл /etc/postfix/master.cf следующие строчки (обратите внимание на пробелы в начале всех строк, кроме первой):

127.0.0.1:10025 inet n - n - 16 smtpd
  -o content_filter=
  -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
  -o smtpd_helo_restrictions=
  -o smtpd_client_restrictions=
  -o smtpd_sender_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject
  -o mynetworks_style=host
  -o smtpd_authorized_xforward_hosts=127.0.0.0/8

Эти строчки настроят ещё один smtp-сервер, который будет принимать письма на порту 10025 только от локальных программ, но при этом не будет отправлять письма на дальнейшую проверку. Именно этот порт необходимо указать в настройке "REMOTE_PORT", если у вас больше нет никаких прокси в цепочке.

Осталось перезапустить postfix и всё должно заработать:

# /etc/init.d/postfix restart

Я специально ради этого устанавливал себе на компьютер Outlook, отправил из него письмо в формате tnef и принял в Outlook Express. Письмо прочиталось вместе с вложениями.

Написать автору