Send mail via SMTP with self-signed certificate with Laravel 5.2

I’m currently writing an application using Laravel 5.2 but needed to send mail via SMTP with self-signed certificate. I didn’t want to edit the SwiftMailer library directly for obvious reasons.

The version of Laravel currently being used for this application is 5.2.6, which comes with SwiftMailer 5.4.1. We need version 5.4.2 or higher so we can use the setStreamOptions() method of Swift_SmtpTransport, so I updated this via Composer.

config/mail.php

I added some new options to the config/mail.php file:

'ssloptions' => [
    'allow_self_signed' => env('MAIL_SSLOPTIONS_ALLOW_SELF_SIGNED', false),
    'verify_peer' => env('MAIL_SSLOPTIONS_VERIFY_PEER', true),
    'verify_peer_name' => env('MAIL_SSLOPTIONS_VERIFY_PEER_NAME', true),
],

This sets up the SSL options we need and they can be overridden in the .env file. These defaults are the same defaults that SwiftMailer uses out-of-the-box.

Laravel .env overrides

I then added the overrides in .env:

MAIL_SSLOPTIONS_ALLOW_SELF_SIGNED=true
MAIL_SSLOPTIONS_VERIFY_PEER=false
MAIL_SSLOPTIONS_VERIFY_PEER_NAME=false

My whole MAIL section in the .env file looks like:

MAIL_DRIVER=smtp
MAIL_HOST=smtp.domain.com
MAIL_PORT=587
MAIL_USERNAME=username@example.com
MAIL_PASSWORD=my_email_password
MAIL_ENCRYPTION=tls
MAIL_SSLOPTIONS_ALLOW_SELF_SIGNED=true
MAIL_SSLOPTIONS_VERIFY_PEER=false
MAIL_SSLOPTIONS_VERIFY_PEER_NAME=false

Controller code

I then constructed the SmtpTransport and SmtpMailer manually in the controller and passed the mailer to the Mail facade:

// Send email notification
$transport = Swift_SmtpTransport::newInstance(
    \Config::get('mail.host'),
    \Config::get('mail.port'),
    \Config::get('mail.encryption'))
    ->setUsername(\Config::get('mail.username'))
    ->setPassword(\Config::get('mail.password'))
    ->setStreamOptions(['ssl' => \Config::get('mail.ssloptions')]);

$mailer = Swift_Mailer::newInstance($transport);
Mail::setSwiftMailer($mailer);

Send the mail via SMTP with self-signed certificate

We can then use the Mail facade as per the Laravel docs:

Mail::send(
    'emails.html-email-template', $templateData, function (\Illuminate\Mail\Message $message) {
        $message->subject('Email notification');
        $message->from('from@example.com', 'From name');
        $message->to('to@example.com', 'To name');
    }
);

Finally, I was able to send the email notifications without SSL errors.