Евгений Прокопьев
Большинство почтовых систем в качестве хранилища сообщений до сих пор
используют различные текстовые форматы. Сегодня мы построим почтовый
сервер на основе реляционной СУБД и посмотрим, какие преимущества нам
это даст.
Одним из малоизвестных, но очень эффективных инструментов
для построения сложных и масштабируемых почтовых систем является DBMail –
комплекс программ для UNIX-подобных систем, позволяющий использовать реляционные
СУБД в качестве серверного хранилища почтовых сообщений вместо традиционных
mbox, Maildir и прочих текстовых хранилищ. Используя DBMail, можно добиться:
n Более высокой производительности по
сравнению с файловыми хранилищами – реляционные СУБД гораздо лучше
приспособлены к обработке больших объемов структурированных данных, чем любой
парсер текстовых файлов.
n Большей гибкости при обработке и анализе
корреспонденции – возможности SQL опять-таки несоизмеримы с тем, что
можно сделать, обрабатывая mbox или Maildir различными самописными скриптами на
Perl/Python/Ruby для извлечения какой-либо статистики.
При этом администратор почтовой
системы может задействовать различные механизмы, предоставляемые СУБД (при
условии, что выбранная им СУБД это позволяет), например:
n Кластеризация – механизм, с помощью
которого можно разместить СУБД на нескольких компьютерах (узлах кластера) с
доступом к единой БД.
n Репликация – возможность автоматического
переноса сообщений из одной БД в другую, создания консолидированной БД из
разных источников и т. д.
n Фрагментирование – разделение одной
логической таблицы БД на несколько физических для упрощения обслуживания,
повышения производительности, сжатия архивных данных и т. д.
n Отказоустойчивость и балансировка нагрузки с
автоматическим переключением на резервный сервер при отказе основного.
n Резервное копирование – горячее (без
необходимости останавливать почтовый сервер, чтобы не получить поврежденное
хранилище сообщений) и инкрементальное (копирование изменений вместо копирования
всего хранилища).
n Дополнительная логика обработки почты, построенную
на триггерах, представлениях и т. д.
Похоже на голубую мечту сисадмина. Конечно, не
все так замечательно: в DBMail пока отсутствуют некоторые возможности более
распространенных и развитых почтовых систем (например, аутентификация с помощью
SASL, встроенная поддержка SSL/TLS, механизм фильтрации почтовых сообщений,
аналогичный Sieve – это первое, что приходит в голову), но реализовать их проще
(и работы над реализацией многих недостающих возможностей ведутся), чем
добавить описанные выше возможности к традиционным почтовым системам.
DBMail – продукт нидерландской компании IC&S,
в котором также есть вклад большого числа независимых разработчиков из разных
стран. Он распространяется по лицензии GPL, кроме того, IC&S
предлагает платную поддержку.
Архитектура
В дальнейшем я предполагаю, что вы знакомы с общими принципами построения
почтовых систем, и термины MTA, MDA и MUA вас не пугают. Если это не так, то
всю необходимую информацию вы можете найти в моей статье «Круговорот почты в
сети, или Архитектура современных почтовых систем», опубликованной в предыдущем
номере журнала. Принципиальная схема работы DBMail, которую нарисовал Wolfram
A. Kraushaar, вдохновленный примером Postfix big picture, выглядит так
(см. рис. 1).

