Русский
Русский
English
Статистика
Реклама

Imap

Настройка Gmail API для замены расширения PHP IMAP и работы по протоколу OAuth2

25.08.2020 12:13:42 | Автор: admin
Оказавшись одним из счастливчиков, совершенно не готовым к тому, что с 15 февраля 2021 года авторизация в Gmail и других продуктах будет работать только через OAuth, я прочитал статью "Google хоронит расширение PHP IMAP" и загрустил начал предпринимать действия по замене расширения PHP IMAP в своём проекте на API Google. Вопросов было больше, чем ответов, поэтому заодно нацарапал мануал.

У меня PHP IMAP используется для следующих задач:
  1. Удаление старых писем из почтовых ящиков. К сожалению, в панели управления корпоративным аккаунтом G Suite можно настроить только срок удаления писем из всех почтовых ящиков организации через N дней после получения. Мне же требуется удалять письма только в заданных почтовых ящиках и через заданное разное количество дней после получения.
  2. Фильтрация, разбор и маркировка писем. С нашего сайта в автоматическом режиме отправляется множество писем, некоторые из которых не доходят до адресатов, о чём, соответственно, приходят отчёты. Нужно эти отчёты отлавливать, разбирать, находить клиента по email и формировать человекочитаемое письмо для менеджера, чтобы тот связался с клиентом и уточнил актуальность адреса электронной почты.


Эти две задачи мы и будем решать при помощи API Gmail в данной статье (а заодно и отключим в настройках почтовых ящиков доступ для небезопасных приложений, который был включён для работы PHP IMAP, и, собственно, перестанет работать в страшный день в феврале 2021). Использовать будем так называемый сервисный аккаунт приложения Gmail, который при соответствующей настройке даёт возможность подключения ко всем почтовым ящикам организации и выполнения в них любых действий.

1. Создаём проект в консоли разработчика Google API


При помощи этого проекта мы и будем осуществлять API-взаимодействие с Gmail, и в нём же создадим тот самый сервисный аккаунт.
Для создания проекта:
  1. Переходим в консоль разработчика Google API и логинимся по администратором G Suite (ну или кто у Вас там пользователь со всеми правами)
  2. Ищем кнопку Создать проект.
    Я нашёл здесь:
    image

    И затем здесь:
    image


    Заполняем имя проекта и сохраняем
    Создание проекта
    image

  3. Переходим к проекту и нажимаем кнопку Включить API и сервисы
    Включить API и сервисы
    image

    Выбираем Gmail API


2. Создаём и настраиваем сервисный аккаунт


Для этого можно воспользоваться официальным мануалом или продолжить чтение:
  1. Переходим в наш добавленный Gmail API, нажимаем кнопку Создать учётные данные и выбираем Сервисный аккаунт
    Создание сервисного аккаунта
    image


    Что-нибудь заполняем и нажимаем Создать
    Сведения о сервисном аккаунте
    image


    Всё остальное можно не заполнять
    Права доступа для сервисного аккаунта
    image

    Предоставление пользователям доступа к сервисному аккаунту
    image

  2. Далее, сервисному аккаунту нужно дать права на чтение или управление почтовыми ящиками. Для этого переходим в консоль администрирования G Suite, открываем главное меню и переходим в пункт Безопасность Управление API.
    Управление API
    image
    image

  3. Прокручиваем страницу вниз и выбираем пункт Настроить делегирование доступа к данным в домене
    Делегирование доступа к данным в домене
    image

    Нажимаем Добавить, в поле Идентификатор клиента копируем соответствующую строку из карточки сервисного аккаунта, а поле Области действия OAuth вставляем права одно или несколько из следующих значений через запятую:

    - https://mail.google.com/ - для полного доступа
    - https://www.googleapis.com/auth/gmail.modify - для редактирования меток
    - https://www.googleapis.com/auth/gmail.readonly - для чтения
    - https://www.googleapis.com/auth/gmail.metadata - для доступа к метаданным


    Сведения о сервисном аккаунте
    image
    image

  4. Возвращаемся к карточке сервисного аккаунта и включаем ещё одну разрешающую галку Включить делегирование доступа к данным в домене G Suite:
    Статус сервисного аккаунта
    image

    А также заполняем название Вашего продукта в поле ниже.
  5. Теперь нужно создать ключ сервисного аккаунта: это файл, который должен быть доступен в Вашем приложении. Он, собственно, и будет использоваться для авторизации.

    Для этого со страницы Учётные данные Вашего проекта переходим по ссылке Управление сервисными аккаунтами
    Учётные данные
    image


    и выбираем Действия Создать ключ, тип: JSON
    Управление сервисными аккаунтами
    image


    После этого будет сформирован и скачан на Ваш компьютер файл ключа, который нужно поместить в свой проект и дать к нему доступ при вызове API Gmail.

