79
stream_socket_enable_crypto(): SSL operation failed with code 1. 
OpenSSL Error messages: error:14090086:SSL 
routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

Im using Laravel 4.2, PHP 5.6, Apache 2.4

I have GoDaddy SSL installed in Amazon ec2 Linux.

SSL working fine when i visit the site with https.

The error happened when I call my function :

<?php

public function sendEmail() 
{
        \Mail::send ( 'emails.code.code', $data, function ($sendemail) use($email) {
            $sendemail->from ( 'info@me.com', 'Me Team' );
            $sendemail->to ( $email, '' )->subject ( 'Activate your account' );
        } );

}
?>

I read some articles about this, they said that there are things we should make some changes, they put that code but i don't know where to insert it.

Been reading this: https://www.mimar.rs/en/sysadmin/2015/php-5-6-x-ssltls-peer-certificates-and-hostnames-verified-by-default/

and this documentation of php http://php.net/manual/en/migration56.openssl.php which is hard to understand.

So my question is how to solve this problem?

Mtxz
  • 3,749
  • 15
  • 29

18 Answers18

145

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 Gmail, 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.

You can add below code in /config/mail.php ( tested and worked on laravel 5.1, 5.2, 5.4 )

'stream' => [
   'ssl' => [
      'allow_self_signed' => true,
      'verify_peer' => false,
      'verify_peer_name' => false,
   ],
],
miken32
  • 42,008
  • 16
  • 111
  • 154
m yadav
  • 1,783
  • 2
  • 11
  • 13
26

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 Gmail, 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.

I have also this error in laravel 4.2 I solved like this way. Find out StreamBuffer.php. For me I use xampp and my project name is itis_db for this my path is like this. So try to find according to your one

C:\xampp\htdocs\itis_db\vendor\swiftmailer\swiftmailer\lib\classes\Swift\Transport\StreamBuffer.php

and find out this function inside StreamBuffer.php

private function _establishSocketConnection()

and paste this two lines inside of this function

$options['ssl']['verify_peer'] = FALSE;
$options['ssl']['verify_peer_name'] = FALSE;

and reload your browser and try to run your project again. For me I put on like this:

private function _establishSocketConnection()
{
    $host = $this->_params['host'];
    if (!empty($this->_params['protocol'])) {
        $host = $this->_params['protocol'].'://'.$host;
    }
    $timeout = 15;
    if (!empty($this->_params['timeout'])) {
        $timeout = $this->_params['timeout'];
    }
    $options = array();
    if (!empty($this->_params['sourceIp'])) {
        $options['socket']['bindto'] = $this->_params['sourceIp'].':0';
    }
    
   $options['ssl']['verify_peer'] = FALSE;
    $options['ssl']['verify_peer_name'] = FALSE;

    $this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, stream_context_create($options));
    if (false === $this->_stream) {
        throw new Swift_TransportException(
            'Connection could not be established with host '.$this->_params['host'].
            ' ['.$errstr.' #'.$errno.']'
            );
    }
    if (!empty($this->_params['blocking'])) {
        stream_set_blocking($this->_stream, 1);
    } else {
        stream_set_blocking($this->_stream, 0);
    }
    stream_set_timeout($this->_stream, $timeout);
    $this->_in = &$this->_stream;
    $this->_out = &$this->_stream;
}

Hope you will solve this problem.....

miken32
  • 42,008
  • 16
  • 111
  • 154
