Laravel provides a clean, simple API over the popular SwiftMailer library with drivers for SMTP, Mailgun, SparkPost, Amazon SES, PHP's mail
function, and sendmail
, allowing you to quickly get started sending mail through a local or cloud based service of your choice.
The API based drivers such as Mailgun and SparkPost are often simpler and faster than SMTP servers. If possible, you should use one of these drivers. All of the API drivers require the Guzzle HTTP library, which may be installed via the Composer package manager:
composer require guzzlehttp/guzzle
To use the Mailgun driver, first install Guzzle, then set the driver
option in your config/mail.php
configuration file to mailgun
. Next, verify that your config/services.php
configuration file contains the following options:
'mailgun' => [
'domain' => 'your-mailgun-domain',
'secret' => 'your-mailgun-key',
],
To use the SparkPost driver, first install Guzzle, then set the driver
option in your config/mail.php
configuration file to sparkpost
. Next, verify that your config/services.php
configuration file contains the following options:
'sparkpost' => [
'secret' => 'your-sparkpost-key',
],
To use the Amazon SES driver you must first install the Amazon AWS SDK for PHP. You may install this library by adding the following line to your composer.json
file's require
section and running the composer update
command:
"aws/aws-sdk-php": "~3.0"
Next, set the driver
option in your config/mail.php
configuration file to ses
and verify that your config/services.php
configuration file contains the following options:
'ses' => [
'key' => 'your-ses-key',
'secret' => 'your-ses-secret',
'region' => 'ses-region', // e.g. us-east-1
],
In Laravel, each type of email sent by your application is represented as a "mailable" class. These classes are stored in the app/Mail
directory. Don't worry if you don't see this directory in your application, since it will be generated for you when you create your first mailable class using the make:mail
command:
php artisan make:mail OrderShipped
All of a mailable class' configuration is done in the build
method. Within this method, you may call various methods such as from
, subject
, view
, and attach
to configure the email's presentation and delivery.
First, let's explore configuring the sender of the email. Or, in other words, who the email is going to be "from". There are two ways to configure the sender. First, you may use the from
method within your mailable class' build
method:
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->from('[email protected]')
->view('emails.orders.shipped');
}
However, if your application uses the same "from" address for all of its emails, it can become cumbersome to call the from
method in each mailable class you generate. Instead, you may specify a global "from" address in your config/mail.php
configuration file. This address will be used if no other "from" address is specified within the mailable class:
'from' => ['address' => '[email protected]', 'name' => 'App Name'],
Within a mailable class' build
method, you may use the view
method to specify which template should be used when rendering the email's contents. Since each email typically uses a Blade template to render its contents, you have the full power and convenience of the Blade templating engine when building your email's HTML:
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped');
}
{tip} You may wish to create a
resources/views/emails
directory to house all of your email templates; however, you are free to place them wherever you wish within yourresources/views
directory.
If you would like to define a plain-text version of your email, you may use the text
method. Like the view
method, the text
method accepts a template name which will be used to render the contents of the email. You are free to define both a HTML and plain-text version of your message:
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->text('emails.orders.shipped_plain');
}
Typically, you will want to pass some data to your view that you can utilize when rendering the email's HTML. There are two ways you may make data available to your view. First, any public property defined on your mailable class will automatically be made available to the view. So, for example, you may pass data into your mailable class' constructor and set that data to public properties defined on the class:
<?php
namespace App\Mail;
use App\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
/**
* The order instance.
*
* @var Order
*/
public $order;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped');
}
}
Once the data has been set to a public property, it will automatically be available in your view, so you may access it like you would access any other data in your Blade templates:
<div>
Price: {{ $order->price }}
</div>
If you would like to customize the format of your email's data before it is sent to the template, you may manually pass your data to the view via the with
method. Typically, you will still pass data via the mailable class' constructor; however, you should set this data to protected
or private
properties so the data is not automatically made available to the template. Then, when calling the with
method, pass an array of data that you wish to make available to the template:
<?php
namespace App\Mail;
use App\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
/**
* The order instance.
*
* @var Order
*/
protected $order;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->with([
'orderName' => $this->order->name,
'orderPrice' => $this->order->price,
]);
}
}
Once the data has been passed to the with
method, it will automatically be available in your view, so you may access it like you would access any other data in your Blade templates:
<div>
Price: {{ $orderPrice }}
</div>
To add attachments to an email, use the attach
method within the mailable class' build
method. The attach
method accepts the full path to the file as its first argument:
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attach('/path/to/file');
}
When attaching files to a message, you may also specify the display name and / or MIME type by passing an array
as the second argument to the attach
method:
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attach('/path/to/file', [
'as' => 'name.pdf',
'mime' => 'application/pdf',
]);
}
The attachData
method may be used to attach a raw string of bytes as an attachment. For example, you might use this method if you have generated a PDF in memory and want to attach it to the email without writing it to disk. The attachData
method accepts the raw data bytes as its first argument, the name of the file as its second argument, and an array of options as its third argument:
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attachData($this->pdf, 'name.pdf', [
'mime' => 'application/pdf',
]);
}
Embedding inline images into your emails is typically cumbersome; however, Laravel provides a convenient way to attach images to your emails and retrieving the appropriate CID. To embed an inline image, use the embed
method on the $message
variable within your email template. Laravel automatically makes the $message
variable available to all of your email templates, so you don't need to worry about passing it in manually:
<body>
Here is an image:
<img src="{{ $message->embed($pathToFile) }}">
</body>
If you already have a raw data string you wish to embed into an email template, you may use the embedData
method on the $message
variable:
<body>
Here is an image from raw data:
<img src="{{ $message->embedData($data, $name) }}">
</body>
To send a message, use the to
method on the Mail
facade. The to
method accepts an email address, a user instance, or a collection of users. If you pass an object or collection of objects, the mailer will automatically use their email
and name
properties when setting the email recipients, so make sure these attributes are available on your objects. Once you have specified your recipients, you may pass an instance of your mailable class to the send
method:
<?php
namespace App\Http\Controllers;
use App\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Http\Controllers\Controller;
class OrderController extends Controller
{
/**
* Ship the given order.
*
* @param Request $request
* @param int $orderId
* @return Response
*/
public function ship(Request $request, $orderId)
{
$order = Order::findOrFail($orderId);
// Ship order...
Mail::to($request->user())->send(new OrderShipped($order));
}
}
Of course, you are not limited to just specifying the "to" recipients when sending a message. You are free to set "to", "cc", and "bcc" recipients all within a single, chained method call:
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->send(new OrderShipped($order));
Since sending email messages can drastically lengthen the response time of your application, many developers choose to queue email messages for background sending. Laravel makes this easy using its built-in unified queue API. To queue a mail message, use the queue
method on the Mail
facade after specifying the message's recipients:
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->queue(new OrderShipped($order));
This method will automatically take care of pushing a job onto the queue so the message is sent in the background. Of course, you will need to configure your queues before using this feature.
If you wish to delay the delivery of a queued email message, you may use the later
method. As its first argument, the later
method accepts a DateTime
instance indicating when the message should be sent:
$when = Carbon\Carbon::now()->addMinutes(10);
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->later($when, new OrderShipped($order));
Since all mailable classes generated using the make:mail
command make use of the Illuminate\Bus\Queueable
trait, you may call the onQueue
and onConnection
methods on any mailable class instance, allowing you to specify the connection and queue name for the message:
$message = (new OrderShipped($order))
->onConnection('sqs')
->onQueue('emails');
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->queue($message);
When developing an application that sends email, you probably don't want to actually send emails to live email addresses. Laravel provides several ways to "disable" the actual sending of emails during local development.
Instead of sending your emails, the log
mail driver will write all email messages to your log files for inspection. For more information on configuring your application per environment, check out the configuration documentation.
Another solution provided by Laravel is to set a universal recipient of all emails sent by the framework. This way, all the emails generated by your application will be sent to a specific address, instead of the address actually specified when sending the message. This can be done via the to
option in your config/mail.php
configuration file:
'to' => [
'address' => '[email protected]',
'name' => 'Example'
],
Finally, you may use a service like Mailtrap and the smtp
driver to send your email messages to a "dummy" mailbox where you may view them in a true email client. This approach has the benefit of allowing you to actually inspect the final emails in Mailtrap's message viewer.
Laravel fires an event just before sending mail messages. Remember, this event is fired when the mail is sent, not when it is queued. You may register an event listener for this event in your EventServiceProvider
:
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Illuminate\Mail\Events\MessageSending' => [
'App\Listeners\LogSentMessage',
],
];