15 Октябрь 2017

Автоматическое конфигурирование клиентов электронной почты

Electronic mail client software automatic configuration

Электронная почта была и остаётся одним из основных практических применений возможностей Интернет. Для удобства работы с ней создано большое количество специализированных почтовых программ — клиентов. В целях облегчения настройки последних применяется ряд механизмов, позволяющих в автоматическом режиме получать и применять настройки подключения к обслуживающим данных адрес e-mail серверам.

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

1. Использование DNS

Использование DNS в качестве источника данных для настройки клиентского программного обеспечения, в том числе и для работы с электронной почтой, возможно используя специальный тип ресурсной записи SRV который описывается стандартом RFC2782. Посредством неё указывается порт и имя сервера, который используется данным доменом для обслуживания того или иного сервиса, а также задать их приоритеты.

К примеру, для используемых почтовых адресов в домене my.server набор SRV записей может выглядеть следующим образом.

root@beta:/usr/local/etc/nsd # grep SRV zones/my.server/my.server.zone
_imap._tcp              IN SRV  10 0 143 imap.my.server.
_imaps._tcp             IN SRV   0 0 993 imap.my.server.
_pop3._tcp              IN SRV  20 0 110 pop.my.server.
_pop3s._tcp             IN SRV  10 0 995 pop.my.server.
_smtp._tcp              IN SRV  10 0 25  smtp.my.server.
_smtps._tcp             IN SRV   0 0 465 smtp.my.server.
_submission._tcp        IN SRV   0 0 587 smtp.my.server.

Первое число в каждой строке означает приоритет данного сервиса для соединения, а второе — вес для равных приоритетов. В данном случае наивысший прироритет будет отдаваться защищённым SSL/TLS соединениям по протоколам IMAP и SMTP. Третьим числом является, как нетрудно заметить, порт для подключения, а сразу же после него имя сервера.

Таким образом, обратившись к DNS по доменному имени формата _servicename._tcp.my.server можно получить искомое значение настроек.

Автору представляется, что именно этот способ построенный на использовании DNS должен использоваться в качестве основного как наиболее стандартизированный, простой и универсальный. Однако, как правило, на практике клиенты электронной почты используют свои собственные методы автоматического получения настроек.

2. Mozilla way

Свой путь для получения автоматических настроек для популярного клиента Thunderbird выбрал разрабатывающий его проект Mozilla. В данном случае предполагается, что поставщик услуг электронной почты размещает специальный файл с необходимой для конфигурирования информации в формате XML. Подробное описание механизма содержится в документе "Autoconfiguration in Thunderbird".

Доступ к настройкам осуществляется по протоколу HTTP. В первую очередь опрашивается хост с именем, получаемым добавлением суффикса autoconfig к доменной части почтового адреса, а в случае неудачи непосредственно к хосту с доменным именем (напомню, что в нашем случае это my.server) к файлу config-v1.1.xml.

Со стороны веб-сервера это выглядит следующим образом (в данном случае приведена выдержка из лог-файла веб-сервера H2O).

grep autodiscover /var/log/h2o/h2o-access.log
...
1.2.3.4 my.server:80 - - [13/Oct/2017:20:12:19 +0200] "GET /mail/config-v1.1.xml?emailaddress=foo@my.server HTTP/1.1" 404 9 "-" "-"
1.2.3.4 autoconfig.my.server:80 - - [13/Oct/2017:20:12:20 +0200] "GET /.well-known/autoconfig/mail/config-v1.1.xml HTTP/1.1" 200 979 "-" "-"
...

Обратите внимание, что данные обращения производятся по-разному, как в части передачи адреса e-mail в качестве параметра, так и в части пути размещения искомого файла. В первом случае предполагается наличие обработчика отправляемого в URL адреса на стороне сервера. Во втором же, с суффиксом autoconfig, простая возврат специально оформленного файла конфигурации, который может иметь такой вид.

