Здравствуйте!Появилась задача настроить Exim так, чтобы в одной группе письма распределялись получателям последовательно - первое письмо - первому в группе, второе - второму и т.д.
В БД создал таблицу - id(порядковый номер),address(e-mail),is_current(должен получить текущее письмо)
Попросите менеджера уточнить ТЗ и бюджет.
Разработка нового функционала почтовика может дорого обойтись.
> Появилась задача настроить Exim так, чтобы в одной группе письма распределялись получателям
> последовательно - первое письмо - первому в группе, второе - второму
> и т.д.Звучит как бред, поэтому может быть, объясните, чего именно желаете добиться таким странным способом?
>> Появилась задача настроить Exim так, чтобы в одной группе письма распределялись получателям
>> последовательно - первое письмо - первому в группе, второе - второму
>> и т.д.
> Звучит как бред, поэтому может быть, объясните, чего именно желаете добиться таким
> странным способом?Юзкейс элементарный: скажем отдача заказов в интернет магазине манагерам по очереди.
> Юзкейс элементарный: скажем отдача заказов в интернет магазине манагерам по очереди.Для таких задач давно придумали Message Queue. А почта это не самый удобный инструмент для отслеживания событий.
> Юзкейс элементарный: скажем отдача заказов в интернет магазине манагерам по очереди.Да, что-то вроде, нужно равномерно загружать менеджеров.
С телефонией на астериске никаких проблем нет - там это стандартный функционал.
А вот в почте что-то никак.
Есть мысль использовать router и queryprogram для конктретного адреса, типа zakaz@company.ru
>> Юзкейс элементарный: скажем отдача заказов в интернет магазине манагерам по очереди.
> Да, что-то вроде, нужно равномерно загружать менеджеров.
> С телефонией на астериске никаких проблем нет - там это стандартный функционал.
> А вот в почте что-то никак.Боюсь, что реализовать такое средствами smtp-сервера (без написания собственных обработчиков почтовой очереди) будет немножко сложно.
Можно попробовать извратиться через агентов доставки типа procmail или maildrop, но за успех такого предприятия лично я не поручусь.
>> Юзкейс элементарный: скажем отдача заказов в интернет магазине манагерам по очереди.
> Да, что-то вроде, нужно равномерно загружать менеджеров.
> С телефонией на астериске никаких проблем нет - там это стандартный функционал.Сравним дак сравнил ....
> А вот в почте что-то никак.
> Есть мысль использовать router и queryprogram для конктретного адреса, типа zakaz@company.ruВыгребай ящик консольным почтовым клиентом и далее делай с письмом что хочешь. Вернее куда очередная шиза заведет если уж так хочется.
> С телефонией на астериске никаких проблем нет - там это стандартный функционал.Телефония на астериске, если менеджер не пришел/заболел/курит, отправит звонок другому. Вы же загоните письмо одному человеку, не зная, прочтет он его или нет - хоп и минус клиент.
>>> Появилась задача настроить Exim так, чтобы в одной группе письма распределялись получателям
>>> последовательно - первое письмо - первому в группе, второе - второму
>>> и т.д.
>> Звучит как бред, поэтому может быть, объясните, чего именно желаете добиться таким
>> странным способом?
> Юзкейс элементарный: скажем отдача заказов в интернет магазине манагерам по очереди.Вам нужна ERP/CRM, а не почта.
DeadMorose не слушайте весь этот бред про доработку exim, или установку CRM. Все решается значительно проще - через конфиг exim (весь необходимый функционал уже есть)Детально прорабатывать команды я не буду (сами справитесь). Предлагаю общую идею.
Таблица - id(порядковый номер),address(e-mail),is_current(должен получить текущее письмо) подойдет.
1) Потребуется создать новый транспорт. Например:delivery_rr:
driver = pipe
command = /usr/sbin/dovecot/deliver -d "${lookup sqlite \
{SELECT address FROM table WHERE is_current=1;}}"
log_output = true
return_output = false
delivery_date_add = true
envelope_to_add = true
return_path_add = trueРазмещение этого блока в секции "begin transports" значения не имеет.
Я использую Dovecot deliver в качестве LDA. Доставку легко можно изменить на Exim LDA (сами справитесь)
2) Создаем роутер для получателя mail_rr@domain.com:round_robin:
driver = accept
domains = +local_domains
local_parts = mail_rr
condition = ${lookup sqlite {UPDATE table SET is_current=1 WHERE bla_bla;} {yes} {yes}}
condition = ${lookup sqlite {UPDATE table ........} {yes} {yes}}
transport = delivery_rr
no_verify
no_moreЭтот роутер нужно разместить в секции "begin routers" непосредственно ПЕРЕД финальной доставкой почты (обычно local_user), т.к. для роутеров порядок имеет значение
Т.к. роутеры на этапе приема запускаются дважды (при проверке и при доставке) мы указываем no_verify (не запускать при проверке), что-бы исключить двойное срабатывание.
После срабатывания этого роутера нормальная (local_user) доставка уже не нужна - используем no_more
Самое интересноеcondition = ${lookup sqlite {UPDATE table SET is_current=1 WHERE bla_bla;} {yes} {yes}}
condition = ${lookup sqlite {UPDATE table ........} {yes} {yes}}
Это по логике - условие для срабатывания роутера. НО, финальные {yes} {yes} делают эти условия всегда истинными. Таким образом здесь по сути не проверяются условия, а исполняются SQL манипуляции над базой.Таких condition = ${lookup sqlite {SQL statement} {yes} {yes}} в роутере может быть много
Сделать циклический перебор поля is_current=1 после каждого срабатывания роутера (т.е. доставки) в таблице средствами SQL надеюсь сами сможете
Небольшое добавлениеТ.к. роутер round_robin мы исключили из предварительной проверки при получении, то в этом случае сработает проверка в local_user. А там проверяется физическое наличие почтового ящика. Т.е. у пользователя, для которого организуется циклическая пересылка (в нашел случае mail_rr@domain.com), обязательно должен быть локальный почтовый ящик (в него ни чего не будет попадать, но быть он должен)
> Небольшое добавление
> Т.к. роутер round_robin мы исключили из предварительной проверки при получении, то в
> этом случае сработает проверка в local_user. А там проверяется физическое наличие
> почтового ящика. Т.е. у пользователя, для которого организуется циклическая пересылка
> (в нашел случае mail_rr@domain.com), обязательно должен быть локальный почтовый ящик (в
> него ни чего не будет попадать, но быть он должен)а для чего он тогда? протсо потому что так должно быть ?
>[оверквотинг удален]
> condition = ${lookup sqlite {UPDATE table ........} {yes} {yes}}
> transport = delivery_rr
> no_verify
> no_more
> Этот роутер нужно разместить в секции "begin routers" непосредственно ПЕРЕД финальной доставкой
> почты (обычно local_user), т.к. для роутеров порядок имеет значение
> Т.к. роутеры на этапе приема запускаются дважды (при проверке и при доставке)
> мы указываем no_verify (не запускать при проверке), что-бы исключить двойное срабатывание.
> После срабатывания этого роутера нормальная (local_user) доставка уже не нужна - используем
> no_moreСделал по аналогии с system_aliases
roundrobin_aliases:
driver = redirect
allow_fail
allow_defer
data = ${lookup mysql{servers=post.******.ru; SELECT rrAliasAddress('${quote_mysql:$local_part@${domain}}')}{$value}fail}
headers_remove = "Subject"
headers_add = "Subject: $h_subject ${lookup mysql{SELECT address FROM rrAddresses WHERE id = (SELECT lastAddressId FROM rrAliases WHERE alias = '${local_part}@${domain}')}}"
user = mailnull
group = mail
file_transport = address_file
pipe_transport = address_pipe
skip_syntax_errors
no_verifyЗдесь rrAliasAddress - хранимая функция на сервере MySQL, в которой и происходит перебор адресов
Кроме того, потребовалось добавить пользователей, которые всегда получают такие письма (ответственные за конкретные задачи), и соответственно пришлось добавлять в заголовок инфу о том, кто конкретно получил письмо
CREATE DEFINER=`mail_admin`@`%` FUNCTION `rrAliasAddress`(rrAlias VARCHAR(128)) RETURNS varchar(128) CHARSET utf8
BEGIN
DECLARE aliasAddress VARCHAR(128);
DECLARE StaticUsers VARCHAR(256);
DECLARE curraliasId INT;
DECLARE nextAddressId INT;
DECLARE currAddressId INT;
SET aliasAddress = (SELECT `address` FROM `rrAddresses` WHERE `id` = (SELECT `currentAddressId` FROM `rrAliases` WHERE `alias` = rrAlias));
IF (aliasAddress IS NULL) THEN
SET aliasAddress = '';
ELSE
SET curraliasId = (SELECT `id` FROM `rrAliases` WHERE `alias` = rrAlias);
SET currAddressId = (SELECT `currentAddressId` FROM `rrAliases` WHERE `id` = curraliasId);
SET nextAddressId = (SELECT MIN(`id`) FROM `rrAddresses` WHERE ((`aliasId` = curraliasId) AND (`id` > currAddressId)));
IF (nextAddressId IS NULL) THEN
SET nextAddressId = (SELECT MIN(`id`) FROM `rrAddresses` WHERE `aliasId` = curraliasId);
END IF;
UPDATE `rrAliases` SET `currentAddressId` = nextAddressId, `lastAddressId` = currAddressId WHERE `id` = curraliasId;
END IF;
SET StaticUsers = (SELECT `userlist` FROM `rrStaticUsers` WHERE `id` = curraliasId);
IF (StaticUsers IS NOT NULL) THEN
SET aliasAddress = concat_ws(',', StaticUsers, aliasAddress);
end if;
RETURN aliasAddress;
ENDСозданы 3 таблицы:
rrAliases -
id int(11) AI PK - идентификатор списка рассылки (1,2,3..... )
alias varchar(128) - адрес списка рассылки (типа sales@ourcompany.ru) обязательно должен существовать и не быть пустым!
currentAddressId int(11) - идентификатор получателя следующего письма
lastAddressId int(11) - идентификатор получателя предыдущего письмаrrAddresses -
id int(11) AI PK - идентификатор получателя (нумерация сквозная для всех списков)
aliasId int(11) - идентификатор списка рассылки
address varchar(128) - e-mail получателяrrStaticUsers -
id int(11) PK - идентификатор списка рассылки
userlist varchar(256) - список "руководителей", через запятую
> Появилась задача настроить Exim так, чтобы в одной группе письма распределялись получателям
> последовательно - первое письмо - первому в группе, второе - второму
> и т.д.
> В БД создал таблицу - id(порядковый номер),address(e-mail),is_current(должен получить
> текущее письмо)В Exim это делается элементарно в одностроковое выражение или в несколько строк роутером redirect.
Всё таки Тьюринг-полный язык под капотом.