Рисунок 1. DBMail big picture
Теперь небольшой комментарий
к изображению. В основе DBMail лежит реляционная БД – хранилище учетных
записей пользователей, почтовых ящиков, сообщений и прочей вспомогательной
информации. Также в состав DBMail входят две категории MDA:
n Предназначенные для доставки сообщений от MTA
в хранилище.
n Предназначенные для доставки MUA из хранилища.
К первым относятся:
n dbmail-smtp – исполняемый файл,
использующий pipe-интерфейс: читает почтовое сообщение от MTA со стандарного
входа (stdin) и сохраняет его в БД. Таким образом, на каждое входящее сообщение
создается отдельный процесс UNIX и подключение к СУБД.
n dbmail-lmtpd – UNIX-демон, принимающий
клиентские подключения через UNIX-сокет или TCP-сокет. Для приема почтовых
сообщений используется протокол LMTP. На каждое входящее сообщение MTA создает
только клиентский сокет, необходимое количество процессов и подключений к БД
создается заранее. Таким образом, этот вариант обеспечивает лучшую производительность
при высокой нагрузке, но при низкой он потребляет больше системных ресурсов,
чем необходимо.
Ко вторым относятся:
n dbmail-pop3d – демон для доступа по
протоколу POP3.
n dbmail-imapd – демон для доступа по
протоколу IMAP.
Кроме того, в состав DBMail
входят следующие вспомогательные утилиты:
n dbmail-users – инструмент для управления
пользователями и их псевдонимами (возможно, многим из вас будет привычнее
термин alias).
n dbmail-util – инструмент для очистки,
оптимизации и проверки корректности БД.
Общая часть функциональности всех рассматриваемых
исполняемых файлов реализована в разделяемых библиотеках: libdbmail,
libauthdbmail, libsortdbmail и lib[rdms-name]dbmail. В настоящее время тип
поддерживаемой СУБД жестко определяется на этапе ./configure, причем указать
можно только одну СУБД. В будущем планируется реализовать динамическую
подгрузку модулей для работы с различными СУБД, описываемую в конфигурационном
файле, – это должно упростить создание и поддержку пакетов DBMail для различных
дистрибутивов Linux.
В качестве СУБД в настоящее время поддерживаются
только PostgreSQL и MySQL, кроме того, в текущей нестабильной версии появилась
поддержка SQLite. Однако реализованный в DBMail уровень абстракции для доступа
к БД позволяет добавлять поддержку других СУБД без внесения каких-либо
изменений в основной код, отвечающий за логику обработки почтовых сообщений.
Установка и настройка
Последней стабильной версией DBMail является 2.0.7, а нестабильной –
2.1.3. Обе можно загрузить с http://www.dbmail.org,
кроме того, самый свежий вариант можно выгрузить из CVN. Для FreeBSD, Debian
Linux и Gentoo Linux существуют готовые порты/пакеты DBMail, для прочих систем
предлагается следующая стандартная процедура установки:
# ./configure –-with-pgsql
(либо -–with-mysql)
# make
# make install
Я использую ALT Linux и считаю этот способ приемлемым
только на тестовых машинах, а для использования на рабочих серверах
предпочитаю собирать любое ПО, отсутствующее в дистрибутиве, в пакеты и
помещать в собственный репозитарий. Соответственно, установка DBMail
в этом случае сведется к:
# apt-get install dbmail
Бинарный RPM-пакет и пакет с исходниками DBMail
для ALT Linux желающие могут загрузить из коллекции бэкпортов для ALT
Linux 2.4 Master (http://backports.altlinux.ru).
Пользователям прочих дистрибутивов Linux или других UNIX-систем предлагается на
выбор установить DBMail стандартным образом или собрать пакет для своей
системы.
Мы будем настраивать DBMail в связке с Postfix (в
качестве MTA) и PostgreSQL (в качестве СУБД – c поддержкой PostgreSQL собран
пакет для ALT Linux) – предполагается, что они уже установлены, настроены и
работают. Для начала сначала создадим БД и пользователя (имеется в виду не
системный пользователь, а пользователь СУБД PostgreSQL)– владельца этой БД:
# createuser -s -U postgres
dbmail
# createdb -U dbmail dbmail
# psql -U dbmail dbmail <
/usr/share/doc/dbmail-2.0.7/sql/postgresql/create_tables.pgsql
Затем создадим конфигурационный файл
/etc/dbmail.conf со следующим содержимым (или слегка отредактируем
уже существующий):
[DBMAIL]
host=localhost
sqlport=5432
sqlsocket=
user=dbmail
pass=dbmailpwd
db=dbmail
postmaster=postmaster@mydomain.com
trace_level=2
[SMTP]
sendmail=/usr/sbin/sendmail
auto_notify=no
auto_reply=no
trace_level=2
[LMTP]
effective_user=mail
effective_group=mail
bindip=*
port=24
nchildren=10
maxchildren=10
minsparechildren=2
maxsparechildren=4
maxconnects=10000
timeout=300
resolve_ip=yes
trace_level=2
max_errors=500
[POP]
effective_user=mail
effective_group=mail
bindip=*
port=110
nchildren=10
maxchildren=10
minsparechildren=2
maxsparechildren=4
maxconnects=10000
timeout=300
resolve_ip=yes
pop_before_smtp=no
trace_level=2
[IMAP]
effective_user=mail
effective_group=mail
bindip=*
port=143
nchildren=10
maxchildren=10
minsparechildren=2
maxsparechildren=4
maxconnects=10000
timeout=4000
resolve_ip=yes
imap_before_smtp=no
trace_level=2
Небольшой комментарий к
содержимому конфигурационного файла. Он состоит из следующих секций:
n DBMAIL – в ней описываются глобальные
настройки, применимые ко всем сервисам DBMail (в основном это параметры
подключения к БД).
n SMTP – здесь описываются параметры
взаимодействия с MTA, которому DBMail передает почтовые сообщения для
дальнейшей обработки.
n LMTP, POP3, IMAP – в этих секциях
описываются настройки соответствующих демонов: на каких адресах и портах
принимать подключения, под какой учетной записью работать, сколько дочерних
процессов породить и т. д.
Пример конфигурационного файла, поставляемого
в комплекте с DBMail, содержит поясняющие комментарии для большинства
настраиваемых параметров.
Теперь необходимо настроить механизм
взаимодействия с Postfix. Как уже было сказано, таких механизмов два:
pipe-интерфейс и LMTP.
В первом случае потребуется в файле
/etc/postfix/master.cf описать следующий транспорт:
dbmail-smtp unix -
n n - - pipe
flags= user=mail:mail
argv=/usr/sbin/dbmail-smtp -d ${recipient}
-r ${sender}
А затем задействовать этот транспорт в
/etc/postfix/main.cf:
mailbox_transport =
dbmail-smtp:
Описание транспорта LMTP будет выглядеть так:
dbmail-lmtp unix -
- n - - lmtp
Или так (если требуется большая детализация в
логах):
dbmail-lmtp unix - -
n - - lmtp -v
Или так (если имена некоторых доменов назначения
входящих почтовых сообщений не описаны в DNS):
dbmail-lmtp unix -
- n - - lmtp
-o
disable_dns_lookups=yes
Во всех этих случаях новый транспорт нужно будет
задействовать следующим образом:
mailbox_transport =
dbmail-lmtp:localhost:24
Разумеется, можно задействовать доставку почтовых
сообщений в хранилище DBMail только для определенных доменов, но это уже не
имеет никакого отношения к DBMail и настраивается исключительно средствами
Postfix.
Кроме того, необходимо поставить Postfix в
известность о тех почтовых ящиках, для которых он должен принимать сообщения.
Создадим для этого файл /etc/postfix/dbmail-mailboxes.cf со следующим
содержимым:
user = dbmail
password = dbmailpwd
hosts = localhost
dbname = dbmail
table = dbmail_aliases
select_field = alias
where_field = alias
И задействуем его в /etc/postfix/main.cf:
local_recipient_maps =
pgsql:/etc/postfix/dbmail-mailboxes.cf $alias_maps
Для того чтобы это работало, Postfix должен быть
собран с поддержкой PostgreSQL. В Debian и ALT Linux (возможно, не только в
них) поддержка PostgreSQL в Postfix вынесена в пакет postfix-pgsql, который
необходимо доустановить, если он еще не установлен.
Пользователи прочих дистрибутивов Linux или
других UNIX-систем, в которых Postfix собран без поддержки PostgreSQL, либо
вообще отсутствует, могут перед компиляцией включить его самостоятельно, указав
ключ -DHAS_PGSQL и пути к соответствующим заголовкам и библиотекам:
# make tidy
# make -f Makefile.init
makefiles \
'CCARGS=-DHAS_PGSQL
-I/usr/local/include/pgsql' \
'AUXLIBS=-L/usr/local/lib -lpq'
# make
Наконец, последний штрих – ежедневные плановые
работы по очистке БД от удаленных записей и проверке корректности БД. Их будет
выполнять файл /etc/cron.daily/dbmail-clean со следующим содержимым:
#!/bin/sh
/usr/sbin/dbmail-util -cturpd
-l 24h -qq
Теперь можно запустить демоны dbmail-lmtpd (в том
случае, если для доставки мы планируем использовать LMTP), dbmail-imapd и
dbmail-pop3d (можно запустить только тот, который будет использоваться для
извлечения почты из хранилища, если он будет один). В пакет для ALT Linux включены
соответствующие стартовые скрипты, которые могут быть вызваны вручную с помощью
service или настроены на автоматическое выполнение при загрузке с помощью
chkconfig/ntsysv. Если для вашей ОС или вашего дистрибутива Linux таких
скриптов нет, вам придется настроить автозапуск вручную.
На этом настройку связки Postfix + DBMail +
PostgreSQL можно считать законченной.
Создадим тестового пользователя почтовой системы
следующим образом:
# dbmail-users
-a test -w testpwd -s test@mydomain.com
Opening
connection to database...
Opening
connection to authentication...
Ok. Connected
Adding user
test with password type ,0 bytes mailbox limit and clientid 0... Ok, user added
id [3]
Adding INBOX
for new user
Ok. added
[test@mydomain.com]
Done
В этом примере с помощью параметра -a указывается
имя пользователя, с помощью -w – пароль, а с помощью s – почтовый ящик, принадлежащий
пользователю (у одного пользователя их может быть несколько).
Отправим созданному пользователю тестовое письмо:
# echo hello | mail -s «Test
Message» test@mydomain.com
В логах мы должны увидеть нечто вроде:
postfix/qmgr[29149]:
432B01774F: from=<john@mydomain.com>, size=301, nrcpt=1 (queue active)
dbmail/lmtpd[29359]:
serverchild.c,PerformChildTask: incoming connection from [127.0.0.1
(localhost.localdomain)]
dbmail/lmtpd[29359]:
db.c, db_get_mailbox_from_filters: default mailbox [(null)]
dbmail/lmtpd[29359]:
sort.c, sort_and_deliver: message id=4, size=333 is inserted
postfix/lmtp[29710]:
432B01774F: to=<test@mydomain.com>, orig_to=<test>,
relay=localhost[127.0.0.1], delay=1341, status=sent (215 Recipient
<test@mydomain.com> OK)
postfix/qmgr[29149]:
432B01774F: removed
Это значит, что письмо успешно доставлено.
Попытаемся получить его по протоколу POP3, чтобы
удостовериться в том, что это действительно так:
# telnet
localhost 110
Trying
127.0.0.1...
Connected to
localhost.
Escape
character is ‘^]’.
+OK DBMAIL pop3
server ready to rock <3b1d246c241825db052940bc65a6a39b@mydomain.com>
user test
+OK Password
required for test
pass testpwd
+OK test has 1
messages (355 octets)
stat
+OK 1 355
list
+OK 1 messages
(355 octets)
1 355
.
retr 1
+OK 355 octets
Return-Path:
john@mydomain.com
Received: by
mydomain.com (Postfix, from userid 502)
id
7E8E617762; Sun, 20 Nov 2005 15:03:04 +0300 (MSK)
To:
test@mydomain.com
Subject: Test
Message
Message-Id:
<20051120120304.7E8E617762@mydomain.com>
Date: Sun, 20
Nov 2005 15:03:04 +0300 (MSK)
From:
john@mydomain.com
hello
.
dele 1
+OK message 1
deleted
quit
+OK see ya
later
Connection
closed by foreign host.
Итак, DBMail настроен и в первом приближении
работает именно так, как нам нужно.
Внутреннее устройство хранилища DBMail
После удачного запуска DBMail имеет смысл взглянуть на устройство его
хранилища более внимательно. Уже знакомый нам по «DBMail big picture» Wolfram
A. Kraushaar нарисовал ER (Entity-Relationship) модель БД DBMail, смотрите рис.
2.

Рисунок 2. DBMail
Entity-Relationship Model
Теперь краткое пояснение. Центральной таблицей
является dbmail_users, в которой хранится вся информация о пользователях:
их имена, пароли, текущий и максимальный размер всех почтовых ящиков, а также
дата и время последнего подключения. Каждому пользователю могут соответствовать
один или несколько почтовых адресов из таблицы dbmail_aliases. Впрочем, с
помощью алиасов в DBMail можно также пересылать сообщения другим адресатам
или передавать внешним программам на стандартный вход (stdin) для дальнейшей
обработки. Каждому пользователю принадлежит один или несколько почтовых ящиков
(каталогов IMAP) из таблицы dbmail_mailboxes, по умолчанию доставка
осуществляется в ящик по имени INBOX. Кроме владельца, с ящиком могут работать
и другие пользователи (такие ящики называются shared folders) – они
описаны в таблице dbmail_subscription, соответствующие права доступа описаны в
таблице dbmail_acl. В каждом ящике хранятся сообщения, IMAP-флаги сообщений
находятся в таблице dbmail_messages, а содержимое сообщений разбивается на
блоки не больше 512 Кб и располагается в таблице dbmail_messageblks –
каждый блок в отдельной записи. Для увеличения производительности размер и дата
получения сообщения вынесены в отдельную таблицу dbmail_physmessage. Таблицы
dbmail_auto_replies и dbmail_auto_notifications используются для
автоматической отправки ответов и уведомлений, а таблица
dbmail_pbsp – для POP/IMAP-before-SMTP (механизма, аналогичного
SMTP-авторизации, но менее распространенного и менее надежного).
Довольно неудобным обстоятельством является то,
что все заголовки каждого сообщения целиком хранятся в одной строке таблицы
dbmail_messageblks – у таких строк значение поля is_header = 1. В нестабильной
версии DBMail заголовки вынесены в отдельную таблицу, и для каждого выделена
собственная запись. Однако вместо того чтобы ждать выхода новой ветки DBMail
или использовать нестабильную, мы можем реализовать эту функциональность
самостоятельно средствами PostgreSQL.
Воспользуемся тем, что PostgreSQL позволяет
создавать функции на языке PL/Python и богатыми возможностями Python в области
обработки почтовых сообщений (разумеется, этот выбор субъективен: желающие
могут реализовать аналогичную функциональность на PL/PgSQL, PL/Perl, PL/Tcl или
даже на С). Сначала включим поддержку PL/Python для выбранной БД:
# createlang -U dbmail
plpythonu dbmail
Для того чтобы эта команда выполнилась,
PostgreSQL необходимо собрать с поддержкой PL/Python. В ALT Linux
поддержка PL/Python вынесена в пакет postgresql-python, который необходимо
доустановить, если он еще не установлен. Кроме того, в ALT Linux PostgreSQL
выполняется в chroot-окружении, поэтому нужно проследить за тем,
чтобы все модули Python, которыми мы собираемся воспользоваться, находились там
же. Проще всего будет полностью перенести каталог /usr/lib/python2.3/ в
/var/lib/pgsql-root/usr/lib, а правильнее будет делать это не регулярно при
необходимости установить или удалить некоторые модули Python, а один раз
описать необходимую последовательность действий в скрипте
/etc/chroot.d/postgresql.lib.
Теперь создадим и протестируем функцию, которая
будет извлекать нужный нам заголовок почтового сообщения:
# psql -U
dbmail dbmail
dbmail=# create
function mailheader(varchar, varchar) returns varchar as $$
dbmail$# import
email.Parser
dbmail$# parser
= email.Parser.Parser()
dbmail$#
message = parser.parsestr(args[0])
dbmail$# return
message.get(args[1])
dbmail$# $$
language plpythonu;
CREATE FUNCTION
dbmail=# select
mailheader(messageblk, 'To') from dbmail_messageblks where is_header=1;
mailheader
---------------------------------------------------
test@mydomain.ru
(записей: 1)
Для того чтобы оценить возможности этого
механизма, у нас слишком маленькая БД. Конечно, можно написать скрипт, генерирующий
множество почтовых сообщений, но мы поступим иначе. Допустим, что у нас уже
есть архив списка рассылки DBMail-Users в формате Maildir. С помощью MUA
создадим IMAP-каталог, а затем с помощью скрипта mailbox2dbmail импортируем в
него все сообщения из архива:
#
/usr/share/doc/dbmail-2.0.7/contrib/mailbox2dbmail/mailbox2dbmail -u test -t
maildir -m maillist/ -b INBOX/DBMail-Users -p /usr/sbin/dbmail-smtp
Processed
Message 1
...
Processed
Message 558
All Done!
Теперь можно провести анализ содержимого
IMAP-каталога:
# psql -U
dbmail dbmail
dbmail=# select
user_idnr, userid from dbmail_users;
user_idnr
| userid
-----------+--------------------------------
1 |
__@!internal_delivery_user!@__
2 |
anyone
3 |
test
(записей: 3)
dbmail=# select
mailbox_idnr, owner_idnr, name from dbmail_mailboxes where owner_idnr = 3;
mailbox_idnr |
owner_idnr | name
--------------+------------+--------------------
1
| 3 | INBOX
3
| 3 | Trash
4
| 3 | INBOX/DBMail-Users
(записей: 3)
dbmail=# select
mailheader(messageblk, 'User-Agent'), count(*)
dbmail=# from
dbmail_messages inner join dbmail_messageblks
dbmail-# on
dbmail_messages.physmessage_id = dbmail_messageblks.physmessage_id
dbmail-# where
mailbox_idnr = 4 and is_header = 1
dbmail-# group
by 1
dbmail-# order
by 2 desc;
mailheader | count
---------------------------------------------------------------------+------
| 194
Debian
Thunderbird 1.0.6 (X11/20050802) | 104
Mozilla
Thunderbird 1.0.6 (Windows/20050716) | 49
Mozilla
Thunderbird 1.0.2 (Windows/20050317) | 32
Debian
Thunderbird 1.0.2 (X11/20050602) | 30
Mozilla/5.0
(X11; U; Linux i686; ru-RU; rv:1.7.2) Gecko/20040808 | 15
Mozilla
Thunderbird 1.0.6 (X11/20050716) | 12
Mozilla
Thunderbird 1.0 (X11/20041206) | 11
Mozilla
Thunderbird 1.0.7 (X11/20051014) | 9
Mozilla
Thunderbird 1.0.7 (Windows/20050923) | 9
Debian
Thunderbird 1.0.2 (X11/20050331) | 8
Mozilla
Thunderbird 1.0 (Windows/20041206) | 8
SquirrelMail/1.4.4
| 7
Mozilla
Thunderbird 1.0.6 (Macintosh/20050716) | 7
Debian
Thunderbird 1.0.7 (X11/20051017) | 6
Opera M2/8.50
(Win32, build 7700) | 6
Mozilla
Thunderbird 1.0.7 (X11/20051010) | 5
KMail/1.8.2
| 4
Thunderbird
1.4 (Windows/20050908) | 4
Mozilla
Thunderbird 1.0.5 (Windows/20050711) | 3
Mozilla
Thunderbird 1.0.7 (X11/20051013) | 2
Thunderbird
1.5 (Windows/20051025) | 2
SquirrelMail/1.5.1
[CVS] | 2
SquirrelMail/1.4.5
| 2
Pan/0.14.2.91
(As She Crawled Across the Table (Debian GNU/Linux)) | 2
Mozilla
Thunderbird 1.0.7 (X11/20051031) | 2
Mozilla
Thunderbird 1.0.6 (X11/20050727) | 2
Mozilla
Thunderbird 1.0.6 (X11/20050826) | 2
SquirrelMail/1.4.3a
| 1
SquirrelMail/1.4.3a-12.EL4.centos4
| 1
Mozilla
Thunderbird 1.0.6 (X11/20050721) | 1
Mozilla/5.0
(X11; U; SunOS i86pc; en-US; rv:1.7) Gecko/20041221 | 1
Mozilla
Thunderbird 1.0.7 (Macintosh/20050923) | 1
Microsoft-Entourage/11.1.0.040913
| 1
Mozilla
Thunderbird 1.0.7 (X11/20051017) | 1
Mozilla
Thunderbird 1.0.6-1.4.1.centos4 (X11/20050721) | 1
Mozilla
Thunderbird 1.0.7 (X11/20050923) | 1
Mozilla
Thunderbird 1.0 (X11/20041207) | 1
Microsoft-Entourage/11.2.1.051004
| 1
(записей: 39)
Итак, мы получили распределение сообщений в
списке рассылки по MUA (точнее, по заголовку User-Agent). Запрос выполнился не
слишком быстро, что и не удивительно: для каждой строки пришлось вызывать
функцию разбора содержимого. Чтобы уменьшить время выполнения, можно создать
триггер на вставку записей с сообщениями и сохранять результаты mailheader в
отдельную проиндексированную таблицу. Тем самым за счет уменьшения времени
анализа сообщений мы получим увеличение времени, затрачиваемого на добавление
сообщений, – что важнее, решать администратору почтовой системы. Впрочем, здесь
из области администрирования почтового сервера мы переходим в область
администрирования баз данных вообще и администрирования PostgreSQL в частности
– последнему посвящен цикл статей Сергея Супрунова, уже публиковавшийся в нашем
журнале.
Shared folders
Трудно представить себе полноценный IMAP-сервер без
поддержки механизма shared folders, обеспечивающего совместный доступ различных
пользователей к общим каталогам с сообщениями. В DBMail поддерживаются:
n Системные общие каталоги в пространстве имен
#Public – настраиваются администратором почтового сервера.
n Личные общие каталоги в пространстве имен
#Users – настраиваются как администратором, так и владельцами
каталогов средствами MUA (при условии, что MUA поддерживают эту
функциональность).
Как мы уже выяснили, универсальный инструмент
администратора DBMail – это SQL-консоль выбранной им СУБД. Создадим системный
общий каталог News и предоставим доступ к нему пользователю test с помощью
этого инструмента. Сначала необходимо создать пользователя с именем __public__.
Мы уже создавали пользователя test с помощью dbmail-users, сделаем теперь то же
самое средствами SQL:
# psql -U
dbmail dbmail
dbmail=# insert
into dbmail_users (userid, passwd)
dbmail-# values
('__public__', 'abracadabra');
INSERT 0 1
dbmail=# select
user_idnr from dbmail_users where userid='__public__';
user_idnr
-----------
5
(1 запись)
Теперь создадим каталог News, владельцем которого
будет пользователь __public__:
# psql -U
dbmail dbmail
dbmail=# insert
into dbmail_mailboxes
dbmail=#
(owner_idnr, name, seen_flag, answered_flag, deleted_flag, flagged_flag,
dbmail=#
recent_flag, draft_flag, no_inferiors, no_select, permission)
dbmail-# values
(5, 'News', 1, 1, 1, 1, 1, 1, 0, 0, 2);
INSERT 0 1
dbmail=# select
mailbox_idnr from dbmail_mailboxes where name='News';
mailbox_idnr
--------------
7
(1 запись)
А теперь опишем права доступа для пользователя
test к этому каталогу:
# psql -U
dbmail dbmail
dbmail=# select
user_idnr from dbmail_users where userid='test';
user_idnr
-----------
3
(1 запись)
dbmail=# insert
into dbmail_acl
dbmail=#
(user_id, mailbox_id, lookup_flag, read_flag, seen_flag, write_flag,
dbmail=#
insert_flag, post_flag, create_flag, delete_flag, administer_flag)
dbmail-# values
(3, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1);
INSERT 0 1
Все, пользователю test осталось только
подписаться на каталог #Public/News средствами своего MUA. Впрочем, и это
тоже можно выполнить средствами SQL:
# psql -U
dbmail dbmail
dbmail=# select
user_idnr from dbmail_users where userid='test';
user_idnr
-----------
3
(1 запись)
dbmail=# select
mailbox_idnr from dbmail_mailboxes where name='News';
mailbox_idnr
--------------
7
(1 запись)
dbmail=# insert
into dbmail_subscription values (3, 7);
INSERT 0 1
Возможности перенаправления
почты
Мы не станем рассматривать эти возможности так же детально,
как и shared folders, т.к. общий принцип администрирования DBMail уже понятен.
Упомянем только таблицы, принимающие участие в перенаправлении почты:
n dbmail_aliases – в этой таблице каждому
почтовому адресу (или нескольким адресам) можно поставить в соответствие один
или несколько идентификаторов пользователей, уже заведенных в DBMail,
произвольных адресов и внешних программ, которые получат сообщение на stdin.
Перед именем программы должен быть символ «|» (в этом случае программа получит
сообщение в необработанном виде) или «!» (к сообщению будет добавлен
mbox-заголовок). Вместо непосредственного редактирования таблицы можно также
использовать утилиту dbmail-users (Примечание: примерно то же самое можно
сделать средствами MTA, но не всегда. Postfix, например, обрабатывает
собственную таблицу алиасов только в том случае, если в доставке принимает
участие его собственный MDA local. Это не самый эффективный способ доставки, и
при настройке DBMail во многих случаях предпочтительнее использовать LMTP).
n dbmail_auto_notifications – в этой
таблице для каждого пользователя DBMail можно указать несколько адресов, на
которые придут уведомления о получении пользователем сообщения. По умолчанию
такая функциональность отключена, чтобы ее включить, необходимо в файле
/etc/dbmail.conf в секции SMTP исправить значение параметра auto_notify с no на
yes.
n dbmail_auto_replies – в этой таблице для
каждого пользователя DBMail можно указать текст сообщения для автоматического
ответа на все приходящие сообщения. По умолчанию такая функциональность также
отключена, и чтобы ее включить, необходимо в файле /etc/dbmail.conf в секции
SMTP исправить значение параметра auto_reply с no на yes.
Использование описанных механизмов требует
аккуратного подхода, иначе очень легко получить зацикливание почты. Так я по
невнимательности указал для почтового пользователя в качестве адреса для
уведомлений один из его же алиасов. После этого вместо одного письма
пользователь получил около 500 сообщений в течение нескольких секунд на машине
с довольно скромной аппаратной конфигурацией. Прекращать это безобразие
пришлось вручную с помощью инструмента postsuper из комплекта Postfix.
Прочие возможности DBMail
К числу прочих возможностей почтового сервера, часто
востребованных администраторами, относятся:
n Квоты на размер почтового ящика –
поддерживаются в DBMail непосредственно: максимальный размер ящика можно
указать как при вызове утилиты dbmail-users ключом -m, так и изменив значение
поля maxmail_size в таблице dbmail_users.
n SMTP-авторизация – вообще-то это задача
MTA, но поскольку в DBMail уже хранится соответствие имен пользователей и их
паролей, есть смысл настроить SASL на использование этой информации.
n POP/IMAP before SMTP – это альтернатива
SMTP-авторизации, которая опирается на использование таблицы dbmail_pbsp и
должна быть включена в /etc/dbmail.conf параметрами pop_before-smtp/imap_before_smtp.
n SSL/TLS – DBMail не поддерживает этот
механизм непосредственно, но есть возможность организовать прозрачный с точки
зрения клиентов SSL-доступ с помощью внешнего ПО, например, stunnel – работа с
этим инструментом подробно рассматривалась в цикле статей Андрея Бешкова.
n Фильтрация почтовых сообщений на основании
их содержимого – эту задачу и способы ее решения мы обсудим позже.
Кроме того, DBMail не обошелся без
GUI-конфигуратора DbMail Administrator (DBMA), написанного на Perl и ориентированного
на веб. Он доступен на http://library.mobrien.com/dbmailadministrator
и выглядит так (см. рис. 3).