На этом настройка API Gmail закончена, далее будет немного моего кака-кода, собственно, реализующего функции, которые до сих пор решались расширением IMAP PHP.

3. Пишем код


По API Gmail есть вполне себе неплохая официальная документация (клик и клик), которой я и пользовался. Но раз уж взялся написать подробный мануал, то приложу и свой собственный кака-код.

Итак, первым делом устанавливаем Google Client Library (apiclient) при помощи composer:

composer require google/apiclient

(Сначала я, как истинный буквоед, установил именно версию 2.0 api-клиента, как указано в PHP Quickstart, но при первом же запуске на PHP 7.4 посыпались всякие ворнинги и алармы, поэтому Вам так же делать не советую)

Затем на основе примеров из официальной документации пишем свой класс для работы с Gmail, не забывая указать файл ключа сервисного аккаунта:
Класс для работы с Gmail
<?php// Класс для работы с Gmailclass GmailAPI{    private $credentials_file = __DIR__ . '/../Gmail/credentials.json'; // Ключ сервисного аккаунта    // ---------------------------------------------------------------------------------------------    /**     * Функция возвращает Google_Service_Gmail Authorized Gmail API instance     *     * @param  string $strEmail Почта пользователя     * @return Google_Service_Gmail Authorized Gmail API instance     * @throws Exception     */    function getService(string $strEmail){        // Подключаемся к почтовому ящику        try{            $client = new Google_Client();            $client->setAuthConfig($this->credentials_file);            $client->setApplicationName('My Super Project');            $client->setScopes(Google_Service_Gmail::MAIL_GOOGLE_COM);            $client->setSubject($strEmail);            $service = new Google_Service_Gmail($client);        }catch (Exception $e) {            throw new \Exception('Исключение в функции getService: '.$e->getMessage());        }        return $service;    }    // ---------------------------------------------------------------------------------------------    /**     * Функция возвращает массив ID сообщений в ящике пользователя     *     * @param  Google_Service_Gmail $service Authorized Gmail API instance.     * @param  string $strEmail Почта пользователя     * @param  array $arrOptionalParams любые дополнительные параметры для выборки писем     * Из них мы сделаем стандартную строку поиска в Gmail вида after: 2020/08/20 in:inbox label:     * и запишем её в переменную q массива $opt_param     * @return array Массив ID писем или массив ошибок array('arrErrors' => $arrErrors), если они есть     * @throws Exception     */    function listMessageIDs(Google_Service_Gmail $service, string $strEmail, array $arrOptionalParams = array()) {        $arrIDs = array(); // Массив ID писем        $pageToken = NULL; // Токен страницы в почтовом ящике        $messages = array(); // Массив писем в ящике        // Параметры выборки        $opt_param = array();        // Если параметры выборки есть, делаем из них строку поиска в Gmail и записываем её в переменную q        if (count($arrOptionalParams)) $opt_param['q'] = str_replace('=', ':', http_build_query($arrOptionalParams, null, ' '));        // Получаем массив писем, соответствующих условию выборки, со всех страниц почтового ящика        do {            try {                if ($pageToken) {                    $opt_param['pageToken'] = $pageToken;                }                $messagesResponse = $service->users_messages->listUsersMessages($strEmail, $opt_param);                if ($messagesResponse->getMessages()) {                    $messages = array_merge($messages, $messagesResponse->getMessages());                    $pageToken = $messagesResponse->getNextPageToken();                }            } catch (Exception $e) {                throw new \Exception('Исключение в функции listMessageIDs: '.$e->getMessage());            }        } while ($pageToken);        // Получаем массив ID этих писем        if (count($messages)) {            foreach ($messages as $message) {                $arrIDs[] = $message->getId();            }        }        return $arrIDs;    }    // ---------------------------------------------------------------------------------------------    /**     * Удаляем сообщения из массива их ID функцией batchDelete     *     * @param  Google_Service_Gmail $service Authorized Gmail API instance.     * @param  string $strEmail Почта пользователя     * @param  array $arrIDs массив ID писем для удаления из функции listMessageIDs     * @throws Exception     */    function deleteMessages(Google_Service_Gmail $service, string $strEmail, array $arrIDs){        // Разбиваем массив на части по 1000 элементов, так как столько поддерживает метод batchDelete        $arrParts = array_chunk($arrIDs, 999);        if (count($arrParts)){            foreach ($arrParts as $arrPartIDs){                try{                    // Получаем объект запроса удаляемых писем                    $objBatchDeleteMessages = new Google_Service_Gmail_BatchDeleteMessagesRequest();                    // Назначаем удаляемые письма                    $objBatchDeleteMessages->setIds($arrPartIDs);                    // Удаляем их                    $service->users_messages->batchDelete($strEmail,$objBatchDeleteMessages);                }catch (Exception $e) {                    throw new \Exception('Исключение в функции deleteMessages: '.$e->getMessage());                }            }        }    }    // ---------------------------------------------------------------------------------------------    /**     * Получаем содержиме сообщения функцией get     *     * @param  Google_Service_Gmail $service Authorized Gmail API instance.     * @param  string $strEmail Почта пользователя     * @param  string $strMessageID ID письма     * @param  string $strFormat The format to return the message in.     * Acceptable values are:     * "full": Returns the full email message data with body content parsed in the payload field; the raw field is not used. (default)     * "metadata": Returns only email message ID, labels, and email headers.     * "minimal": Returns only email message ID and labels; does not return the email headers, body, or payload.     * "raw": Returns the full email message data with body content in the raw field as a base64url encoded string; the payload field is not used.     * @param  array $arrMetadataHeaders When given and format is METADATA, only include headers specified.     * @return  object Message     * @throws Exception     */    function getMessage(Google_Service_Gmail $service, string $strEmail, string $strMessageID, string $strFormat = 'full', array $arrMetadataHeaders = array()){        $arrOptionalParams = array(            'format' => $strFormat // Формат, в котором возвращаем письмо        );        // Если формат - metadata, перечисляем только нужные нам заголовки        if (($strFormat == 'metadata') and count($arrMetadataHeaders))            $arrOptionalParams['metadataHeaders'] = implode(',',$arrMetadataHeaders);        try{            $objMessage = $service->users_messages->get($strEmail, $strMessageID,$arrOptionalParams);            return $objMessage;        }catch (Exception $e) {            throw new \Exception('Исключение в функции getMessage: '.$e->getMessage());        }    }    // ---------------------------------------------------------------------------------------------    /**     * Выводим список меток, имеющихся в почтовом ящике     *     * @param  Google_Service_Gmail $service Authorized Gmail API instance.     * @param  string $strEmail Почта пользователя     * @return  object $objLabels - объект - список меток     * @throws Exception     */    function listLabels(Google_Service_Gmail $service, string $strEmail){        try{            $objLabels = $service->users_labels->listUsersLabels($strEmail);            return $objLabels;        }catch (Exception $e) {            throw new \Exception('Исключение в функции listLabels: '.$e->getMessage());        }    }    // ---------------------------------------------------------------------------------------------    /**     * Добавляем или удаляем метку (флаг) к письму     *     * @param  Google_Service_Gmail $service Authorized Gmail API instance.     * @param  string $strEmail Почта пользователя     * @param  string $strMessageID ID письма     * @param  array $arrAddLabelIds Массив ID меток, которые мы добавляем к письму     * @param  array $arrRemoveLabelIds Массив ID меток, которые мы удаляем в письме     * @return  object Message - текущее письмо     * @throws Exception     */    function modifyLabels(Google_Service_Gmail $service, string $strEmail, string $strMessageID, array $arrAddLabelIds = array(), array $arrRemoveLabelIds = array()){        try{            $objPostBody = new Google_Service_Gmail_ModifyMessageRequest();            $objPostBody->setAddLabelIds($arrAddLabelIds);            $objPostBody->setRemoveLabelIds($arrRemoveLabelIds);            $objMessage = $service->users_messages->modify($strEmail,$strMessageID,$objPostBody);            return $objMessage;        }catch (Exception $e) {            throw new \Exception('Исключение в функции modifyLabels: '.$e->getMessage());        }    }    // ---------------------------------------------------------------------------------------------}


