Tutorial

Ultimate Guide on Sending Email in Laravel

Draft updated on Invalid Date
Default avatar

By Chris Nwamba

Ultimate Guide on Sending Email in Laravel

This tutorial is out of date and no longer maintained.

Introduction

Sending emails in web applications has become so essential. Marketing, notifications, newsletters, adverts, etc. are some of the reasons why we send emails to our clients. I’d say the majority of websites send automated emails at least via a “Contact us” form.

Let’s explore the many possible ways to send emails in a Laravel application.

Choosing An Email Service Provider

Although your first thought when you see “Email Service Provider” may be service providers in Laravel, that is not what I am referring to here. I am referring to online services that provide email sending functionalities via APIs.

You might be wondering why you need to make use of a service when you can just go hardcore with SMTP. The old way works fine, no doubt, but if you really want something awesome, robust, scalable, and economic, then a service provider is better as it does all the hard jobs and just gives you an endpoint for your program to talk to,

We are going to review several possible providers and how to set them up in a Laravel application. Speaking of which, install a new Laravel application and leave config/services.php open in your favorite editor.

Mailgun

  1. Sign up for an account if you have not.
  2. Verify your email and phone number.
  3. You will be redirected to your Dashboard.
  4. Locate your API Key and domain

Mailgun Keys

Mailgun Domain

Mailtrap

Mailtrap is awesome for development and testing. It was not built with sending emails in production in mind.

  1. Sign up
  2. Verify if necessary
  3. Access your inboxes via https://mailtrap.io/inboxes
  4. Store the SMTP credentials somewhere safe

Mailtrap Credentials

Mandrill

  1. Sign up
  2. Setup a domain name

Mandrill Domain

  1. Go to settings from the left menu
  2. Click Add API key

Mandrill Key

  1. Add Mandrill option in the config/services.php file
'mandrill' => [
    'secret' => env('MANDRILL_KEY'),
],

There are several more options, including Amazon SES, but we will just focus on a few. They are all very similar to set up so let us just stick with learning with what we have.

Configuring Our Services

Our config/services.php has all the configuration for major external services that are required for our application. It is also recommended that if Laravel does not provide any service, you should stick to the design pattern of using the services config file to configure your application.

 'mailgun' => [
        'domain' => env('MAILGUN_DOMAIN'),
        'secret' => env('MAILGUN_SECRET'),
    ],

    'mandrill' => [
        'secret' => env('MANDRILL_KEY'),
    ],

    'ses' => [
        'key' => env('SES_KEY'),
        'secret' => env('SES_SECRET'),
        'region' => 'us-east-1',
    ],

    'sparkpost' => [
        'secret' => env('SPARKPOST_SECRET'),
    ],

    'stripe' => [
        'model' => App\User::class,
        'key' => env('STRIPE_KEY'),
        'secret' => env('STRIPE_SECRET'),
    ],

Notice that Mailtrap is missing here. It uses SMTP and is provided as default in every Laravel installation because it is made for testing purposes.

A practice really frowned upon is storing credentials in codes as they may leak to the wrong hands, especially while moving a codebase around in a VCS. For this reason, Laravel uses a .env file for storing its credentials and environmental variables:

APP_ENV=local
APP_DEBUG=true
APP_KEY=[APPLICATION_KEY]
APP_URL=http://localhost

DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp

MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=[MAILTRAP_USERNAME]
MAIL_PASSWORD=[MAILTRAP_PASSWORD]
MAIL_ENCRYPTION=null

MAILGUN_DOMAIN=[MAILGUN_DOMAIN]
MAILGUN_SECRET=[MAILGUN_SECRET]

MANDRILL_KEY=[MANDRILL_KEY]

You can go ahead to replace the usernames, passwords, keys, domains, and secrets you got while registering for the email services.

Setting a Default Option

As I already mentioned, we cannot use all the services at the same time. In that case, even after setting up multiple providers, we still need to tell Laravel which one to use:

//SMTP/Mailtrap
MAIL_DRIVER=smtp

//Mailgun
MAIL_DRIVER=mailgun

//Mandrill
MAIL_DRIVER=mandrill

//etc

Sending Emails

Setting up the services and configuring them does not actually send the emails, but it is an amazing step we have taken together. We can do better. Let us send an email.

A Basic Approach

We will use RESTful approach to send the emails because it is the standard. So get your Postman ready to do some jobs.

We do not need a Model or a View with where we are headed. Instead, we just need a controller and a route. Create a controller named EmailController:

  1. php artisan make:controller EmailController

Now add a simple route to app/Http/routes.php:

Route::post('/send', 'EmailController@send');

Our controller is pointing to the controller we created and is asking the send action method to process the request. Let us go ahead and create the send action method:

Note: Action methods are methods in a controller that handle a request.

public function send(Request $request){
    //Logic will go here
}

That is a basic method waiting and ready to be fleshed out. We have also type-hinted Request if we need anything to do with the request object.

To send HTML emails, we need to create a template for that. Create a send.blade.php file in resources/views/emails with the following:

<html>
<head></head>
<body style="background: black; color: white">
<h1>{{$title}}</h1>
<p>{{$content}}</p>
</body>
</html>

Back to the action method. It is time to actually add the mail sending logic which can be done using the Mail facade:

 public function send(Request $request)
    {
        $title = $request->input('title');
        $content = $request->input('content');

        Mail::send('emails.send', ['title' => $title, 'content' => $content], function ($message)
        {

            $message->from('me@gmail.com', 'Christian Nwamba');

            $message->to('chrisn@scotch.io');

        });


        return response()->json(['message' => 'Request completed']);
    }

The Mail Facade which is used to handle emails in Laravel provides several methods including send(). The send() method takes 3 parameters: a blade view, data to be bound to the view, and a closure. You can configure the mail however you want in the closure.

Head to Postman and make a Post request to /send with title and content as seen below:

Postman POST email

Below is an image of this mail as it arrives in Mailtrap

Mailtrap email

We can configure all the properties of an email right inside the closure. Below are the available options as provided by Taylor:

$message->from($address, $name = null);
$message->sender($address, $name = null);
$message->to($address, $name = null);
$message->cc($address, $name = null);
$message->bcc($address, $name = null);
$message->replyTo($address, $name = null);
$message->subject($subject);
$message->priority($level);
$message->attach($pathToFile, array $options = []);

Let us experiment with one more of the features which is $message->attach().

Attaching Files

Use the attach() method and supply a file path to attach files.

 public function send(Request $request)
    {
        $title = $request->input('title');
        $content = $request->input('content');
        //Grab uploaded file
        $attach = $request->file('file');

        Mail::send('emails.send', ['title' => $title, 'content' => $content], function ($message) use ($attach)
        {

            $message->from('me@gmail.com', 'Christian Nwamba');

            $message->to('chrisn@scotch.io');

            //Attach file
            $message->attach($attach);

            //Add a subject
            $message->subject("Hello from Scotch");

        });

We requested a file uploaded via a form and attached it to the mail. Notice that we also added a subject to the email.

Postman POST email attachment

Mailtrap email attachment

Optimizing with Queues

You can now use queues to optimize sending emails. Instead of sending with the send() method, we send with the queue() method:

 public function send(Request $request)
    {
        //Using queues is better
        Mail::queue('emails.send', ['title' => $title, 'content' => $content], function ($message) use ($attach)
        {


        });
    }

Remember that we have to run the listen command on the queues before they can be dispatched:

  1. php artisan queue:listen

In production, it is not advisable to use listen because of its high CPU usage. It is better we use work and pass the --daemon option:

  1. sude nohup php artisan queue:work --daemon --tries=3

Bonus: Bulk Email Notifications with MailChimp

As this article is one about sending emails, it would be nice to consider sending bulk emails. The popular tool that handles this is Mailchimp so let’s try that out.

Setup MailChimp

Setting up Mailchimp involves two steps - account creation and Laravel project setup. To create a MailChimp account, head straight to the Sign up page, sign up, and verify your account if required.

Next, create a list of your subscribers. In a real project, you would be adding users to the list programmatically using the API, but we can just go ahead and create some via the dashboard as seen below.

Add subscribers to Mailchimp

Now grab the List Id by going to Settings > List name and defaults. Also create and get your API key from User > Accounts > Extras > API Keys. User stands for your username, which is on the navigation bar.

Head back to the Laravel project and store the key and Id in .env:

  1. MAILCHIMP_KEY=[KEY]
  2. MAILCHIMP_LIST_ID=[ID]

Then pull Mandrill’s PHP SDK from composer:

  1. composer require mailchimp/mailchimp

Sending Campaigns

Mailchimp’s bulk emails are identified as campaigns. Let us create another simple action method to handle sending bulk messages to our list of subscribers:

public function notify(Request $request){

        //List ID from .env
        $listId = env('MAILCHIMP_LIST_ID');

        //Mailchimp instantiation with Key
        $mailchimp = new \Mailchimp(env('MAILCHIMP_KEY'));

        //Create a Campaign $mailchimp->campaigns->create($type, $options, $content)
        $campaign = $mailchimp->campaigns->create('regular', [
            'list_id' => $listId,
            'subject' => 'New Article from Scotch',
            'from_email' => 'pub@gmail.com',
            'from_name' => 'Scotch Pub',
            'to_name' => 'Scotch Subscriber'

        ], [
            'html' => $request->input('content'),
            'text' => strip_tags($request->input('content'))
        ]);

        //Send campaign
        $mailchimp->campaigns->send($campaign['id']);

        return response()->json(['status' => 'Success']);
    }

We are using two campaign methods: create() and send(). The create() method provisions a campaign and returns an array that contains the id of our campaign. We then pass this id to the send() method to dispatch the emails. That’s all!

Go ahead and add the extra route:

Route::post('/notify', 'EmailController@notify');

Conclusion

If your web application sends emails, it is recommended you take the extra mile and use useful services to optimize the whole process. Test your emails with Mailtrap, send with Mandrill/Mailgun/SES or anything that suits you, and optimize with Queues.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Chris Nwamba

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel