smtp — Swiftmailer, использующий STARTTLS и самозаверяющие сертификаты

Я пытаюсь отправить электронное письмо с php и swiftmailer, используя STARTTLS, но получаю ошибку сертификата. У меня есть root-доступ к SMTP-серверу, а используемый сертификат самоподписан.
Я использую Debian на обеих машинах (веб-сервер и SMTP-сервер)

PHP message: PHP Warning: stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in [..]/lib/classes/Swift/Transport/StreamBuffer.php on line 97
PHP message: PHP Fatal error: Uncaught exception 'Swift_TransportException' with message 'Unable to connect with TLS encryption' in [..]/lib/classes/Swift/Transport/EsmtpTransport.php:294

Нужно ли где-то добавить свой собственный сертификат, чтобы он был принят? Или это какая-то ошибка конфигурации OpenSSL?

11

Решение

Swiftmailer был обновлен, чтобы включить опцию для этого. Теперь это можно решить с помощью setStreamOptions метод из вашего Swift_SmtpTransport экземпляр, а не редактирование класса swift.

$transport = Swift_SmtpTransport::newInstance('smtp.server.com', 123, 'tls')
->setUsername('username')
->setPassword('password')
->setStreamOptions(array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false)));
14

Другие решения

У меня та же проблема с использованием Swiftmailer в Laravel.

Похоже, что в Swiftmailer этого нет. Чистым решением было бы добавить свой собственный корневой CA на ваш сервер и подписать сертификат вашего почтового сервера с этим CA. Сертификат будет действительным после этого. Смотри например этот урок.

В любом случае, быстрый грязный хак, который вы не должны использовать, будет редактировать swiftmailer\swiftmailer\lib\classes\Swift\Transport\StreamBuffer.php, В _establishSocketConnection() Строка 253 заменить:

$options = array();

с чем-то вроде этого:

$options = array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false));

Это изменит опции ssl из stream_context_create () (несколько строк ниже $options):

$this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno,
$errstr, $timeout, STREAM_CLIENT_CONNECT, stream_context_create($options));
13

Вам не нужно редактировать /vendor файлы. Вы можете указать (недокументированные) параметры в вашем config/mail.php файл:

'stream' => [
'ssl' => [
'allow_self_signed' => true,
'verify_peer' => false,
'verify_peer_name' => false,
],
],

Вы можете проверить это сами в vendor/laravel/framework/src/Illuminate/Mail/TransportManager.php на линии ~ 50:

...
if (isset($config['stream'])) {
$transport->setStreamOptions($config['stream']);
}
...
5