При любом взаимодействии с Gmail первым делом мы вызываем функцию getService($strEmail) класса GmailAPI, которая возвращает авторизованный объект для работы с почтовым ящиком $strEmail. Далее этот объект уже передаётся в любую другую функцию для уже непосредственно выполнения нужных нам действий. Все остальные функции в классе GmailAPI уже выполняют конкретные задачи:

  • listMessageIDs находит письма по заданным критериям и возвращает их ID (передаваемая в функцию listUsersMessages Gmail API строка поиска писем должна быть аналогична строке поиска в веб-интерфейсе почтового ящика),
  • deleteMessages удаляет письма с переданными в неё ID (функция batchDelete API Gmail удаляет не более 1000 писем за один проход, поэтому пришлось разбить массив переданных в функцию ID на несколько массивов по 999 писем и выполнить удаление несколько раз),
  • getMessage получает всю информацию о сообщении с переданным в неё ID,
  • listLabels возвращает список флагов в почтовом ящике (я использовал её, чтобы получить ID флага, который изначально был создан в веб-интерфейсе ящика, и присваивается нужным сообщениям)
  • modifyLabels добавляет или удаляет флаги к сообщению


Далее, у нас есть задача удаления старых писем в различных почтовых ящиках. При этом старыми мы считаем письма, полученные своё количество дней назад для каждого почтового ящика. Для реализации этой задачи пишем следующий скрипт, ежедневно запускаемый cron'ом:
Удаление старых писем
<?php/** * Удаляем письма в почтовых ящиках Gmail * Используем сервисный аккаунт и его ключ */require __DIR__ .'/../general/config/config.php'; // Общий файл конфигурацииrequire __DIR__ .'/../vendor/autoload.php'; // Загрузчик внешних компонент// Задаём количества дней хранения почты в ящиках$arrMailBoxesForClean = array(    'a@domain.com' => 30,    'b@domain.com' => 30,    'c@domain.com' => 7,    'd@domain.com' => 7,    'e@domain.com' => 7,    'f@domain.com' => 1);$arrErrors = array(); // Массив ошибок$objGmailAPI = new GmailAPI(); // Класс для работы с GMail// Проходим по списку почтовых ящиков, из которых нужно удалить старые письмаforeach ($arrMailBoxesForClean as $strEmail => $intDays) {    try{        // Подключаемся к почтовому ящику        $service = $objGmailAPI->getService($strEmail);        // Указываем условие выборки писем в почтовом ящике        $arrParams = array('before' => date('Y/m/d', (time() - 60 * 60 * 24 * $intDays)));        // Получаем массив писем, подходящих для удаления        $arrIDs = $objGmailAPI->listMessageIDs($service,$strEmail,$arrParams);        // Удаляем письма по их ID в массиве $arrIDs        if (count($arrIDs)) $objGmailAPI->deleteMessages($service,$strEmail,$arrIDs);        // Удаляем все использованные переменные        unset($service,$arrIDs);    }catch (Exception $e) {        $arrErrors[] = $e->getMessage();    }}if (count($arrErrors)){    $strTo = 'my_email@domain.com';    $strSubj = 'Ошибка при удалении старых писем из почтовых ящиков';    $strMessage = 'При удалении старых писем из почтовых ящиков возникли следующие ошибки:'.        '<ul><li>'.implode('</li><li>',$arrErrors).'</li></ul>'.        '<br/>URL: '.filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL);    $objMailSender = new mailSender();    $objMailSender->sendMail($strTo,$strSubj,$strMessage);}


