Introducción

Laravel proporciona una API limpia y simple sobre la popular biblioteca SwiftMailer con drivers para SMTP, Mailgun, Postmark, Amazon SES y sendmail, permitiéndote comenzar rápidamente a enviar correos a través de un servicio local o en la nube de tu elección.

Requisitos previos del driver

Los drivers basados ​​en una API como Mailgun y Postmark suelen ser más simples y rápidos que los servidores SMTP. Si es posible, deberías usar uno de estos drivers. Todos los drivers con API requieren la biblioteca Guzzle HTTP, que puede instalarse a través del manejador de paquetes Composer:

composer require guzzlehttp/guzzle

Driver Mailgun

Para usar el driver de Mailgun, primero instala Guzzle, luego configura la opción driver en tu archivo de configuración config/mail.php en mailgun. Luego, verifica que tu archivo de configuración config/services.php contenga las siguientes opciones:

'mailgun' => [
    'domain' => 'your-mailgun-domain',
    'secret' => 'your-mailgun-key',
],

Si no estás usando la región de Mailgun «US», puedes definir el endpoint de tu región en el archivo de configuración services:

'mailgun' => [
    'domain' => 'your-mailgun-domain',
    'secret' => 'your-mailgun-key',
    'endpoint' => 'api.eu.mailgun.net',
],

Driver Postmark

Para usar el driver de Postmark, instala el transporte de SwiftMailer de Postmark mediante Composer:

composer require wildbit/swiftmailer-postmark

Luego, instala Guzzle y establece la opción driver en tu archivo de configuración config/mail.php a postmark. Finalmente, verifica que tu archivo de configuración config/services.php contiene las siguientes opciones:

'postmark' => [
    'token' => 'your-postmark-token',
],

Driver SES

Para usar el driver de Amazon SES, primero debes instalar Amazon AWS SDK para PHP. Puedes instalar esta librería agregando la siguiente línea a la sección require del archivo composer.json y ejecutando el comando composer update:

"aws/aws-sdk-php": "~3.0"

A continuación, configura la opción driver en tu archivo de configuración config/mail.php en ses y verifica que tu archivo de configuración config/services.php contenga las siguientes opciones:

'ses' => [
    'key' => 'your-ses-key',
    'secret' => 'your-ses-secret',
    'region' => 'ses-region',  // e.g. us-east-1
],

Si necesitas incluir opciones adicionales al ejecutar la solicitud SendRawEmail de SES, puedes definir un arreglo options dentro de tu configuración de ses:

'ses' => [
    'key' => 'your-ses-key',
    'secret' => 'your-ses-secret',
    'region' => 'ses-region',  // e.g. us-east-1
    'options' => [
        'ConfigurationSetName' => 'MyConfigurationSet',
        'Tags' => [
            [
                'Name' => 'foo',
                'Value' => 'bar',
            ],
        ],
    ],
],

Generando mailables

En Laravel, cada tipo de correo electrónico enviado por tu aplicación se representa como una clase «mailable». Estas clases se almacenan en el directorio app/Mail. No te preocupes si no ves este directorio en tu aplicación, ya que se generará para ti cuando crees tu primera clase mailable usando el comando make:mail:

php artisan make:mail OrderShipped

Escribiendo mailables

Toda la configuración de una clase mailable se realiza en el método build. Dentro de este método, puedes llamar a varios métodos como from, subject, view y attach para configurar la presentación y entrega del correo electrónico.

Configurando el remitente

Usando el método from

Primero, exploremos la configuración del remitente para el correo electrónico. O, en otras palabras, de quién será el correo electrónico (from). Hay dos formas de configurar el remitente. En primer lugar, puedes usar el método from dentro del método build de tu clase mailable:

/**
* Build the message.
*
* @return $this
*/
public function build()
{
    return $this->from('[email protected]')
                ->view('emails.orders.shipped');
}

Usando una dirección global con from

Sin embargo, si tu aplicación utiliza la misma dirección «from» para todos sus correos electrónicos, puede resultar engorroso llamar al método from en cada clase mailable que generes. En su lugar, puedes especificar una dirección global «from» en tu archivo de configuración config/mail.php. Esta dirección se usará si no se especifica ninguna otra dirección «from» dentro de la clase mailable:

'from' => ['address' => '[email protected]', 'name' => 'App Name'],

Adicionalmente, puedes definir una dirección global «reply_to» dentro de tu archivo de configuración config/mail.php:

'reply_to' => ['address' => '[email protected]', 'name' => 'App Name'],

Configurando la vista

Dentro de un método build de la clase mailable, puedes usar el método view para especificar qué plantilla se debe usar al renderizar los contenidos del correo electrónico. Dado que cada correo electrónico generalmente usa una Plantilla Blade para renderizar sus contenidos, tienes toda la potencia y la comodidad del motor de plantillas Blade al construir el HTML de tu correo electrónico:

/**
* Build the message.
*
* @return $this
*/
public function build()
{
    return $this->view('emails.orders.shipped');
}

Es posible que desees crear un directorio resources/views/emails para albergar todas tus plantillas de correos electrónicos; sin embargo, puedes colocarlos donde quieras siempre y cuando estén dentro del directorio resources/views.

Correos con texto plano

Si deseas definir una versión de texto sin formato en tu correo electrónico, puedes usar el método text. Al igual que el método view, el método text acepta un nombre de plantilla que se usará para renderizar el contenido del correo electrónico. Eres libre de definir una versión HTML y de texto sin formato del mensaje:

/**
* Build the message.
*
* @return $this
*/
public function build()
{
    return $this->view('emails.orders.shipped')
                ->text('emails.orders.shipped_plain');
}

Datos en vistas

A través de propiedades públicas

Por lo general, querrás pasar algunos datos a tu vista que puedes utilizar al renderizar el HTML del correo electrónico. Hay dos maneras en que puedes hacer que los datos estén disponibles para la vista. Primero, cualquier propiedad pública definida en tu clase mailable se pondrá automáticamente a disposición de la vista. Entonces, por ejemplo, puedes pasar datos al constructor de tu clase mailable y establecer esos datos a propiedades públicas definidas en la clase:

<?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');
    }
}

Una vez que los datos se han establecido en una propiedad pública, estarán automáticamente disponibles en tu vista, por lo que puedes acceder a ella como si tuvieras acceso a cualquier otro dato en tus plantillas Blade:

<div>
    Price: {{ $order->price }}
</div>

A través del método with:

Si deseas personalizar el formato de los datos de tu correo electrónico antes de enviarlos a la plantilla, puedes pasar manualmente los datos a la vista mediante el método with. Por lo general, aún podrás pasar datos a través del constructor de la clase mailable; sin embargo, debes establecer estos datos en propiedades protected o private para que los datos no estén automáticamente disponibles para la plantilla. Luego, al llamar al método with, pasa un arreglo de datos que deseas poner a disposición de la plantilla:

<?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,
                    ]);
    }
}

Una vez que los datos se han pasado con el método with, estarán automáticamente disponibles en la vista, por lo que puedes acceder a ellos como lo harías con cualquier otro dato en las plantillas Blade:

<div>
    Price: {{ $orderPrice }}
</div>

Archivos adjuntos

Para agregar archivos adjuntos a un correo electrónico, podemos usar el método attach dentro del método build de la clase mailable. El método attach acepta la ruta completa al archivo como su primer argumento:

/**
* Build the message.
*
* @return $this
*/
public function build()
{
    return $this->view('emails.orders.shipped')
                ->attach('/path/to/file');
}

Al adjuntar archivos a un mensaje, también puedes especificar el nombre para mostrar y / o el tipo MIME pasando un array como segundo argumento al método attach:

/**
* Build the message.
*
* @return $this
*/
public function build()
{
    return $this->view('emails.orders.shipped')
                ->attach('/path/to/file', [
                    'as' => 'name.pdf',
                    'mime' => 'application/pdf',
                ]);
}

Adjuntando archivos desde el disco

Si has almacenado un archivo en uno de tus discos, puedes adjuntarlo al correo electrónico usando el método attachFromStorage:

/**
* Build the message.
*
* @return $this
*/
public function build()
{
    return $this->view('email.orders.shipped')
                ->attachFromStorage('/path/to/file');
}

De ser necesario, puedes especificar el nombre del archivo adjunto y opciones adicionales usando el segundo y tercer argumento del método attachFromStorage:

/**
* Build the message.
*
* @return $this
*/
public function build()
{
    return $this->view('email.orders.shipped')
                ->attachFromStorage('/path/to/file', 'name.pdf', [
                    'mime' => 'application/pdf'
                ]);
}

El método attachFromStorageDisk puede ser usado si necesitas especificar un disco de almacenamiento diferente a tu disco por defecto:

/**
* Build the message.
*
* @return $this
*/
public function build()
{
    return $this->view('email.orders.shipped')
                ->attachFromStorageDisk('s3', '/path/to/file');
}

Archivos adjuntos desde la memoria

El método attachData se puede usar para adjuntar una cadena de bytes sin formato como un archivo adjunto. Por ejemplo, puedes usar este método si has generado un PDF en la memoria y deseas adjuntarlo al correo electrónico sin escribirlo en el disco. El método attachData acepta los bytes de datos brutos como su primer argumento, el nombre del archivo como su segundo argumento y un arreglo de opciones como su tercer argumento:

/**
* Build the message.
*
* @return $this
*/
public function build()
{
    return $this->view('emails.orders.shipped')
                ->attachData($this->pdf, 'name.pdf', [
                    'mime' => 'application/pdf',
                ]);
}

Archivos adjuntos en línea

La incrustación de imágenes en línea en tus correos electrónicos suele ser engorrosa; sin embargo, Laravel proporciona una forma conveniente de adjuntar imágenes a tus correos electrónicos y recuperar el CID apropiado. Para incrustar una imagen en línea, usa el método embed en la variable $message dentro de tu plantilla de correo electrónico. Laravel automáticamente hace que la variable $message esté disponible para todas tus plantillas de correo electrónico, por lo que no tienes que preocuparte por pasarla manualmente:

<body>
    Here is an image:

    <img src="{{ $message->embed($pathToImage) }}">
</body>

La variable $message no está disponible en los mensajes de texto plano, ya que estos mensajes (plain-text) no utilizan archivos adjuntos en línea.

Incrustar datos adjuntos de la memoria

Si ya tienes una cadena de datos en la memoria que desees incorporar a una plantilla de correo electrónico, puedes usar el método embedData en la variable $message:

<body>
    Here is an image from raw data:

    <img src="{{ $message->embedData($data, $name) }}">
</body>

Personalizar el mensaje de SwiftMailer

El método withSwiftMessage de la clase base Mailable te permite registrar una función anónima que se invocará con la instancia del mensaje de SwiftMailer sin procesar antes de enviar el mensaje. Esto te da la oportunidad de personalizar el mensaje antes de que se entregue:

/**
* Build the message.
*
* @return $this
*/
public function build()
{
    $this->view('emails.orders.shipped');

    $this->withSwiftMessage(function ($message) {
        $message->getHeaders()
                ->addTextHeader('Custom-Header', 'HeaderValue');
    });
}

Mailables en markdown

Los mensajes para mailables escritos con Markdown te permiten aprovechar las plantillas y los componentes precompilados de las notificaciones por correo en tus mailables. Dado que los mensajes se escriben en Markdown, Laravel puede generar plantillas HTML atractivas y responsivas para los mensajes, y generar automáticamente una contraparte de texto sin formato.

Generar mailables en markdown

Para generar una clase mailable con una plantilla para Markdown, puedes usar la opción --markdown del comando Artisan make:mail:

php artisan make:mail OrderShipped --markdown=emails.orders.shipped

Luego de generar la clase, dentro de su método build, debes llamar al método markdown en lugar del método view. El método markdown acepta el nombre de la plantilla Markdown y un arreglo opcional de datos para poner a disposición de la plantilla:

/**
* Build the message.
*
* @return $this
*/
public function build()
{
    return $this->from('[email protected]')
                ->markdown('emails.orders.shipped');
}

Escribir mensajes en Markdown

Los correos de mailables con Markdown utilizan una combinación de componentes Blade y sintaxis Markdown que te permiten construir fácilmente mensajes de correo al mismo tiempo que aprovechas los componentes prefabricados de Laravel:

@component('mail::message')
# Order Shipped

Your order has been shipped!

@component('mail::button', ['url' => $url])
View Order
@endcomponent

Thanks,<br>
{{ config('app.name') }}
@endcomponent

No uses una sangría excesiva al escribir correos electrónicos de Markdown. Los analizadores de Markdown renderizarán contenido sangrado como bloques de código.

Componente button

El componente de botón renderiza un enlace de botón centrado. El componente acepta dos argumentos, una url y un color opcional. Los colores compatibles son primary, success y error. Puedes agregar los botones que desees a un mensaje:

@component('mail::button', ['url' => $url, 'color' => 'success'])
View Order
@endcomponent

Componente panel