Humaun Rashid Nayan
  • 1,232
  • 14
  • 25
  • 1
    This works for me but is there any other way to resolve this issue without touching the code of vendor ? – Rajesh Jan 31 '16 at 14:28
  • 21
    Downvote because you shouldn't ever edit vendor code. First of all you'll loose all changes on any composer update. Second - vendor isn't (and shouldn't) be added to control version so anyone of team will not get this changes. Much better way is to create your own classes which extend existing vendor classes. – ElChupacabra May 26 '17 at 08:17
  • 6
    You software just made the list at [The most dangerous code in the world: validating SSL certificates in non-browser software](http://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html). – jww Jun 08 '17 at 00:05
  • It worked really well for me.. But isn't there a way without touching vendor code? – Prince Bhanwra Oct 03 '17 at 23:07
  • hello, I have a problem while sending email with gmail, but it has already solved by adding two lines of code that you give. Could you please tell me why I have to put the two lines of code? – Jems Apr 02 '18 at 09:35
  • For editing a vendor file you can use "exclude-from-classmap" and "files" directives in your composer.json "autoload" section. – Milad Rahimi Apr 09 '20 at 21:35
17

Try changing the app/config/email.php

smtp to mail

  • 1
    Laravel Framework problem, changing protocol removed issue. – Ravikumar Sharma Oct 26 '15 at 06:53
  • 1
    Now it not throwing error but after changing it to "mail" i am not receiving mails but displaying as mail sent as in my application , what could be the issue ? – Rajesh Jan 31 '16 at 14:13
  • 20
    Changing this to mail sends mail directly from the server, instead of connecting to an smtp server! – JoeGalind Apr 20 '16 at 00:49
  • 31
    This is a really bad answer because it doesn't describe the consequences of this change. When sending email via SMTP laravel logs into your sever and sends and email on your behalf. If you change it to 'mail' it will then send the mail via PHP mail meaning that it will be subject to higher spam scores because PHP is essentially spoofing the email. You can use PHP mail to send emails from bill@microsoft.com if you want. But they they'll probably end up in spam. More info here. https://www.jvfconsulting.com/blog/php-mail-function-vs-smtp-guaranteed-delivery/ – Mark Oct 12 '17 at 01:31
  • Correct answer ! – w3spi Apr 03 '18 at 18:39
  • 2
    Regarding e-mail spoofing, that's why there are SPF and DKIM records, it has nothing to do whether PHP or something else sends e-mail. If you have your domain set up properly, sending it via SMTP or PHP is equal providing you use correct domain. – vitro Jun 28 '19 at 00:43
13

How to fix on Laravel (5,6,7 at least), WordPress (and other PHP + cURL implementations I guess):

Download the latest cacert.pem file from cURL website.

wget https://curl.haxx.se/ca/cacert.pem

Edit php.ini (you can do php --ini to find it), update (or create if they don't exist already) those two lines:

curl.cainfo="/path/to/downloaded/cacert.pem"
...
openssl.cafile="/path/to/downloaded/cacert.pem"

Those lines should already exist but commented out, so uncomment them and edit both values with the path to the downloaded cacert.pem

Restart PHP and Nginx/Apache.

Edit: You may need to chown/chmod the downloaded certificate file so PHP (and the user running it) can read it.

source

Mtxz
  • 3,749
  • 15
  • 29
  • 1
    Is there an automated way to keep this up to date? I have to manually update it every few months and I don't know when it's going to be updated. – Jeff Davis Oct 28 '21 at 20:30
  • I guess you could do a monthly CRON that updates the file, and reload related services. I'm not aware of a tool to maintain it automatically. – Mtxz Oct 28 '21 at 21:04
8

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 Gmail, 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.

Easy fix for this might be editing config/mail.php and turning off TLS

'encryption' => env('MAIL_ENCRYPTION', ''), //'tls'),

Basically by doing this

$options['ssl']['verify_peer'] = FALSE;
$options['ssl']['verify_peer_name'] = FALSE;

You should loose security also, but in first option there is no need to dive into Vendor's code.

miken32
  • 42,008
  • 16
  • 111
  • 154
monas
  • 204
  • 4
  • 8
  • 2
    You software just made the list at [The most dangerous code in the world: validating SSL certificates in non-browser software](http://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html). – jww Jun 08 '17 at 00:05
  • Thanks so so much! – jonatanes Jun 27 '17 at 18:42
  • 2
    I'm using the solution in this answer for testing emails via Mailgun sandbox, and for that it works perfectly. However I wouldn't recommend this for production mailing. – GTCrais Aug 07 '17 at 11:49
  • I'm using lumen version 7 running locally. Turning off TLS encryption value to empty works. I haven't tried in the production server yet. Thanks! – kriscondev Apr 21 '20 at 09:02
8

edit your .env and add this line after mail config lines

MAIL_ENCRYPTION=""

Save and try to send email

Somwang Souksavatd
  • 4,947
  • 32
  • 30
5

For Laravel 9, following is enough to disable ssl check:

 'verify_peer'       => false,

Example:
// 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,
            'auth_mode'  => null,
            'verify_peer' => false,
        ],
        ...
vkGunasekaran
  • 6,668
  • 7
  • 50
  • 59
4

Finally! it was my AVG antivirus, it has a feature called email shield, disabled it and the error was gone.

Omar
  • 607
  • 3
  • 8
  • 18
  • 1
    Oh Myyyyyy God! Thank you so much. Went crazy with this thing for like 10 hours, it was due to AVG blocking everything!!!!! Thank you so much Bro! – Benny Oct 24 '22 at 21:37
  • 1
    You don't need to completely disable Email Shield. In AVG, select "Web & Email" > Settings (the gear icon top right) > "Email Shield" and unselect "Scan outbound emails (SMTP)". – CJ Dennis Oct 27 '22 at 22:49
3

This start to happen today in one of my servers using wordpress with a plugin that uses PHPMailer, with no recent changes.

The solution: sudo yum install ca-certificates

Now It works again perfectly, I did also an httpd restart (not sure if needed)

I can't figure out the real problem, I suspect that was a hardcoded date in the old ca-certificates package.

anibal
  • 431
  • 1
  • 4
  • 9
1

To resolve this problem you first need to check the SSL certificates of the host your are connecting to. For example using ssllabs or other ssl tools. In my case the intermediate certificate was wrong.

If the certificate is ok, make sure the openSSL on your server is up to date. Run openssl -v to check your version. Maybe your version is to old to work with the certificate.

In very rare cases you might want to disable ssl security features like verify_peer, verify_peer_name or allow_self_signed. Please be very careful with this and never use this in production. This is only an option for temporary testing.

PiTheNumber
  • 22,828
  • 17
  • 107
  • 180
1

change encryption type from SSL to TLS works form me.

Rana Nadeem
  • 1,115
  • 1
  • 9
  • 17
  • My Laravel project is already using TLS. What kind of project do you have and where do you make the change? – JCarlosR Aug 08 '22 at 00:07
0

in my case i did following

$mail = new PHPMailer;
$mail->isSMTP();            
$mail->Host = '<YOUR HOST>';
$mail->Port = 587;
$mail->SMTPAuth = true;
$mail->Username = '<USERNAME>';
$mail->Password = '<PASSWORD>';
$mail->SMTPSecure = '';
$mail->smtpConnect([
    'ssl' => [
        'verify_peer' => false,
        'verify_peer_name' => false,
        'allow_self_signed' => true
    ]
]);
$mail->smtpClose();

$mail->From = '<MAILFROM@MAIL.COM>';
$mail->FromName = '<MAIL FROM NAME>';

$mail->addAddress("<SENDTO@MAIL.com>", '<SEND TO>');

$mail->isHTML(true);
$mail->Subject= '<SUBJECTHERE>';
$mail->Body =  '<h2>Test Mail</h2>';
$isSend = $mail->send();
Renish Gotecha
  • 2,232
  • 22
  • 21
0

with symfony I modify the dotEnv to include some small information and it works great

MAILER_DSN=smtp://user:pass@container_name:25?verify_peer=false&verify_peer_name=false&allow_self_signed=true
arno
  • 792
  • 14
  • 33
0

I my case the issue occurred on websites hosted on VPS with cPanel' WHM. After an update all the emails sent via Gmail SMTP stopped working.

As a solution, in the WHM I had to turn off

Restrict outgoing SMTP to root, exim, and mailman (FKA SMTP Tweak)

setting under

Home / Server Configuration / Tweak Settings

See pic.

enter image description here

I guess after WHM update this settings was turn on somehow or probably this is a new settings, I am not sure.

Arvind K.
  • 1,184
  • 2
  • 13
  • 27
-1

Reading app/config/mailphp

Supported : "smtp", "mail", "sendmail"

Depending on your mail utilities installed on your machine, fill in the value of the driver key. I would do

'driver' => 'sendmail',
-1

for Laravel 5.4
for gmail


in .env file

MAIL_DRIVER=mail
MAIL_HOST=mail.gmail.com
MAIL_PORT=587
MAIL_USERNAME=<username>@gmail.com
MAIL_PASSWORD=<password>
MAIL_ENCRYPTION=tls

in config/mail.php

'driver' => env('MAIL_DRIVER', 'mail'),

'from' => [
    'address' => env(
        'MAIL_FROM_ADDRESS', '<username>@gmail.com'
    ),
    'name' => env(
        'MAIL_FROM_NAME', '<from_name>'
    ),
],
Pasindu Jayanath
  • 892
  • 10
  • 27
-1

Go to vendor\swiftmailer\swiftmailer\lib\classes\Swift\Transport\StreamBuffer.php

comment line 250 and add this line:

//$options = [];
$options['ssl'] = array('verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true);
    
Adem Kouki
  • 17
  • 1
  • 3
-2
$default = [ ... ];

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

$environment = env('APP_ENV');

if ($environment === 'local') {
    return array_merge($default, $turnOffSSL);
}

return $default;
Mhar Daniel
  • 475
  • 5
  • 11