Скрипт подключается к каждому заданному почтовому ящику, выбирает старые письма и удаляет их.

Задача формирования отчётов для менеджера о недоставленных письмах на основании автоматических отчётов решается следующим скриптом:
Фильтрация и маркировка писем
<?php/* * Подключаемся к ящику a@domain.com * Берём с него письма о том, что наши письма не доставлены: отправитель: mailer-daemon@googlemail.com * Проверяем почтовые ящики в этих письмах. Если они есть у клиентов на нашем сайте, отправляем на b@domain.com * письмо об этом */require __DIR__ .'/../general/config/config.php'; // Общий файл конфигурацииrequire __DIR__ .'/../vendor/autoload.php'; // Загрузчик внешних компонент$strEmail = 'a@domain.com';$strLabelID = 'Label_2399611988534712153'; // Флаг reportProcessed - устанавливаем при обработке письма// Параметры выборки$arrParams = array(    'from' => 'mailer-daemon@googlemail.com', // Письма об ошибках приходят с этого адреса    'in' => 'inbox', // Во входящих    'after' => date('Y/m/d', (time() - 60 * 60 * 24)), // За последние сутки    'has' => 'nouserlabels' // Без флага);$arrErrors = array(); // Массив ошибок$objGmailAPI = new GmailAPI(); // Класс для работы с GMail$arrClientEmails = array(); // Массив адресов электронной почты, на которые не удалось отправить сообщениеtry{    // Подключаемся к почтовому ящику    $service = $objGmailAPI->getService($strEmail);    // Находим в нём отчёты за последние сутки о том, что письма не доставлены    $arrIDs = $objGmailAPI->listMessageIDs($service,$strEmail, $arrParams);    // Для найденных писем получаем заголовок 'X-Failed-Recipients', в котором содержится адрес, на который пыталось быть отправлено письмо    if (count($arrIDs)){        foreach ($arrIDs as $strMessageID){            // Получаем метаданные письма            $objMessage = $objGmailAPI->getMessage($service,$strEmail,$strMessageID,'metadata',array('X-Failed-Recipients'));            // Заголовки письма            $arrHeaders = $objMessage->getPayload()->getHeaders();            // Находим нужный            foreach ($arrHeaders as $objMessagePartHeader){                if ($objMessagePartHeader->getName() == 'X-Failed-Recipients'){                    $strClientEmail = mb_strtolower(trim($objMessagePartHeader->getValue()), 'UTF-8');                    if (!empty($strClientEmail)) {                        if (!in_array($strClientEmail, $arrClientEmails)) $arrClientEmails[] = $strClientEmail;                    }                    // Помечаем письмо флагом reportProcessed, чтобы не выбирать его в следующий раз                    $objGmailAPI->modifyLabels($service,$strEmail,$strMessageID,array($strLabelID));                }            }        }    }    unset($service,$arrIDs,$strMessageID);}catch (Exception $e) {    $arrErrors[] = $e->getMessage();}// Если найдены адреса электронной почты, на которые не удалось доставить сообщения, проверяем их в базеif (count($arrClientEmails)) {    $objClients = new clients();    // Получаем все email всех клиентов    $arrAllClientsEmails = $objClients->getAllEmails();    foreach ($arrClientEmails as $strClientEmail){        $arrUsages = array();        foreach ($arrAllClientsEmails as $arrRow){            if (strpos($arrRow['email'], $strClientEmail) !== false) {                $arrUsages[] = 'как основной email клиентом "<a href="'.MANAGEURL.'?m=admin&sm=clients&edit='.$arrRow['s_users_id'].'">'.$arrRow['name'].'</a>"';            }            if (strpos($arrRow['email2'], $strClientEmail) !== false) {                $arrUsages[] = 'как дополнительный email клиентом "<a href="'.MANAGEURL.'?m=admin&sm=clients&edit='.$arrRow['s_users_id'].'">'.$arrRow['name'].'</a>"';            }            if (strpos($arrRow['site_user_settings_contact_email'], $strClientEmail) !== false) {                $arrUsages[] = 'как контактный email клиентом "<a href="'.MANAGEURL.'?m=admin&sm=clients&edit='.$arrRow['s_users_id'].'">'.$arrRow['name'].'</a>"';            }        }        $intUsagesCnt = count($arrUsages);        if ($intUsagesCnt > 0){            $strMessage = 'Не удалось доставить письмо с сайта по адресу электронной почты <span style="color: #000099;">'.$strClientEmail.'</span><br/>                Этот адрес используется';            if ($intUsagesCnt == 1){                $strMessage .= ' '.$arrUsages[0].'<br/>';            }else{                $strMessage .= ':<ul>';                foreach ($arrUsages as $strUsage){                    $strMessage .= '<li>'.$strUsage.'</li>';                }                $strMessage .= '</ul>';            }            $strMessage .= '<br/>Пожалуйста, уточните у клиента актуальность этого адреса электронной почты.<br/><br/>                Это письмо было отправлено автоматически, не отвечайте на него';            if (empty($objMailSender)) $objMailSender = new mailSender();            $objMailSender->sendMail('b@domain.com','Проверьте email клиента',$strMessage);        }    }}if (count($arrErrors)){    $strTo = 'my_email@domain.com';    $strSubj = 'Ошибка при обработке отчётов о недоставленных письмах';    $strMessage = 'При обработке отчётов о недоставленных письмах возникли следующие ошибки:'.        '<ul><li>'.implode('</li><li>',$arrErrors).'</li></ul>'.        '<br/>URL: '.filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL);    if (empty($objMailSender)) $objMailSender = new mailSender();    $objMailSender->sendMail($strTo,$strSubj,$strMessage);}


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

