Как настроить отправку почты через postfix в Битрикс24

Как настроить отправку почты через postfix в Битрикс24

По-умолчанию веб-окружение Битрикс24 использует msmtp для отправки почтовых сообщений. Преимущество такого решения — простота настройки. Недостаток — медленная отправка почтовых сообщений через внешние сервисы (Google, Yandex). В большинстве случаев, это не приводит к каким-либо проблемам, так как почтовые события отрабатывают из-под cron’a, но в ряде случаев это может создать проблему.

Почему так происходит?

Скорость отправки писем напрямую зависит от того, как настроена отправка почты в Битрикс24. На агентах или на хитах? А так же зависит от вида отправляемых писем. Например, отправка рассылок из CRM выполняется только на агентах — такие письма обрабатываются cron'ом по расписанию.

Если все агенты, которые выполняют получение и отправку писем исполняются на хитах (задан параметр немедленной доставки) или разработчик напрямую использует функцию mail(), то в этом случае она будет зависеть от активности сотрудников, которые работают на портале Битрикс24. Поэтому, если на портале отсутствует активность, рассылка писем будет выполняться достаточно медленно, при каждом хите сотрудника по несколько писем.
Переходить на Postfix имеет смысл если:
  • не устраивает низкая скорость отправки почты через msmtp
  • нужно настроить DKIM-подпись отправляемых писем
  • отправляемые письма не доходят до адресатов
  • У Битрикса в документации по веб-окружению есть инструкция по установке Postfix, но она почему-то не работает и вообще делает не совсем то, что нужно: Настройка Postfix для отправки почты.

    Разберем настройку отправки почтовых сообщений с помощью Postfix. Будем считать, что наш Битрикс24 развёрнут на домене example.com и в его MX-записях прописаны сервера Яндекса.

    Настраиваем Postfix

    Ставим необходимые пакеты.
    $ yum -y install postfix cyrus-sasl-plain
    
    Добавляем в /etc/postfix/canonical указание через какой аккаунт отправлять почту:
    # Слева - регулярное выражение, применяемое к отправителю
    # Справа - отправитель, которого нужно поставить
    /.+/ mail@example.com
    
    Добавляем в /etc/postfix/generic отправку почты админу на внешний ящик:
    # Слева - локальный пользователь
    
    # Справа - отправитель, которого нужно поставить
    root@localhost mail@example.com
    bitrix@localhost mail@example.com
    
    Добавляем в /etc/postfix/mailpasswd логин и пароль релей-хостов:
    # [SMTP_HOST]:SMTP_PORT SMTP_USER:SMTP_PASSWORD
    [smtp.yandex.ru] mail@example.com:SecretPassword*
    
    * в этом примере мы создаем учетную запись для аутентификации на Яндексе. При отправке писем от mail@example.com необходимо авторизоваться на сервере Яндекса от этой же учетной записи с паролем SecretPassword

    Добавляем в /etc/postfix/sender_relay привязку доменов и конкретных отправителей к внешним службам:
    # Слева - отправитель, справа - релей
    mail@example.com [smtp.yandex.ru]*
    
    *в этом примере мы все сообщения, отправляемые от домена example.com переправляем через сервер smtp.yandex.ru.

    Настройка значений From и Reply-To

    По-умолчанию Битрикс24 будет использовать в качестве отправителя адрес, заданный в настройках главного модуля. Но вот в карточках лидов, контактов и компаний система использует мейл текущего авторизованного пользователя. Заголовки, например:
    From: Иван Петров <i.petrov@example.com>
    To: Фёдор Сидоров <f.sidorov@example.com>
    
    В некоторых случаях это даже будет работать, но в основном нет. Такие сервисы, как Яндекс и Гугл блокируют отправку почты, если для авторизации SMTP используется один аккаунт, а в поле “From” стоит другое значение.

    Чтобы этого не происходило — можно настроить замену заголовка From на статичное значение, которое невозможно изменить из Битрикс24. Но неправильно просто затереть значение, которое там стояло - нужно оставить возможность пользователю ответить на отправленное ему письмо.

    Для этого у нас есть заголовок Reply-To. Но и это не все! При ответе пользователя на письмо, в качестве получателей будет подставляться два адреса (два поля Reply-To). Первый — сам отправитель, второй — технический адрес, с которого это письмо было отправлено. Сделаем, так чтобы технический адрес Postfix игнорировал и письмо отправлялось только его отправителю.

    Добавляем блок в /etc/postfix/header_checks:
    # Добавить в Reply-To значение, использованное в From
    /^From: (.*)/ PREPEND Reply-To: $1
    # Перезаписать From на значение по-умолчанию
    /^From: (.*)/ REPLACE From: mail@example.com
    # Удалить добавление технического адреса в ответном письме
    /^(Reply-To:.*)/ IGNORE
    
    Включаем обработку заголовков в /etc/postfix/main.cf:
    header_checks = regexp:/etc/postfix/header_checks
    
    Добавляем блок в /etc/postfix/main.cf:
    # Отключаем ipv6, потому что он толком не работает
    inet_protocols = ipv4
    
    # Указываем все письма отсылать через этот релей
    relayhost = [smtp.yandex.ru]
    
    # Включение аутентификации на стороне клиента
    $ smtp_sasl_auth_enable = yes
    # Указывает на файл, в котором хранится база связок логин/пароль
    $ smtp_sasl_password_maps = hash:/etc/postfix/mailpasswd
    
    # Опции SASL. noanonymous указывает на запрет анонимной аутентификации
    $ smtp_sasl_security_options = noanonymous
    # Задает плагин SASL для аутентификации
    $ smtp_sasl_type = cyrus
    # Перечисляет механизмы проверки пользователя и пароля
    $ smtp_sasl_mechanism_filter = login
    
    # Включает зависящую от отправителя аутентификацию, отключает кэширование SMTP-соединения
    $ smtp_sender_dependent_authentication = yes
    # Указание на список адресов и почтовых серверов, через которые нужно отправлять письма на эти адреса
    sender_dependent_relayhost_maps = hash:/etc/postfix/sender_relay
    # Добавляет для домена указание через какой аккаунт отправлять почту
    sender_canonical_maps = hash:/etc/postfix/canonical
    
    # Добавляет отправку почты админу на внешний ящик
    smtp_generic_maps = hash:/etc/postfix/generic
    # Указывает, использовать ли TLS для SMTP
    smtp_use_tls = yes
    
    Логи о неработающем IPv6 выглядят как-то так:
    Mar  5 19:48:28 MegaRoss-207-Krasnodar postfix/smtp[43577]: connect to smtp.gmail.com[2a00:1450:4010:c0b::6c]:587: Network is unreachable
    
    Mar  5 19:48:28 MegaRoss-207-Krasnodar postfix/smtp[43577]: 919BB1A3E6E: to=<user@example.com>, relay=none, delay=0.44, delays=0.02/0/0.43/0, dsn=4.4.1, status=deferred (connect to smtp.gmail.com[2a00:1450:4010:c0b::6c]:587: Network is unreachable)
    
    Редактируем параметр sendmail_path в /etc/php.d/bitrixenv.ini:
    # Удаляем работу через msmtp
    ; sendmail_path = msmtp -t -i
    # Добавляем работу через postfix
    sendmail_path = /usr/sbin/sendmail -t -i -f mail@example.com
    
    Генерируем индексированные файлы:
    $ postmap /etc/postfix/generic
    $ postmap /etc/postfix/canonical
    $ postmap /etc/postfix/mailpasswd
    $ postmap /etc/postfix/sender_relay
    
    Добавляем в автозагрузку и запускаем сервис:
    $ systemctl enable postfix
    $ systemctl start postfix
    

    Отправка тестового письма

    Выполняем из консоли следующую команду:
    $ echo "Test message" | mail -s "Test subject" user@example.com
    
    Смотрим логи, ищем фразу “status=sent”:
    $ tail /var/log/maillog
    Mar  6 10:33:43 MegaRoss-207-Krasnodar postfix/pickup[45768]: 24FD91A3E6F: uid=0 from=<root>
    Mar  6 10:33:43 MegaRoss-207-Krasnodar postfix/cleanup[46875]: 24FD91A3E6F: message-id=<20190306073343.24FD91A3E6F@megaross-207-krasnodar.ugtel.ru>
    Mar  6 10:33:43 MegaRoss-207-Krasnodar postfix/qmgr[45769]: 24FD91A3E6F: from=<mail@example.com>, size=478, nrcpt=1 (queue active)
    Mar  6 10:33:44 MegaRoss-207-Krasnodar postfix/smtp[46877]: 24FD91A3E6F: to=<user@example.com>, relay=smtp.yandex.ru[187.150.150.138]:25, delay=1.3, delays=0.03/0.01/0.33/0.89, dsn=2.0.0, <strong>status=sent</strong> (250 2.0.0 Ok: queued on smtp2o.mail.yandex.net as 1551857624-LUq73TrSs8-XhiW0rUr)
    Mar  6 10:33:44 MegaRoss-207-Krasnodar postfix/qmgr[45769]: 24FD91A3E6F: removed
    
    Поздравляем, тестовое письмо успешно отправлено! :)

    Настраиваем DKIM

    Переходим к настройке DKIM.

    DKIM (DomainKeys Identified Mail) — технология, которая борется с поддельными сообщениями. Для почтового домена генерируется пара ключей (открытый и закрытый). Закрытым ключом подписываются отправляемые сообщения. Открытый ключ добавляется на домене в качестве DNS в виде TXT-записи. Когда принимающий сервер находит в заголовке сообщения DKIM-подпись, он выполняет DNS-запрос к серверу домена на получение открытого ключа.

    Это нужно для массовой рассылки писем, так как наличие DKIM-подписи — обязательное условие для большинства почтовых провайдеров. Письма с отсутствием такой подписи скорее всего попадут в спам.

    С помощью этого ключа сервер определяет подлинность DKIM-подписи и решает, что делать с письмом. В зависимости от результатов проверки, письмо может быть принято, отклонено или отправлено в спам. При этом информация с результатами проверки добавляется в заголовок сообщения, которая в дальнейшем может быть использована антиспам фильтрами.

    Чтобы снизить вероятность попадания писем в спам (повысить доверие почтовых серверов к отправляемым письмам), настроим добавление подписи DKIM в заголовок. Ставим нужные пакеты:
    # Пакет opendkim-tools требуется для генерации ключей
    $ yum -y install opendkim opendkim-tools
    
    Генерируем ключи:
    $ opendkim-genkey -D /etc/opendkim/keys -d example.com -s default*
    
    * после выполнения команды в директории /etc/opendkim/ должны появится ключи (публичный и приватный) для домена example.com Смотрим результат:
    $ ls -alh /etc/opendkim/keys
    total 8,0K
    drwxr-x--- 2 opendkim opendkim  48 мар  4 15:24 .
    drwxr-xr-x 3 root     opendkim  74 мар  4 15:33 ..
    -rw-r----- 1 opendkim opendkim 887 мар  4 15:24 default.private
    -rw-r----- 1 opendkim opendkim 316 мар  4 15:24 default.txt
    
    Изменяем права на файлы и директории:
    $ chgrp opendkim /etc/opendkim/*
    $ chgrp opendkim /etc/opendkim/keys/*
    $ chmod g+r /etc/opendkim/keys/*
    $ gpasswd -a postfix opendkim
    
    Добавляем в автозагрузку и запускаем сервис:
    $ systemctl enable opendkim
    $ systemctl start opendkim
    
    Идём в настройки DNS домена и добавляем TXT-запись для поддомена default._domainkey, в содержимое ставим содержимое публичного ключа:
    $ cat /etc/opendkim/keys/default.txt 
    default._domainkey	IN	TXT	( "v=DKIM1; k=rsa; p=MIGfMA0GC5qGSIb3DQEBAQUAA4GNADCBiQKBgQDDW...JtXs1XbcZ6qHNJKXw1DAQAB" )  ; ----- DKIM key default for example.com
    
    Проверим, что всё работает:
    $ dig TXT default._domainkey.example.com
    ; <<>> DiG 9.10.3-P4-Ubuntu <<>> TXT default._domainkey.example.com
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50978
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    ;; QUESTION SECTION:
    ;default._domainkey.example.com. IN	TXT
    ;; ANSWER SECTION:
    default._domainkey.example.com. 599 IN	TXT	"v=DKIM1; k=rsa; p=MIGfMA0GC5qGSIb3DQEBAQUAA4GNADCBiQKBgQDDW...JtXs1XbcZ6qHNJKXw1DAQAB"
    ;; Query time: 94 msec
    ;; SERVER: 127.0.1.1#53(127.0.1.1)
    ;; WHEN: Wed Mar 06 10:40:22 MSK 2019
    ;; MSG SIZE  rcvd: 296
    [/bp_code]
    
    Добавляем блок в /etc/opendkim/KeyTable (одной строкой):
    [bp_code background=""]
    # Полное имя ключа - домен - селектор - путь к приватному ключу (одной строкой)
    default._domainkey.example.com example.com:default:/etc/opendkim/keys/default.private
    [/bp_code]
    
    Добавляем блок в /etc/opendkim/SigningTable:
    [bp_code background=""]
    # Какие домены - каким ключом подписывать
    *@example.com default._domainkey.example.com
    [/bp_code]
    
    И пишем в /etc/opendkim.conf:
    [bp_code background=""]
    # Режим работы - подписывать(signer)(s) и валидировать/контролировать(verified)(v)
    Mode	sv
    # Указываем список ключей
    KeyTable file:/etc/opendkim/keytable
    # Соответствие ключей и доменов
    SigningTable file:/etc/opendkim/signingtable
    [/bp_code]
    
    Укажем postfix’у использовать opendkim - добавляем блок в /etc/postfix/main.cf:
    [bp_code background=""]
    # Обработка ошибок при фильтрации писем до попадания сообщений в очередь 
    milter_default_action = accept
    # Версия протокола: 2 для 2.3 ≤ Postfix ≤ 2.5, 6 для Postfix ≥ 2.6
    milter_protocol = 2
    # Подписывать сообщения, полученные по SMTP с других серверов
    smtpd_milters = inet:127.0.0.1:8891
    # Подписывать сообщения, приходящие из sendmail
    non_smtpd_milters = inet:127.0.0.1:8891
    [/bp_code]
    
    Перезапускаем postfix и opendkim:
    [bp_code background=""]
    $ systemctl restart postfix
    $ systemctl restart opendkim
    [/bp_code]
    
    Проверяем работу - ищем в лог-файле почты строку “DKIM-Signature field added”:
    [bp_code background=""]
    $ tail -20 /var/log/maillog
    Mar  6 09:34:25 server1 postfix/pickup[29010]: 0A2AA407C6EA: uid=600 from=<bitrix24@example.com>
    Mar  6 09:34:25 server1 postfix/cleanup[29684]: 0A2AA407C6EA: prepend: header From: =?UTF-8?B?0JzQsNC60YHQuNC8INCU0L7RgNC+0YnQtdC90LrQvg==?= <user2@example.com> from local; from=<bitrix24@example.com>: Reply-To: =?UTF-8?B?0JzQsNC60YHQuNC8INCU0L7RgNC+0YnQtdC90LrQvg==?= <user2@example.com>
    Mar  6 09:34:25 server1 postfix/cleanup[29684]: 0A2AA407C6EA: message-id=<crm.activity.9434-0ZQRGV@bitrix24.example.com>
    Mar  6 09:34:25 server1 opendkim[23286]: 0A2AA407C6EA: DKIM-Signature field added (s=default, d=example.com)
    Mar  6 09:34:25 server1 postfix/qmgr[29011]: 0A2AA407C6EA: from=<bitrix24@example.com>, size=1282, nrcpt=2 (queue active)
    Mar  6 09:34:25 server1 postfix/smtp[29687]: 0A2AA407C6EA: to=<0123456@example.com>, relay=121.145.167.190[121.145.167.190]:25, delay=0.27, delays=0.1/0/0.12/0.05, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 44DkWP1dDJz3X8r)
    Mar  6 09:34:25 server1 postfix/smtp[29687]: 0A2AA407C6EA: to=<user2@example.com>, relay=121.145.167.190[121.145.167.190]:25, delay=0.27, delays=0.1/0/0.12/0.05, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 44DkWP1dDJz3X8r)
    Mar  6 09:34:25 server1 postfix/qmgr[29011]: 0A2AA407C6EA: removed
    

    Настраиваем DMARC

    Теперь перейдем к настройке записи DMARC. Это нужно, чтобы получатель мог быть уверен, что письмо с адреса durov@vk.com действительно отправил Павел Дуров, а не злоумышленник.

    DMARC (Domain-based Message Authentication, Reporting and Conformance) — политика обработки почтовых сообщений, основанная на SPF или DKIM аутентификации. С ее помощью администратор почты может самостоятельно определять, что делать с письмами, которые не прошли проверку доменом на сторонних серверах. Настраивается на домене путем добавления DNS в виде TXT-записи.

    В настройках домена, добавляем DNS-запись TXT для поддомена _dmarc.example.com с таким значением:
    v=DMARC1; p=quarantine
    
    Проверяем, что всё работает: $ dig TXT _dmarc.example.com ; <<>> DiG 9.10.3-P4-Ubuntu <<>> TXT _dmarc.example.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22795 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;_dmarc.example.com. IN TXT ;; ANSWER SECTION: _dmarc.example.com. 600 IN TXT "v=DMARC1; p=quarantine" ;; Query time: 52 msec ;; SERVER: 127.0.1.1#53(127.0.1.1) ;; WHEN: Wed Mar 06 10:40:55 MSK 2019 ;; MSG SIZE rcvd: 83 [/bp_code]

    Опциональная автоматизация настройки Postfix через ansible

    Практически всё можно автоматизировать. Мы используем ansible, вот ссылка на репозиторий
    Пользуйтесь:)
    Алексей Цывенко
    Алексей Цывенко
    Системный администратор