El componente del panel renderiza el bloque de texto dado en un panel que tiene un color de fondo ligeramente diferente que el resto del mensaje. Esto te permite llamar la atención sobre un bloque de texto dado:

@component('mail::panel')
This is the panel content.
@endcomponent

Componente table

El componente de tabla te permite transformar una tabla en Markdown a una tabla HTML. El componente acepta la tabla en Markdown como su contenido. La alineación de columna de tabla es compatible con la sintaxis de alineación de tabla de Markdown predeterminada:

@component('mail::table')
| Laravel       | Table         | Example  |
| ------------- |:-------------:| --------:|
| Col 2 is      | Centered      | $10      |
| Col 3 is      | Right-Aligned | $20      |
@endcomponent

Personalizar los componentes

Puedes exportar todos los componentes de correo Markdown a su propia aplicación para personalización. Para exportar los componentes, use el comando Artisan vendor:publish y la opción del tag laravel-mail de esta forma:

php artisan vendor:publish --tag=laravel-mail

Este comando publicará los componentes de correo Markdown en el directorio resources/views/vendor/mail. El directorio mail contendrá un directorio html y otro text, cada uno con sus respectivas representaciones de cada componente disponible. Eres libre de personalizar estos componentes como desees.

Personalizar el CSS

Después de exportar los componentes, el directorio resources/views/vendor/mail/html/themes contendrá un archivo default.css. Puedes personalizar el CSS en este archivo y tus estilos se alinearán automáticamente en las representaciones HTML de tus mensajes de correo Markdown.

Si te gustaría construir un nuevo tema para los componentes de Markdown de Laravel, puedes colocar un archivo CSS dentro del directorio html/themes. Luego de nombrar y guardar tu archivo de CSS, actualiza la opción theme del archivo de configuración mail con el nuevo nombre de tu tema.

Para personalizar un tema para un mailable individual, debes establecer la propiedad $theme de la clase mailable al nombre del tema que debería ser usado al enviar el mailable.

Enviar correo

Para enviar un mensaje, debes usar el método to del facade Mail. El método to acepta una dirección de correo electrónico, una instancia de usuario o una colección de usuarios. Si pasas un objeto o una colección de objetos, el remitente utilizará automáticamente sus propiedades email y name cuando configure los destinatarios del correo electrónico, por lo tanto, asegúrate que estos atributos estén disponibles en tus objetos. Una vez que hayas especificado tus destinatarios, puedes pasar una instancia de tu clase mailable al método send:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Mail\OrderShipped;
use App\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;

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));
    }
}

No estás limitado a especificar sólo los destinatarios «to» al enviar un mensaje. Eres libre de configurar los destinatarios «to», «cc» y «bcc», todo dentro de una única llamada a un método encadenado:

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->send(new OrderShipped($order));

Renderizar mailables

Algunas veces puedes querer capturar el contenido HTML de un mailable sin enviarlo. Para lograr esto, puedes llamar al método render del mailable. Este método retornará los contenidos evaluados del mailable como una cadena:

$invoice = App\Invoice::find(1);

return (new App\Mail\InvoicePaid($invoice))->render();

Previsualizar mailables en el navegador

Al diseñar una plantilla mailable, es conveniente previsualizar rápidamente el mailable renderizado en tu navegador como una plantilla de Blade corriente. Por esta razón, Laravel te permite retornar cualquier mailable directamente desde un Closure de ruta o un controlador. Cuando un mailable es retornado, será renderizado y mostrado en el navegador, permitiéndote previsualizar su diseño sin necesidad de enviarlo a una dirección de correo electrónico real:

Route::get('mailable', function () {
    $invoice = App\Invoice::find(1);

    return new App\Mail\InvoicePaid($invoice);
});

Correo en cola

Poniendo en cola un correo electrónico

Dado que el envío de correos electrónicos puede alargar drásticamente el tiempo de respuesta de la aplicación, muchos desarrolladores eligen poner los correos electrónicos en cola para enviarlos en segundo plano. Laravel hace esto fácil usando su función incorporada API de cola unificada. Para poner en cola un correo, usa el método queue en el facade Mail después de especificar los destinatarios del mensaje:

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->queue(new OrderShipped($order));

Este método se encargará automáticamente de insertar un trabajo en la cola para que el mensaje se envíe en segundo plano. Necesitarás configurar tus colas antes de usar esta característica.

Cola de mensajes retrasada

Si deseas retrasar la entrega de un mensaje de correo electrónico en cola, puedes usar el método later. Como primer argumento, el método later acepta una instancia DateTime que indica cuándo se debe enviar el mensaje:

$when = now()->addMinutes(10);

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->later($when, new OrderShipped($order));

Enviar a queues específicas

Como todas las clases mailable generadas usando el comando make:mail usan el trait Illuminate\Bus\Queueable, puedes llamar a los métodos onQueue y onConnection en cualquier instancia de clase mailable, lo que te permite especificar la conexión y nombre de cola para el mensaje:

$message = (new OrderShipped($order))
                ->onConnection('sqs')
                ->onQueue('emails');

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->queue($message);

En cola por defecto

Si tienes clases mailables que deseas que siempre se pongan en cola, puedes implementar la interfaz ShouldQueue en la clase. Ahora, incluso si llamas al método send cuando envíes correos, el mailable se pondrá en cola ya que implementa la interfaz:

use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Mailable implements ShouldQueue
{
    //
}

Configuración regional de mailables

Laravel te permite enviar mailables en una configuración regional diferente del idioma actual, e incluso recordará dicha configuración si el correo es agregado a una cola.

Para lograr esto, el facade Mail ofrece un método locale para establecer el idioma deseado. La aplicación cambiará a dicha configuración regional cuando el mailable sea formateado y luego volverá a la configuración anterior cuando el formato es completado:

Mail::to($request->user())->locale('es')->send(
    new OrderShipped($order)
);

Configuración regional de usuarios

Algunas veces, las aplicaciones almacenan la configuración regional preferida de cada usuario. Al implementar la interfaz HasLocalePreference en uno o más de tus modelos, puedes instruir a Laravel a usar dicha configuración almacenada al enviar correos electrónicos:

use Illuminate\Contracts\Translation\HasLocalePreference;

class User extends Model implements HasLocalePreference
{
    /**
    * Get the user's preferred locale.
    *
    * @return string
    */
    public function preferredLocale()
    {
        return $this->locale;
    }
}

Una vez has implementado la interfaz, Laravel automáticamente usará la configuración regional preferida al enviar mailables y notificaciones al modelo. Por lo tanto, no hay necesidad de llamar al método locale al usar esta interfaz:

Mail::to($request->user())->send(new OrderShipped($order));

Correos y desarrollo local

Al desarrollar una aplicación que envía correos electrónicos, probablemente no deseas enviar correos electrónicos a direcciones reales. Laravel proporciona varias formas de «desactivar» el envío real de correos electrónicos durante el desarrollo local.

Driver Log

En lugar de enviar tus correos electrónicos, el driver de correos log escribirá todos los mensajes de correo electrónico en tus archivos de logs para su inspección. Para obtener más información sobre cómo configurar tu aplicación por entorno, revisa la configuración en la documentación.

Destinatario universal

Otra solución proporcionada por Laravel es establecer un destinatario universal de todos los correos electrónicos enviados por el framework. De esta forma, todos los correos electrónicos generados por tu aplicación serán enviados a una dirección específica, en lugar de la dirección realmente especificada al enviar el mensaje. Esto se puede hacer a través de la opción to en tu archivo de configuración config/mail.php:

'to' => [
    'address' => '[email protected]',
    'name' => 'Example'
],

Mailtrap

Finalmente, puedes usar un servicio como Mailtrap y el driver smtp para enviar tus mensajes de correo electrónico a un buzón «ficticio» donde puedes verlos en un verdadero cliente de correo electrónico. Este enfoque tiene el beneficio de permitirte inspeccionar realmente los correos electrónicos finales en el visor de mensajes de Mailtrap.

Eventos

Laravel dispara dos eventos durante el proceso de envío de mensajes de correo. El evento MessageSending se dispara antes de que se envíe un mensaje, mientras que el evento MessageSent se dispara después de que se ha enviado un mensaje. Recuerda, estos eventos se disparan cuando el correo se envía, no cuando se pone en cola. Puedes registrar un listener de eventos para este evento en tu EventServiceProvider:

/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
    'Illuminate\Mail\Events\MessageSending' => [
        'App\Listeners\LogSendingMessage',
    ],
    'Illuminate\Mail\Events\MessageSent' => [
        'App\Listeners\LogSentMessage',
    ],
];

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.

Lección anterior Helpers - Documentación de Laravel 6 Lección siguiente Notificaciones - Documentación de Laravel 6