Исходники доступны на GitHub.

Вот и всё, что я хотел поведать в этой статье. Спасибо за прочтение! Если у Вас защипало в глазах от моего кода, просто сверните спойлер или напишите свои замечания буду рад конструктивной критике.
Подробнее..

Настройка собственного почтового сервера

26.02.2021 20:18:58 | Автор: admin

Есть три основных шага, чтобы установить и настроить собственный почтовый сервер.

  • Настройка IP и DNS

  • Выбор и запуск приложения почтового сервера

  • Добавление своего почтового сервера в белые списки

Настройка IP и DNS

Обеспечение внешнего статического IP-адреса, публичного домена и записи PTR

Это основные требования для запуска собственного почтового сервера.

  • Публичный статический IP-адрес
    IP-адрес почтового сервера должен быть общедоступным и постоянным во времени. Убедиться в этом можно у хостинг или Интернет-провайдера.

  • Доменное имя указывает на IP
    DNS-запись публичного доменного имени почтового сервера должна указывать на этот IP-адрес. Им можно управлять в настройках DNS провайдера доменного имени.

  • IP указывает на доменное имя
    Самое главное, обратная DNS-запись (именуемая PTR) должна указывать на доменное имя почтового сервера по IP-адресу. Можно попросить своего хостинг-провайдера или поставщика интернет-услуг настроить его. Его можно легко проверить по IP-адресу онлайн (например, тут), или с помощью команды nslookup в Windows и команды host в системах на основе UNIX.

Настройка MX записи в DNS

Запись почтового обмена (MX) указывает почтовый сервер, ответственный за прием сообщений электронной почты от имени домена.

Например, если наш домен - mycompany.com, почтовый сервер - mail.mycompany.com, то запись DNS для mycompany.com будет:

Type

Host

Value

Priority

TTL

MX

@

mail.mycompany.com

10

1 min

где:

  • Priority (приоритет) используется, когда в домене более одного почтового сервера.

  • TTL (время жизни) можно установить любое предпочтительное значение, а наименьшее значение используется для применения конфигурации DNS как можно скорее при отладке настроек.

Настройка DKIM записи в DNS

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

Понадобятся приватный и открытый ключи. Их можно создать с помощью онлайн-инструментов, например Power DMARC Toolbox - DKIM Record Generator, или с помощью команд OpenSSL (приведен пример для Windows):

  • Создать приватный ключ
    openssl.exe genrsa -out private.key 2048

  • Создать публичный ключ из приватного
    openssl.exe rsa -in private.key -pubout -outform der 2>nul | openssl base64 -A > public.key.txt

И запись DNS будет выглядеть так:

Type

Host

Value

TTL

TXT

selector._domainkey

v=DKIM1; k=rsa; p=public_key

1 min

где:

  • selector - самостоятельно выбранный идентификатор (например, mysrv), который будет использоваться в приложении почтового сервера (смотрите ниже).

  • public_key - открытый ключ, закодированный алгоритмом base64 (содержимое public.key.txt).

  • TTL (время жизни) имеет то же значение, что и в предыдущем разделе.