root@beta: # cat /usr/local/www/my.server/.well-known/autoconfig/mail/config-v1.1.xml
<?xml version="1.0" encoding="UTF-8"?>
<clientConfig version="1.1">
        <emailProvider id="my.server">
                <domain>my.server</domain>
                <displayName>Почта my.server</displayName>
                <displayShortName>my.server</displayShortName>
                <incomingServer type="imap">
                        <hostname>imap.my.server</hostname>
                        <port>993</port>
                        <socketType>SSL</socketType>
                        <authentication>password-cleartext</authentication>
                        <username>%EMAILADDRESS%</username>
                </incomingServer>
                <incomingServer type="pop">
                        <hostname>pop.my.server</hostname>
                        <port>995</port>
                        <socketType>SSL</socketType>
                        <authentication>password-cleartext</authentication>
                        <username>%EMAILADDRESS%</username>
                </incomingServer>
                <outgoingServer type="smtp">
                        <hostname>smtp.my.server</hostname>
                        <port>587</port>
                        <socketType>SSL</socketType>
                        <authentication>password-cleartext</authentication>
                        <username>%EMAILADDRESS%</username>
                </outgoingServer>
                <documentation url="https://my.server/faq.html">
                        <descr lang="ru">Часто задаваемые вопросы</descr>
                        <descr lang="en">Frequently Asked Questions</descr>
                </documentation>
                <webMail>
                        <loginPage url="https://webmail.my.server/" />
                </webMail>
        </emailProvider>
</clientConfig>

Обратите внимание на использование специальной маски %EMAILADDRESS%, которая сообщает клиенту о необходимости использования в качестве логина адреса электронной почты. Для варианта применения локальной части имеется маска %EMAILLOCALPART%.

И, разумеется, следует не забыть добавить соответствующий поддомен в DNS-зону, например в виде записи CNAME.

root@beta:~ # cd /usr/local/etc/nsd/
root@beta:/usr/local/etc/nsd # grep autoconfig zones/my.server/my.server.zone
autoconfig              IN CNAME my.server.

3. Microsoft way

Почтовые клиенты Microsoft для получения автоматических настроек используют комплексный многоэтапный подход, который подробно описывается в документе "Plan to automatically configure user accounts in Outlook 2010".

Наиболее интересной его частью является стадия обращения веб-серверу за получением специально сформированного файла с настройками в XML.

Важно понимать, что обращение производится, во-первых, исключительно по защищённому протоколу HTTPS, а, во-вторых, это делается HTTP-методом POST (а не GET).

При этом в передаваемом на сервер запросе содержится XML-оформленный адрес электронной почты в следующем формате.

<?xml version="1.0" encoding="utf-8"?>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
  <Request>
    <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
    <EMailAddress>foo@my.server</EMailAddress>
  </Request>
</Autodiscover>

Данный запрос должен быть обработан на стороне сервера и в ответ предоставлены данные для автоматической настройки клиентского приложения и детали механизма аутентификации и доступа к ним.

Типичный ответ на него может выглядеть следующим образом.

<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
<User>
<DisplayName>my.service</DisplayName>
</User>
<Account>
<AccountType>email</AccountType>
<Action>settings</Action>
<Image>https://my.service/favicon.png</Image>
<ServiceHome>https://my.service</ServiceHome>
<Protocol>
<Type>IMAP</Type>
<Server>imap.my.service</Server>
<Port>993</Port>
<LoginName>foo@my.server</LoginName>
<AuthRequired>on</AuthRequired>
<DomainRequired>off</DomainRequired>
<SPA>off</SPA>
<SSL>on</SSL>
</Protocol>
<Protocol>
<Type>POP</Type>
<Server>pop.my.service</Server>
<Port>995</Port>
<LoginName>foo@my.server</LoginName>
<AuthRequired>on</AuthRequired>
<DomainRequired>off</DomainRequired>
<SPA>off</SPA>
<SSL>on</SSL>
</Protocol>
<Protocol>
<Type>SMTP</Type>
<Server>smtp.my.service</Server>
<Port>465</Port>
<LoginName>foo@my.server</LoginName>
<AuthRequired>on</AuthRequired>
<DomainRequired>off</DomainRequired>
<SPA>off</SPA>
<SSL>on</SSL>
</Protocol>
</Account>
</Response>
</Autodiscover>

