How to deal with self-signed TLS certificates in Laravel's SMTP driver?

46.3k views Asked by At

I'm trying to send an email with this configuration:

return [

    'driver'     => 'smtp',

    'host'       => 'mail.mydomain.com',

    'port'       => 26,

    'from'       => ['address' => '[email protected]', 'name' => 'Mailer'],

    'encryption' => 'tls',

    'username'   => env('MAIL_USERNAME'),

    'password'   => env('MAIL_PASSWORD'),

    'sendmail'   => '/usr/sbin/sendmail -bs',

    'pretend'    => false,

];

When I submit the form I receive this erorr:

ErrorException in StreamBuffer.php line 95:
stream_socket_enable_crypto(): SSL operation failed with code 1.
OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

I found this solution where people seems to have solved the problem with the same library but I cant manage to solve it in Laravel.

https://github.com/PHPMailer/PHPMailer/issues/368

5

There are 5 answers

0
geggleto On BEST ANSWER

Well in that link you provided the solution is straight-forward.

The correct solution is to fix your SSL config - it's not PHP's fault!

how to fix it? in config/mail.php ,'driver' => env('MAIL_DRIVER', 'smtp'), should be 'driver' => env('MAIL_DRIVER', 'mail'), (credits: Danyal Sandeelo)

1
Adam M. On

In Laravel 9 defining stream options for the SMTP transport is no longer supported. Instead, you must define the relevant options directly within the configuration if they are supported. For example, to disable TLS peer verification:

'smtp' => [
    // Laravel 8.x...
    'stream' => [
        'ssl' => [
            'verify_peer' => false,
        ],
    ],
 
    // Laravel 9.x...
    'verify_peer' => false,
],
0
Maciej Laskowski On

In case you are using Laravel 7.0 you can disable SSL verification in SwiftMailer this way (please note that disabling SSL verification is not recommended!):

config/mail.php

'mailers' => [
    'smtp' => [
        'transport' => 'smtp',
        'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
        'port' => env('MAIL_PORT', 587),
        'encryption' => env('MAIL_ENCRYPTION', 'tls'),
        'username' => env('MAIL_USERNAME'),
        'password' => env('MAIL_PASSWORD'),
        'timeout' => null,
        'stream' => [
            'ssl' => [
                'allow_self_signed' => true,
                'verify_peer' => false,
                'verify_peer_name' => false,
            ],
        ],
    ],
],

EDIT: Since Laravel 9 depreciated SwiftMailer has been replaced with Symfony Mailer. According to update guide they way you disable TLS peer verification has changed as well.

'smtp' => [
    // Laravel 8.x...
    'stream' => [
        'ssl' => [
            'verify_peer' => false,
        ],
    ],
 
    // Laravel 9.x...
    'verify_peer' => false,
],
1
M Arfan On

Editor's note: disabling SSL verification has security implications. Without verification of the authenticity of SSL/HTTPS connections, a malicious attacker can impersonate a trusted endpoint (such as GitHub or some other remote Git host), and you'll be vulnerable to a Man-in-the-Middle Attack.

Be sure you fully understand the security issues before using this as a solution.

Add this at bottom of your config/mail.php

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

this will solve your problem.

0
mosh442 On

In my case the problem was related to SSL. My SMTP has a self-signed certificate and my laravel was running on top of PHP 5.6 which disables the 'allow_self_signed' context variable to false and enables 'verify_peer' and hence poping the error when sending an email.

Since I didn't wanted to hack around swiftmailer code I added the Certificate Authority (CA) file of my server as trusted CA for my system executing laravel.

I did that getting the CA cert of my smtp server, something like

-----BEGIN CERTIFICATE-----
MIIElTCCA32gAwIBAgIJAMZjjNg64RQwMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYD
VQQGEwJVUzEMMAoGA1UECBMDTi9BMQwwCgYDVQQHEwNOL0ExJDAiBgNVBAoTG1pp
...
5a8a4QEwWmnAOgHetsOCvhfeGW3yAJPD8Q==
-----END CERTIFICATE-----

and write it in my laravel machine which has an ubuntu 14.04 to a file named /usr/local/share/ca-certificates/my_cert.crt. It is crucial to end the file with .crt and also make it readable for everyone.

Then call update-ca-certificates and the certificate will be added to the list of valid CAs of your server.