Настройка SPF записи в DNS

Инфраструктура политики отправителя (SPF) это стандарт проверки подлинности электронной почты, который проверяет IP-адрес отправителя по списку авторизованных IP-адресов владельца домена для проверки входящей электронной почты.

Тут запись DNS будет выглядеть так:

Type

Host

Value

TTL

TXT

@

v=spf1 a mx include:relayer_name -all

1 min

где:

  • relayer_name - имя необязательного внешнего почтового сервера-ретранслятора (смотрите ниже). Если не нужно - убирается вместе с "include:".

  • TTL (время жизни) имеет то же значение, что и в предыдущем разделе.

Можно использовать удобный онлайн-генератор записи SPF.

Дополнительные записи DNS

Некоторые поля не обязательны, но желательно иметь.

  • DMARC
    Запись доменной проверки подлинности сообщений, отчетов и соответствия (DMARC) позволяет собственному почтовому серверу декларировать политику того, как другие почтовые серверы должны реагировать на недостоверные сообщения от него.

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

  • TLS-RPT
    TLS-отчетность (TLS-RPT) дает ежедневные сводные отчеты с информацией о электронных письмах, которые не зашифровываются и не доставляются.

Все эти записи могут быть созданы с помощью Power DMARC Toolbox.

Выбор и запуск приложения почтового сервера

Конечно, хостинг должен позволять устанавливать программное обеспечение. Можно использовать любое подходящее приложение для почтового сервера. Например, есть бесплатный hMailServer для Windows, который предоставляет все необходимые функции с минимальным использованием ресурсов. Для систем на базе UNIX существует множество бесплатных почтовых серверов, таких как Exim Internet Mailer или iRedMail.

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

Инициализация

Когда программное обеспечение выбрано и установлено, самое время его настроить.

  • Домен и пользователи
    Нужно добавить домен и начальный набор пользователей почтового сервера.

  • Безопасность
    Чтобы обеспечить соответствующий уровень безопасности, мы должны добавить сертификат SSL для домена.

  • Подпись сообщений
    Далее, следует настроить DKIM. Нужно указать полученные выше приватный ключ и селектор. Кроме того, методы заголовка и тела должны быть установлены на расслабленный, алгоритм подписи должен быть установлен на SHA256, иначе на некоторых SMTP серверах не проходит проверка (например, google).

  • Защита от спама
    Наконец, нужно настроить антиспам-проверку специальными узлами черных списков, такими как spamhaus.org, чтобы защитить пользователей почтового сервера от нежелательных сообщений.

Протоколы электронной почты

Нужно настроить три протокола электронной почты, которые необходимы для её отправки и получения.

SMTP

SMTP используется для приема входящей и исходящей почты с/на другие почтовые серверы. И это позволяет пользователям домена отправлять свои сообщения.

  • 25 порт
    Этот порт необходим для управления входящими подключениями от других почтовых серверов. Метод безопасности следует установить в STARTTLS.

  • 587 порт
    Он нужен для почтовых клиентов собственного почтового сервера. Метод безопасности следует установить в STARTTLS.

  • 465 порт
    Он не является официальным и может потребоваться для старых почтовых клиентов. И метод безопасности следует установить в SSL/TLS.

POP3, IMAP

POP3 и IMAP используются отдельными почтовыми клиентами, такими как Outlook на ПК или любой почтовый клиент на мобильных телефонах. Это позволяет пользователям домена управлять своими сообщениями.

Порт 993 следует использовать для защищенных соединений IMAP, а порт 995 - для POP3. Для обеспечения совместимости с большинством клиентов метод безопасности следует установить в SSL/TLS (не STARTTLS).

Также можно настроить порты 143 для IMAP и 110 для POP3, но они не шифруются и сейчас их уже мало кто использует.