Начальное обращение клиента за настройками производится по URL где в качестве доменного имени также, как и в случае с Thunderbird, используется доменная часть адреса электронной почты, а при неудаче к нему добавляется префикс с именем autodiscover к файлу autodiscover.xml.

grep autodiscover /var/log/h2o/h2o-access.log
...
1.2.3.4 my.server:443 - - [13/Oct/2017:20:10:39 +0200] "POST /autodiscover/autodiscover.xml HTTP/1.1" 404 9 "-" "-"
1.2.3.4 autodiscover.my.server:443 - - [13/Oct/2017:20:10:40 +0200] "POST /autodiscover/autodiscover.xml HTTP/1.1" 200 979 "-" "-"
...

Это позволяет вынести функции рассылки файлов автоконфигурирования на отдельный адрес или даже сервер. Более того, используя специальный вид _autodiscover описанной в предыдущем разделе этой статьи записи SRV можно указать любой другой хост в качестве такого источника.

root@beta:/usr/local/etc/nsd # host -t SRV _autodiscover._tcp.my.server
_autodiscover._tcp.my.server has SRV record 0 0 443 foo.other.server.

Тогда при неудачном доступе по двум предыдущим адресам обращение будет произведено уже к хосту foo.other.server.

Очевидно, что реализация такого подхода к получению настроек для клиента электронной почты требует наличие обработчика на стороне сервера. В качестве варианта рассмотрим реализацию такого механизма на базе того же веб-сервера H2O и бэкэнда на PHP.

root@beta:/usr/local/etc/nsd # h2o -v
h2o version 2.2.2
OpenSSL: OpenSSL 1.0.2k-freebsd  26 Jan 2017
mruby: YES
root@beta:/usr/local/etc/nsd # php -v
PHP 7.1.10 (cli) (built: Sep 29 2017 09:17:09) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies

Простейший скрипт, назовём его autodiscover.php для генерации корректного файла настроек может выглядеть так.

root@beta:/usr/local/etc/nsd # cat /usr/local/www/my.server/autodiscover/autodiscover.php
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
        $email = array();
        preg_match('/<EMailAddress>(.*)<\/EMailAddress>/', file_get_contents('php://input'), $email);
        header('Content-Type: application/xml');
        echo '<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
<User>
<DisplayName>my.service</DisplayName>
</User>
<Account>
<AccountType>email</AccountType>
<Action>settings</Action>
<Image>https://my.service/favicon.png</Image>
<ServiceHome>https://my.service</ServiceHome>
<Protocol>
<Type>IMAP</Type>
<Server>imap.my.service</Server>
<Port>993</Port>
<LoginName>' . $email[1] .'</LoginName>
<AuthRequired>on</AuthRequired>
<DomainRequired>off</DomainRequired>
<SPA>off</SPA>
<SSL>on</SSL>
</Protocol>
<Protocol>
<Type>POP</Type>
<Server>pop.my.service</Server>
<Port>995</Port>
<LoginName>' . $email[1] .'</LoginName>
<AuthRequired>on</AuthRequired>
<DomainRequired>off</DomainRequired>
<SPA>off</SPA>
<SSL>on</SSL>
</Protocol>
<Protocol>
<Type>SMTP</Type>
<Server>smtp.my.service</Server>
<Port>465</Port>
<LoginName>' . $email[1] .'</LoginName>
<AuthRequired>on</AuthRequired>
<DomainRequired>off</DomainRequired>
<SPA>off</SPA>
<SSL>on</SSL>
</Protocol>
</Account>
</Response>
</Autodiscover>
';
} else {
        header($_SERVER['SERVER_PROTOCOL']." 405 Method Not Allowed");
}
?>

Здесь производится извлечение адреса электронной почты из начального HTTP POST-запроса и его подстановка в соответствующее поле ответа.

На стороне веб-сервера также необходимо реализовать переадресацию обращений к файлу autodiscover.xml на наш скрипт.

root@beta:/usr/local/etc/nsd # cat /usr/local/etc/h2o/h2o.conf
# see https://h2o.examp1e.net/ for detailed documentation
# see h2o --help for command-line options and settings
...
    "my.server:443":
        listen:
            port: 443
            ssl:
                 <<: *default_ssl
                 certificate-file: /usr/local/etc/letsencrypt/live/my.server/fullchain.cur.pem
                 key-file: /usr/local/etc/letsencrypt/live/my.server/privkey.cur.pem
        paths:
            "/":
                file.dir: /usr/local/www/my.server
...
            "/autodiscover/autodiscover.xml":
                redirect:
                    url: /autodiscover/autodiscover.php
                    internal: YES
                    status: 307
...

4. Apple way

Автоматическое конфигурирование в продуктах производства Apple, в том числе и настройка клиентов электронной почты, осуществляется через их стандартный механизм конфигурационных профилей, которые описаны в документе "Configuration Profile Reference".

В отличие от предыдущих способов, сам клиент не инициирует соединение для получения настроек. Это необходимо сделать вручную перейдя, например, по предоставленной ссылке, которая предоставляет для пользователя специальную веб-форму для ввода необходимой информации для идентификации его учётной записи, как правило это адрес электронной почты. После отправки данных сервер предоставить информацию о конфигурации. При этом ответ должен, во-первых, иметь расширение .mobileconfig, а, во-вторых, иметь тип данных (MIME или, в случае с HTTP, заголовок Content-type) application/x-apple-aspen-config.

Формат файла настроек описан в вышеупомянутом документе, однако наиболее простым способом получить шаблон под конкретные настройки будет использование утилиты iPhone Configuration Utility (версия для Windows) введя в качестве адреса e-mail, к примеру, строку %EMAIL% для дальнейшей обработки на стороне сервера. В итоге будет получен аналогичный файл.

root@beta:/usr/local/etc/nsd # cat /usr/local/my.server/.well-known/autoconfig/mail/mail.mobileconfig
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>PayloadContent</key>
        <array>
                <dict>
                        <key>EmailAccountDescription</key>
                        <string>my.server</string>
                        <key>EmailAccountType</key>
                        <string>EmailTypeIMAP</string>
                        <key>EmailAddress</key>
                        <string>%EMAIL%</string>
                        <key>IncomingMailServerAuthentication</key>
                        <string>EmailAuthNone</string>
                        <key>IncomingMailServerHostName</key>
                        <string>imap.my.server</string>
                        <key>IncomingMailServerPortNumber</key>
                        <integer>993</integer>
                        <key>IncomingMailServerUseSSL</key>
                        <true/>
                        <key>IncomingMailServerUsername</key>
                        <string>%EMAIL%</string>
                        <key>OutgoingMailServerAuthentication</key>
                        <string>EmailAuthPassword</string>
                        <key>OutgoingMailServerHostName</key>
                        <string>smtp.my.server</string>
                        <key>OutgoingMailServerPortNumber</key>
                        <integer>587</integer>
                        <key>OutgoingMailServerUseSSL</key>
                        <true/>
                        <key>OutgoingMailServerUsername</key>
                        <string>%EMAIL%</string>
                        <key>OutgoingPasswordSameAsIncomingPassword</key>
                        <true/>
                        <key>PayloadDescription</key>
                        <string>Configures email account.</string>
                        <key>PayloadDisplayName</key>
                        <string>my.server</string>
                        <key>PayloadIdentifier</key>
                        <string>my.server.email</string>
                        <key>PayloadOrganization</key>
                        <string></string>
                        <key>PayloadType</key>
                        <string>com.apple.mail.managed</string>
                        <key>PayloadUUID</key>
                        <string>B06E534B-52F9-42A9-8CCF-8B7D43329DBD</string>
                        <key>PayloadVersion</key>
                        <integer>1</integer>
                        <key>PreventAppSheet</key>
                        <false/>
                        <key>PreventMove</key>
                        <false/>
                        <key>SMIMEEnabled</key>
                        <false/>
                        <key>disableMailRecentsSyncing</key>
                        <false/>
                </dict>
        </array>
        <key>PayloadDescription</key>
        <string>Настройка почты my.server</string>
        <key>PayloadDisplayName</key>
        <string>my.server</string>
        <key>PayloadOrganization</key>
        <string>my.server</string>
        <key>PayloadRemovalDisallowed</key>
        <false/>
        <key>PayloadType</key>
        <string>Configuration</string>
        <key>PayloadUUID</key>
        <string>067B85DD-A7E0-470A-B791-65979457742D</string>
        <key>PayloadVersion</key>
        <integer>1</integer>
</dict>
</plist>

Теперь вновь воспользовавшись PHP напишем обработчик запросов для устройств Apple. Заметьте, что он поддерживает обращение как HTTP методом GET, так и методом POST.

root@beta:/usr/local/etc/nsd # cat /usr/local/my.server/.well-known/autoconfig/mail/mobileconfig.php
<?php
if (isset($_REQUEST['email'])) {
        $conf = str_replace('%EMAIL%', $_REQUEST['email'], file_get_contents('mail.mobileconfig'));
        header('Content-type: application/x-apple-aspen-config; chatset=utf-8');
        header('Content-Disposition: attachment; filename="my.server.mobileconfig"');
        print $conf;
} else {
        echo '<html>
        <head>
                <title>Автоматическая настройка почты my.server</title>
                <meta name="viewport" content="width=device-width; initial-scale=1; user-scalable=no" />
        </head>
        <body>
                <form method="post" action="apple">
                        <p style="text-align: center">
                                Введите адрес электронной почты для получения настроек для my.server<br/><br/><br/>
                                <input type="email" name="email" style="height: 30px; width: 250px;"/><br/><br/>
                                <input type="submit" value="Отправить" style="height: 30px; width: 100px;"/>
                        </p>
                </form>
        </body>
</html>';
}
?>

Вызов осуществляется путём предоставления клиенту URL формата http://my.server/apple при переходе по которому у пользователя откроется простая форма с полем ввода адреса электронной почты после отправки которого на устройство будет загружен файл конфигурации my.server.mobileconfig со всеми необходимыми параметрами. Если же для данного пользователя заранее известен его e-mail, то через предоставление ему ссылки формата http://my.server/apple?email=foo@my.server он будет избавлен от ручного ввода адреса e-mail и настройки будут сразу же загружены.

Обработка обращений на стороне веб-сервера H2O эмулируется аналогичным примеру из раздела 3 настоящей статьи методом.

root@beta:/usr/local/etc/nsd # cat /usr/local/etc/h2o/h2o.conf
# see https://h2o.examp1e.net/ for detailed documentation
# see h2o --help for command-line options and settings
...
    "my.server:443":
        listen:
            port: 443
            ssl:
                 <<: *default_ssl
                 certificate-file: /usr/local/etc/letsencrypt/live/my.server/fullchain.cur.pem
                 key-file: /usr/local/etc/letsencrypt/live/my.server/privkey.cur.pem
        paths:
            "/":
                file.dir: /usr/local/www/my.server
...
            "/apple":
                redirect:
                    url: /.well-known/autoconfig/mail/mobileconfig.php
                    internal: YES
                    status: 307
...

Также в целях обеспечения большей безопасности профиль конфигурации Apple может быть подписан цифровой подписью используя, к примеру, уже выпущенный для веб-сервера SSL-сертификат.

5. PROFIT!

Статья была полезной? Тогда прошу не стесняться и поддерживать деньгами через PayPal, Яндекс.Деньги или через замечательную систему Patreon.


php  html  DNS  H2O  HTTP