Рисунок 3. DbMail
Administrator
Есть еще один веб-интерфейс к DBMail – swiftMail
(http://www.obfuscatedcode.com/swiftmail/trac),
написанный на PHP. Его можно было бы отнести к классу webmail-приложений, если
бы не одна особенность: для чтения почты используется не POP3/IMAP, а прямой
доступ к БД DBMail. В настоящее время доступна альфа-версия swiftMail,
поддерживающая только MySQL. Поддержка PostgreSQL обещается в ближайшем
будущем.
Фильтрация почтовых сообщений
средствами DBMail
Общеизвестным преимуществом IMAP является то, что почтовый пользователь
может работать со своей и общей корреспонденцией с разных рабочих мест с
помощью совершенно различных MUA: как традиционных, так и ориентированных на
веб. Это означает, что правила, в соответствии с которыми сообщения распределяются
по каталогам IMAP, должны определяться не на уровне MUA, а на уровне MDA.
В настоящее время в DBMail отсутствуют штатные
способы решения этой задачи. В будущих версиях планируется использование
специализированного языка программирования для фильтрации почтовых сообщений
Sieve (описан в RFC 3028, активно используется в Cyrus IMAP), код поддержки
Sieve даже есть в текущей стабильной версии, но он не завершен и недостаточно
протестирован, поэтому при компиляции по умолчанию поддержка Sieve отключена.
Кроме того, для большинства случаев Sieve является слишком мощным инструментом.
Сформулируем, что нам требуется
от простейшего механизма фильтрации почтовых сообщений:
n Каждый пользователь может задать собственный
список фильтров и назначить их приоритеты.
n Фильтр представляет из себя соответствие
названия заголовка письма и его значения IMAP-каталогу, в который должно
попасть письмо.
n Письмо попадает в каталог, если значение
заголовка в письме содержит в себе значение заголовка в фильтре.
А теперь перечислим те способы
решения задачи, которые пришли мне в голову:
n Использование традиционных MDA (procmail,
maildrop) и dbmail-smtp.
n Использование фильтров MTA и патча для
поддержки RFC 3589 (Sieve Email Filtering – Subaddress Extension:
user+folder@server) в dbmail-lmtpd. Патч можно взять здесь – http://www.dbmail.org/mantis/bug_view_advanced_page.php?bug_id=0000057.
n Использование средств СУБД (триггеров) для
модификации записей, соответствующих сообщению, в БД.