Проверка

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

Теперь пора проверить отправку на внешний адрес.

Аккаунт Gmail.com

Если есть учетная запись Gmail.com (что наверняка), можно отправить тестовое письмо на свой адрес Gmail. Затем открываем свою электронную почту в браузере и нажимаем Показать подробности.

Если есть подписано: домен, подпись DKIM настроена правильно. Если есть отправлено по почте: домен, SPF в порядке.

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

Также, в Outlook можно видеть те же заголовки в свойствах сообщения.

Специальные онлайн-сервисы

Существует множество онлайн-сервисов, которые могут проверять отправку электронной почты. Ниже приведены некоторые из них.

  • AppMailDev
    Этот сервис позволяет тестировать конфигурацию почтового сервера, такую как DKIM и SPF, отправляя электронное письмо на указанный сгенерированный почтовый адрес. Нужно просто следовать инструкциям на экране и результаты теста будут отображены там же.

  • DKIMValidator
    Предоставляет те же функции, что и предыдущая служба. Результаты тестирования будут отправлены на адрес отправителя.

  • HAD Email Auth Tester
    Чтобы проверить отправку сообщения здесь, нужно отправить специальное сообщение на tester@email-test.had.dnsops.gov. Результаты тестирования будут отправлены на адрес отправителя.

  • PowerDMARC
    Этот сервис предоставляет только облегченную проверку всех атрибутов, но у него есть удобные инструменты, указанные в ссылках выше.

Итак, если всё настроено правильно, но сервер присутствует в чёрных списках спама, нужно внести его в белый список.

Добавление почтового сервера в белые списки

Итак, если всё вышеперечисленное настроено правильно, другие почтовые серверы по-прежнему могут отмечать сообщения как спам и отклонять их. Это бывает, когда IP (или его диапазон) домена попадает в какой-то черный список. Чаще всего причиной этого является использование соседних IP-адресов для рассылки спам-сообщений.

Внесение в белый список в публичных источниках

Итак, сначала проверим IP (и, если необходимо, домен) онлайн на наличие в каких-либо черных списках. Его можно проверить в любом онлайн-чекере, который можно найти через поиск. Например, MXToolBox проверяет самые популярные черные списки. Также, multirbl.valli.org показывает много источников черного списка и доверие к каждому из них.

Затем нужно последовательно просмотреть каждый элемент в результатах и прочитать рекомендации о том, как внести IP-адрес в белый список в конкретном источнике черного списка. Но не все из них могут позволить это сделать бесплатно, например, немецкий UCEPROTECT-Network.

Кстати, на тут на habr обсуждалась автоматизация мониторинга IP в блэклистах.

Внесение в белый список определенных почтовых серверов

Некоторые серверы, такие как Outlook, имеют свои собственные черные списки. Проверка проста - приложение почтового сервера уведомит о неудачной доставке в почтовом клиенте. Большинство почтовых серверов предоставляют в ответе URL-адреса разблокировки. Таким образом, нужно открыть такой URL и следовать инструкциям, например, как этот.

Обход черных списков

Если какой-то официальный черный список не разрешает добавление в исключения или когда-нибудь почта перестает отправляться на определенный домен - можно использовать внешние службы ретрансляции SMTP. Они позволяют использовать их в качестве шлюзов (или прокси) при отправке почты.

  • MailerSend
    Один из самых дешевых - позволяет бесплатно отправлять 20 тысяч писем в месяц и имеет низкую стоимость дополнительной отправки. Но есть особенность: поля CC и BCC пока не поддерживаются.

  • SendInBlue
    Это еще один хороший сервис, который позволяет бесплатно отправлять 9 тысяч писем в месяц с лимитом 200 в день. Но есть нюансы: встроенное отслеживание электронной почты нельзя отключить и высоковатая цена сверх бесплатного лимита.

В каждой службе нужно зарегистрироваться и получить подтверждение почтового домена. После подтверждения, каждый из них дает указания на то, что должно быть настроено для DNS (DKIM, SPF и DMARK) и почтового приложения (адрес сервера ретрансляции SMTP, порт и учетные данные).

Заключение

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

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru