This tutorial is out of date and no longer maintained.
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.
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.
Mailtrap is awesome for development and testing. It was not built with sending emails in production in mind.
https://mailtrap.io/inboxes
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.
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.
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
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.
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
:
- 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:
Below is an image of this mail as it arrives in Mailtrap
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()
.
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.
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:
- 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:
- sude nohup php artisan queue:work --daemon --tries=3
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.
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.
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:
- MAILCHIMP_KEY=[KEY]
- MAILCHIMP_LIST_ID=[ID]
Then pull Mandrill’s PHP SDK from composer:
- composer require mailchimp/mailchimp
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');
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.
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!