I'm trying to send an email with php and swiftmailer, using STARTTLS, but I'm getting a certificate error. I have root access to the SMTP server, and the certificate used is self-signed.
I'm using Debian on both machines (web server and smtp server)
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
Do I need to add my own certificate somewhere to get it accepted? Or is this some OpenSSL configuration error?
Swiftmailer has now been updated to include an option for this. It can now be solved using the setStreamOptions
method from your Swift_SmtpTransport
instance rather than editing the swift class.
$transport = Swift_SmtpTransport::newInstance('smtp.server.com', 123, 'tls')
->setUsername('username')
->setPassword('password')
->setStreamOptions(array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false)));
I got the same problem using Swiftmailer in Laravel.
Looks like there is no option for this in Swiftmailer. Clean solution would be to add your own root CA to your server and sign your mail server certificate with this CA. The certificate would be valid after this. See for example this tutorial.
Anyway, a quick dirty hack you should not use would be to edit swiftmailer\swiftmailer\lib\classes\Swift\Transport\StreamBuffer.php
. In _establishSocketConnection()
line 253 replace:
$options = array();
with something like this:
$options = array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false));
This will change the ssl options of stream_context_create() (a few lines below $options
):
$this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno,
$errstr, $timeout, STREAM_CLIENT_CONNECT, stream_context_create($options));
You do not need to edit /vendor
files. You can specify (undocumented) options in your config/mail.php
file:
'stream' => [
'ssl' => [
'allow_self_signed' => true,
'verify_peer' => false,
'verify_peer_name' => false,
],
],
You can check it yourself in vendor/laravel/framework/src/Illuminate/Mail/TransportManager.php
on line ~50:
...
if (isset($config['stream'])) {
$transport->setStreamOptions($config['stream']);
}
...