1. Profundizando
  2. Correo

Introducción

Enviar correos electrónicos no tiene por qué ser complicado. Laravel proporciona una API de correo electrónico limpia y sencilla impulsada por el popular componente Symfony Mailer. Laravel y Symfony Mailer proporcionan controladores para enviar correos electrónicos a través de SMTP, Mailgun, Postmark, Amazon SES y sendmail, lo que te permite comenzar rápidamente a enviar correos electrónicos a través de un servicio local o basado en la nube de tu elección.

Configuración

Los servicios de correo electrónico de Laravel se pueden configurar a través del archivo de configuración config/mail.php de tu aplicación. Cada remitente configurado dentro de este archivo puede tener su propia configuración única e incluso su propio "transporte" único, lo que permite que tu aplicación utilice diferentes servicios de correo electrónico para enviar ciertos mensajes de correo electrónico. Por ejemplo, tu aplicación podría usar Postmark para enviar correos electrónicos transaccionales mientras usa Amazon SES para enviar correos electrónicos masivos.

Dentro de tu archivo de configuración mail, encontrarás una matriz de configuración mailers. Esta matriz contiene una entrada de configuración de ejemplo para cada uno de los principales controladores/transportes de correo admitidos por Laravel, mientras que el valor de configuración default determina qué remitente se utilizará de forma predeterminada cuando tu aplicación necesite enviar un mensaje de correo electrónico.

Requisitos Previos del Controlador / Transporte

Los controladores basados en API como Mailgun, Postmark y MailerSend a menudo son más simples y más rápidos que enviar correos electrónicos a través de servidores SMTP. Siempre que sea posible, recomendamos que uses uno de estos controladores.

Controlador Mailgun

Para usar el controlador Mailgun, instala el transporte de Mailgun de Symfony a través de Composer:

composer require symfony/mailgun-mailer symfony/http-client

A continuación, establece la opción default en el archivo de configuración config/mail.php de tu aplicación en mailgun. Después de configurar el remitente predeterminado de tu aplicación, verifica que tu archivo de configuración config/services.php contenga las siguientes opciones:

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

Si no estás utilizando la región de Mailgun de Estados Unidos, puedes definir el punto final de tu región en el archivo de configuración services:

'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
'endpoint' => env('MAILGUN_ENDPOINT', 'api.eu.mailgun.net'),
],

Controlador Postmark

Para usar el controlador Postmark, instala el transporte de correo Postmark de Symfony a través de Composer:

composer require symfony/postmark-mailer symfony/http-client

A continuación, establece la opción default en el archivo de configuración config/mail.php de tu aplicación en postmark. Después de configurar el remitente predeterminado de tu aplicación, verifica que tu archivo de configuración config/services.php contenga las siguientes opciones:

'postmark' => [
'token' => env('POSTMARK_TOKEN'),
],

Si deseas especificar el flujo de mensajes de Postmark que debe utilizar un remitente dado, puedes agregar la opción de configuración message_stream_id al array de configuración del remitente. Este array de configuración se puede encontrar en el archivo de configuración config/mail.php de tu aplicación:

'postmark' => [
'transport' => 'postmark',
'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
],

De esta manera, también puedes configurar varios mailers de Postmark con diferentes flujos de mensajes.

Controlador SES

Para utilizar el controlador de Amazon SES, primero debes instalar el SDK de Amazon AWS para PHP. Puedes instalar esta biblioteca a través del administrador de paquetes Composer:

composer require aws/aws-sdk-php

A continuación, establece la opción default 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' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],

Para utilizar credenciales temporales de AWS a través de un token de sesión, puedes agregar una clave token a la configuración SES de tu aplicación:

'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'token' => env('AWS_SESSION_TOKEN'),
],

Si deseas definir opciones adicionales que Laravel debe pasar al método SendEmail del AWS SDK al enviar un correo electrónico, puedes definir una matriz options dentro de tu configuración ses:

'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'options' => [
'ConfigurationSetName' => 'MyConfigurationSet',
'EmailTags' => [
['Name' => 'foo', 'Value' => 'bar'],
],
],
],

Controlador MailerSend

MailerSend, un servicio de correo electrónico y SMS transaccional, mantiene su propio controlador de correo basado en API para Laravel. El paquete que contiene el controlador se puede instalar a través del administrador de paquetes Composer:

composer require mailersend/laravel-driver

Una vez instalado el paquete, agrega la variable de entorno MAILERSEND_API_KEY al archivo .env de tu aplicación. Además, la variable de entorno MAIL_MAILER debe definirse como mailersend:

MAIL_MAILER=mailersend
MAIL_FROM_ADDRESS=[email protected]
MAIL_FROM_NAME="App Name"
 
MAILERSEND_API_KEY=your-api-key

Para obtener más información sobre MailerSend, incluido cómo usar plantillas alojadas, consulta la documentación del controlador de MailerSend.

Configuración de Respaldo

A veces, un servicio externo que has configurado para enviar el correo de tu aplicación puede estar caído. En estos casos, puede ser útil definir una o más configuraciones de entrega de correo de respaldo que se utilizarán en caso de que tu controlador de entrega principal esté caído.

Para lograr esto, debes definir un remitente dentro del archivo de configuración de correo de tu aplicación que use el transporte failover. La matriz de configuración para el remitente de failover de tu aplicación debe contener una matriz de mailers que haga referencia al orden en que se deben elegir los controladores de correo para la entrega:

'mailers' => [
'failover' => [
'transport' => 'failover',
'mailers' => [
'postmark',
'mailgun',
'sendmail',
],
],
 
// ...
],

Una vez que hayas definido tu remitente de correo de respaldo, debes establecer este remitente como el remitente predeterminado utilizado por tu aplicación especificando su nombre como el valor de la clave de configuración default dentro del archivo de configuración de correo de tu aplicación:

'default' => env('MAIL_MAILER', 'failover'),

Generación de Correos Electrónicos

Al construir aplicaciones 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á automáticamente cuando crees tu primera clase mailable utilizando el comando Artisan make:mail:

php artisan make:mail OrderShipped

Redacción de Correos Electrónicos

Una vez que hayas generado una clase mailable, ábrela para que podamos explorar su contenido. La configuración de la clase mailable se realiza en varios métodos, incluidos los métodos envelope, content y attachments.

El método envelope devuelve un objeto Illuminate\Mail\Mailables\Envelope que define el asunto y, a veces, los destinatarios del mensaje. El método content devuelve un objeto Illuminate\Mail\Mailables\Content que define la plantilla de Blade que se utilizará para generar el contenido del mensaje.

Configuración del Remitente

Uso del Sobre

Primero, exploremos la configuración del remitente del correo electrónico. O, en otras palabras, quién va a ser el remitente del correo electrónico. Hay dos formas de configurar el remitente. Primero, puedes especificar la dirección "from" en el sobre de tu mensaje:

use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Envelope;
 
/**
* Obtener el sobre del mensaje.
*/
public function envelope(): Envelope
{
return new Envelope(
from: new Address('[email protected]', 'Jeffrey Way'),
subject: 'Order Shipped',
);
}

Si lo deseas, también puedes especificar una dirección replyTo:

return new Envelope(
from: new Address('[email protected]', 'Jeffrey Way'),
replyTo: [
new Address('[email protected]', 'Taylor Otwell'),
],
subject: 'Order Shipped',
);

Uso de una Dirección Global from

Sin embargo, si tu aplicación utiliza la misma dirección "from" para todos sus correos electrónicos, puede resultar engorroso agregarla a 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 utilizará si no se especifica ninguna otra dirección "from" dentro de la clase mailable:

'from' => [
'address' => env('MAIL_FROM_ADDRESS', '[email protected]'),
'name' => env('MAIL_FROM_NAME', 'Example'),
],

Además, puedes definir una dirección global "reply_to" en tu archivo de configuración config/mail.php:

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

Configuración de la Vista

Dentro del método content de una clase mailable, puedes definir la view, o qué plantilla se debe usar al representar el contenido del correo electrónico. Dado que cada correo electrónico suele utilizar una plantilla de Blade para representar su contenido, tienes todo el poder y la comodidad del motor de plantillas Blade al construir el HTML de tu correo electrónico:

/**
* Obtener la definición de contenido del mensaje.
*/
public function content(): Content
{
return new Content(
view: 'emails.orders.shipped',
);
}

Nota Puede que desees crear un directorio resources/views/emails para almacenar todas tus plantillas de correo electrónico; sin embargo, eres libre de colocarlas donde desees dentro de tu directorio resources/views.

Correos Electrónicos en Texto Plano

Si deseas definir una versión de texto sin formato de tu correo electrónico, puedes especificar la plantilla de texto sin formato al crear la definición Content del mensaje. Al igual que el parámetro view, el parámetro text debe ser un nombre de plantilla que se utilizará para representar el contenido del correo electrónico. Eres libre de definir tanto una versión HTML como una versión de texto sin formato de tu mensaje:

/**
* Obtener la definición de contenido del mensaje.
*/
public function content(): Content
{
return new Content(
view: 'emails.orders.shipped',
text: 'emails.orders.shipped-text'
);
}

Por claridad, el parámetro html se puede utilizar como un alias del parámetro view:

return new Content(
html: 'emails.orders.shipped',
text: 'emails.orders.shipped-text'
);

Datos de la Vista

A través de Propiedades Públicas

Por lo general, querrás pasar algunos datos a tu vista que puedas utilizar al representar el HTML del correo electrónico. Hay dos formas de hacer que los datos estén disponibles en tu 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 a la clase mailable a través del constructor y establecer esos datos en propiedades públicas definidas en la clase:

<?php
 
namespace App\Mail;
 
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Queue\SerializesModels;
 
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
 
/**
* Crear una nueva instancia de mensaje.
*/
public function __construct(
public Order $order,
) {}
 
/**
* Obtener la definición de contenido del mensaje.
*/
public function content(): Content
{
return new Content(
view: 'emails.orders.shipped',
);
}
}

Una vez que los datos se hayan establecido en una propiedad pública, estarán disponibles automáticamente en tu vista, por lo que puedes acceder a ellos como lo harías con cualquier otro dato en tus plantillas Blade:

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

A través del Parámetro with:

Si deseas personalizar el formato de los datos de tu correo electrónico antes de enviarlos a la plantilla, puedes pasar manualmente tus datos a la vista a través del parámetro with de la definición Content. Por lo general, seguirás pasando 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 se pongan automáticamente a disposición de la plantilla:

<?php
 
namespace App\Mail;
 
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Queue\SerializesModels;
 
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
 
/**
* Crear una nueva instancia de mensaje.
*/
public function __construct(
protected Order $order,
) {}
 
/**
* Obtener la definición de contenido del mensaje.
*/
public function content(): Content
{
return new Content(
view: 'emails.orders.shipped',
with: [
'orderName' => $this->order->name,
'orderPrice' => $this->order->price,
],
);
}
}

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

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

Archivos Adjuntos

Para agregar archivos adjuntos a un correo electrónico, agregarás archivos adjuntos a la matriz devuelta por el método attachments del mensaje. Primero, puedes agregar un archivo adjunto proporcionando la ruta del archivo al método fromPath proporcionado por la clase Attachment:

use Illuminate\Mail\Mailables\Attachment;
 
/**
* Obtener los archivos adjuntos para el mensaje.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromPath('/path/to/file'),
];
}

Cuando adjuntas archivos a un mensaje, también puedes especificar el nombre para mostrar y / o el tipo MIME del archivo adjunto mediante los métodos as y withMime:

/**
* Obtener los archivos adjuntos para el mensaje.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromPath('/path/to/file')
->as('name.pdf')
->withMime('application/pdf'),
];
}

Adjuntar Archivos Desde Disco

Si has almacenado un archivo en uno de tus discos de sistema de archivos, puedes adjuntarlo al correo electrónico utilizando el método de archivo adjunto fromStorage:

/**
* Obtener los archivos adjuntos para el mensaje.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromStorage('/path/to/file'),
];
}

Por supuesto, también puedes especificar el nombre y el tipo MIME del archivo adjunto:

/**
* Obtener los archivos adjuntos para el mensaje.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromStorage('/path/to/file')
->as('name.pdf')
->withMime('application/pdf'),
];
}

El método fromStorageDisk se puede usar si necesitas especificar un disco de almacenamiento que no sea tu disco predeterminado:

/**
* Obtener los archivos adjuntos para el mensaje.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromStorageDisk('s3', '/path/to/file')
->as('name.pdf')
->withMime('application/pdf'),
];
}

Archivos Adjuntos de Datos en Bruto

El método de archivo adjunto fromData se puede usar para adjuntar una cadena de bytes sin formato como archivo adjunto. Por ejemplo, podrías usar este método si has generado un PDF en memoria y deseas adjuntarlo al correo electrónico sin escribirlo en disco. El método fromData acepta un cierre que resuelve los bytes de datos sin formato, así como el nombre que se asignará al archivo adjunto:

/**
* Obtener los archivos adjuntos para el mensaje.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromData(fn () => $this->pdf, 'Report.pdf')
->withMime('application/pdf'),
];
}

Archivos Adjuntos Inline

Incrustar imágenes en línea en tus correos electrónicos suele ser engorroso; sin embargo, Laravel proporciona una forma conveniente de adjuntar imágenes a tus correos electrónicos. Para incrustar una imagen en línea, utiliza el método embed en la variable $message dentro de tu plantilla de correo electrónico. Laravel hace que la variable $message esté disponible automáticamente en todas tus plantillas de correo electrónico, por lo que no es necesario preocuparse por pasarla manualmente:

<body>
Here is an image:
 
<img src="{{ $message->embed($pathToImage) }}">
</body>

Advertencia La variable $message no está disponible en las plantillas de mensajes de texto sin formato, ya que los mensajes de texto sin formato no utilizan archivos adjuntos en línea.

Incrustar Archivos Adjuntos de Datos en Bruto

Si ya tienes una cadena de datos de imagen sin formato que deseas incrustar en una plantilla de correo electrónico, puedes llamar al método embedData en la variable $message. Al llamar al método embedData, deberás proporcionar un nombre de archivo que se asignará a la imagen incrustada:

<body>
Here is an image from raw data:
 
<img src="{{ $message->embedData($data, 'example-image.jpg') }}">
</body>

Objetos Adjuntos

Si bien adjuntar archivos a mensajes mediante simples rutas de cadena a menudo es suficiente, en muchos casos, las entidades adjuntas en tu aplicación están representadas por clases. Por ejemplo, si tu aplicación está adjuntando una foto a un mensaje, tu aplicación también puede tener un modelo Photo que represente esa foto. Cuando ese es el caso, ¿no sería conveniente pasar simplemente el modelo Photo al método attach? Los objetos adjuntos te permiten hacer justamente eso.

Para empezar, implementa la interfaz Illuminate\Contracts\Mail\Attachable en el objeto que se podrá adjuntar a los mensajes. Esta interfaz dicta que tu clase debe definir un método toMailAttachment que devuelva una instancia de Illuminate\Mail\Attachment:

<?php
 
namespace App\Models;
 
use Illuminate\Contracts\Mail\Attachable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Mail\Attachment;
 
class Photo extends Model implements Attachable
{
/**
* Obtener la representación adjunta del modelo.
*/
public function toMailAttachment(): Attachment
{
return Attachment::fromPath('/path/to/file');
}
}

Una vez que hayas definido tu objeto adjunto, puedes devolver una instancia de ese objeto desde el método attachments al construir un mensaje de correo electrónico:

/**
* Obtener los archivos adjuntos para el mensaje.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [$this->photo];
}

Por supuesto, los datos del archivo adjunto pueden almacenarse en un servicio de almacenamiento de archivos remotos como Amazon S3. Por lo tanto, Laravel también te permite generar instancias de archivos adjuntos a partir de datos almacenados en uno de los discos de sistema de archivos de tu aplicación:

// Crear un archivo adjunto desde un archivo en su disco predeterminado...
return Attachment::fromStorage($this->path);
 
// Crear un archivo adjunto desde un archivo en un disco específico...
return Attachment::fromStorageDisk('backblaze', $this->path);

Además, puedes crear instancias de archivos adjuntos a partir de datos que tengas en memoria. Para hacer esto, proporciona un cierre al método fromData. El cierre debe devolver los datos sin formato que representan el archivo adjunto:

return Attachment::fromData(fn () => $this->content, 'Photo Name');

Laravel también proporciona métodos adicionales que puedes usar para personalizar tus archivos adjuntos. Por ejemplo, puedes usar los métodos as y withMime para personalizar el nombre del archivo y el tipo MIME:

return Attachment::fromPath('/path/to/file')
->as('Photo Name')
->withMime('image/jpeg');

Cabeceras

A veces es posible que necesites adjuntar encabezados adicionales al mensaje saliente. Por ejemplo, es posible que necesites establecer un Message-Id personalizado u otros encabezados de texto arbitrarios.

Para lograr esto, define un método headers en tu clase mailable. El método headers debe devolver una instancia de Illuminate\Mail\Mailables\Headers. Esta clase acepta los parámetros messageId, references y text. Por supuesto, puedes proporcionar solo los parámetros que necesites para tu mensaje en particular:

use Illuminate\Mail\Mailables\Headers;
 
/**
* Obtener las cabeceras del mensaje.
*/
public function headers(): Headers
{
return new Headers(
messageId: '[email protected]',
references: ['[email protected]'],
text: [
'X-Custom-Header' => 'Custom Value',
],
);
}

Etiquetas y Metadatos

Algunos proveedores de correo electrónico de terceros, como Mailgun y Postmark, admiten "etiquetas" y "metadatos" de mensajes, que se pueden usar para agrupar y rastrear correos electrónicos enviados por tu aplicación. Puedes agregar etiquetas y metadatos a un mensaje de correo electrónico a través de tu definición de Envelope:

use Illuminate\Mail\Mailables\Envelope;
 
/**
* Obtener el sobre del mensaje.
*
* @return \Illuminate\Mail\Mailables\Envelope
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Order Shipped',
tags: ['shipment'],
metadata: [
'order_id' => $this->order->id,
],
);
}

Si tu aplicación está utilizando el controlador Mailgun, puedes consultar la documentación de Mailgun para obtener más información sobre etiquetas y metadatos. Del mismo modo, la documentación de Postmark también se puede consultar para obtener más información sobre su soporte para etiquetas y metadatos.

Si tu aplicación está utilizando Amazon SES para enviar correos electrónicos, debes usar el método metadata para adjuntar etiquetas SES al mensaje.

Personalización del Mensaje Symfony

Las capacidades de correo de Laravel están alimentadas por Symfony Mailer. Laravel te permite registrar devoluciones de llamada personalizadas que se invocarán con la instancia de Symfony Message antes de enviar el mensaje. Esto te brinda la oportunidad de personalizar profundamente el mensaje antes de enviarlo. Para lograr esto, define un parámetro using en tu definición de Envelope:

use Illuminate\Mail\Mailables\Envelope;
use Symfony\Component\Mime\Email;
 
/**
* Obtener el sobre del mensaje.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Order Shipped',
using: [
function (Email $message) {
// ...
},
]
);
}

Correo Electrónico con Markdown

Los mensajes de correo electrónico basados en Markdown te permiten aprovechar las plantillas y componentes preconstruidos de notificaciones de correo en tus mailables. Dado que los mensajes están escritos en Markdown, Laravel puede representar plantillas HTML hermosas y receptivas para los mensajes mientras genera automáticamente un equivalente en texto sin formato.

Generación de Correos Electrónicos con Markdown

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

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

Luego, al configurar la definición de Content del mailable dentro de su método content, utiliza el parámetro markdown en lugar del parámetro view:

use Illuminate\Mail\Mailables\Content;
 
/**
* Obtener la definición de contenido del mensaje.
*/
public function content(): Content
{
return new Content(
markdown: 'emails.orders.shipped',
with: [
'url' => $this->orderUrl,
],
);
}

Redacción de Mensajes con Markdown

Los mailables de Markdown utilizan una combinación de componentes de Blade y sintaxis de Markdown que te permiten construir fácilmente mensajes de correo mientras aprovechas los componentes de IU de correo electrónico preconstruidos de Laravel:

<x-mail::message>
# Order Shipped
 
Your order has been shipped!
 
<x-mail::button :url="$url">
View Order
</x-mail::button>
 
Thanks,<br>
{{ config('app.name') }}
</x-mail::message>

Nota No utilices una indentación excesiva al redactar correos electrónicos en Markdown. Según las normas de Markdown, los analizadores de Markdown renderizarán el contenido con sangría como bloques de código.

Componente de Botón

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 admitidos son primary, success y error. Puedes agregar tantos componentes de botón a un mensaje como desees:

<x-mail::button :url="$url" color="success">
View Order
</x-mail::button>

Componente de Panel

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

<x-mail::panel>
This is the panel content.
</x-mail::panel>

Componente de Tabla

El componente de tabla te permite transformar una tabla de Markdown en una tabla de HTML. El componente acepta la tabla de Markdown como su contenido. La alineación de las columnas de la tabla se admite utilizando la sintaxis de alineación de tabla de Markdown por defecto:

<x-mail::table>
| Laravel | Table | Example |
| ------------- |:-------------:| --------:|
| Col 2 is | Centered | $10 |
| Col 3 is | Right-Aligned | $20 |
</x-mail::table>

Personalización de los Componentes

Puedes exportar todos los componentes de correo electrónico de Markdown a tu aplicación para personalizarlos. Para exportar los componentes, utiliza el comando Artisan vendor:publish para publicar la etiqueta de activo laravel-mail:

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

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

Personalización del 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 convertirán automáticamente en estilos CSS en línea dentro de las representaciones HTML de tus mensajes de correo electrónico de Markdown.

Si deseas construir un tema completamente nuevo para los componentes de Markdown de Laravel, puedes colocar un archivo CSS dentro del directorio html/themes. Después de nombrar y guardar tu archivo CSS, actualiza la opción theme en el archivo de configuración config/mail.php de tu aplicación para que coincida con el nombre de tu nuevo tema.

Para personalizar el tema para un mailable individual, puedes establecer la propiedad $theme de la clase del mailable con el nombre del tema que se debe usar al enviar ese mailable.

Envío de Correos Electrónicos

Para enviar un mensaje, utiliza el método to en la fachada 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 de correo electrónico utilizará automáticamente sus propiedades email y name al determinar los destinatarios del correo electrónico, así que asegúrate de que estas propiedades 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\Models\Order;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
 
class OrderShipmentController extends Controller
{
/**
* Enviar el pedido dado.
*/
public function store(Request $request): RedirectResponse
{
$order = Order::findOrFail($request->order_id);
 
// Enviar el pedido...
 
Mail::to($request->user())->send(new OrderShipped($order));
 
return redirect('/orders');
}
}

No estás limitado a especificar solo los destinatarios "to" al enviar un mensaje. Eres libre de establecer destinatarios "to", "cc" y "bcc" encadenando sus respectivos métodos:

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

Recorrido de Destinatarios

Ocasionalmente, es posible que necesites enviar un mailable a una lista de destinatarios iterando sobre un array de destinatarios/direcciones de correo electrónico. Sin embargo, dado que el método to agrega direcciones de correo electrónico a la lista de destinatarios del mailable, cada iteración a través del bucle enviará otro correo electrónico a cada destinatario anterior. Por lo tanto, siempre debes volver a crear la instancia del mailable para cada destinatario:

foreach (['[email protected]', '[email protected]'] as $recipient) {
Mail::to($recipient)->send(new OrderShipped($order));
}

Envío de Correos Electrónicos a través de un Mailer Específico

Por defecto, Laravel enviará correos electrónicos utilizando el remitente configurado como el remitente default en el archivo de configuración config/mail.php de tu aplicación. Sin embargo, puedes usar el método mailer para enviar un mensaje utilizando una configuración de remitente específica:

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

Encolado de Correos Electrónicos

Encolado de un Mensaje de Correo Electrónico

Dado que el envío de mensajes de correo electrónico puede afectar negativamente el tiempo de respuesta de tu aplicación, muchos desarrolladores eligen encolar mensajes de correo electrónico para enviarlos en segundo plano. Laravel facilita esto mediante su API de cola unificada integrada. Para encolar un mensaje de correo, utiliza el método queue en la fachada 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 poner un trabajo en la cola para que el mensaje se envíe en segundo plano. Necesitarás configurar tus colas antes de usar esta función.

Encolado de Mensajes con Retraso

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 de DateTime que indica cuándo se debe enviar el mensaje:

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

Envío a Colas Específicas

Dado que todas las clases mailable generadas con el comando make:mail utilizan el rasgo 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 el nombre de la cola para el mensaje:

$message = (new OrderShipped($order))
->onConnection('sqs')
->onQueue('emails');
 
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->queue($message);

Encolado por Defecto

Si tienes clases mailables que siempre deseas que estén en cola, puedes implementar el contrato ShouldQueue en la clase. Ahora, incluso si llamas al método send al enviar el correo, el mailable seguirá en cola ya que implementa el contrato:

use Illuminate\Contracts\Queue\ShouldQueue;
 
class OrderShipped extends Mailable implements ShouldQueue
{
// ...
}

Correos Electrónicos en Cola y Transacciones de Base de Datos

Cuando los mailables en cola se despachan dentro de transacciones de base de datos, pueden procesarse en la cola antes de que la transacción de base de datos se haya confirmado. Cuando esto sucede, cualquier actualización que hayas realizado a modelos o registros de bases de datos durante la transacción de base de datos puede no reflejarse aún en la base de datos. Además, cualquier modelo o registro de base de datos creado dentro de la transacción puede no existir en la base de datos. Si tu mailable depende de estos modelos, pueden producirse errores inesperados cuando se procesa el trabajo que envía el mailable en cola.

Si la opción de configuración after_commit de tu conexión de cola está configurada como false, aún puedes indicar que un determinado mailable en cola debe despacharse después de que se hayan confirmado todas las transacciones de base de datos abiertas llamando al método afterCommit al enviar el mensaje de correo:

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

Alternativamente, puedes llamar al método afterCommit desde el constructor de tu mailable:

<?php
 
namespace App\Mail;
 
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
 
class OrderShipped extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
 
/**
* Crear una nueva instancia de mensaje.
*/
public function __construct()
{
$this->afterCommit();
}
}

Nota Para obtener más información sobre cómo solucionar estos problemas, revisa la documentación sobre trabajos en cola y transacciones de base de datos.

Renderización de Correos Electrónicos

En ocasiones, es posible que desees capturar el contenido HTML de un mailable sin enviarlo. Para lograr esto, puedes llamar al método render del mailable. Este método devolverá el contenido HTML evaluado del mailable como una cadena:

use App\Mail\InvoicePaid;
use App\Models\Invoice;
 
$invoice = Invoice::find(1);
 
return (new InvoicePaid($invoice))->render();

Vista Preliminar de Correos Electrónicos en el Navegador

Al diseñar la plantilla de un mailable, es conveniente previsualizar rápidamente el mailable renderizado en tu navegador como una plantilla Blade típica. Por esta razón, Laravel te permite devolver cualquier mailable directamente desde un cierre de ruta o controlador. Cuando se devuelve un mailable, se renderizará y mostrará en el navegador, lo que te permite previsualizar rápidamente su diseño sin necesidad de enviarlo a una dirección de correo electrónico real:

Route::get('/mailable', function () {
$invoice = App\Models\Invoice::find(1);
 
return new App\Mail\InvoicePaid($invoice);
});

Localización de Correos Electrónicos

Laravel te permite enviar mailables en un idioma diferente al idioma actual de la solicitud, e incluso recordará este idioma si el correo está en cola.

Para lograr esto, la fachada Mail ofrece un método locale para establecer el idioma deseado. La aplicación cambiará a este idioma cuando se esté evaluando la plantilla del mailable y luego volverá al idioma anterior cuando la evaluación esté completa:

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

Configuración Regional Preferida del Usuario

En ocasiones, las aplicaciones almacenan el idioma preferido de cada usuario. Al implementar el contrato HasLocalePreference en uno o más de tus modelos, puedes indicar a Laravel que use este idioma almacenado al enviar correos electrónicos:

use Illuminate\Contracts\Translation\HasLocalePreference;
 
class User extends Model implements HasLocalePreference
{
/**
* Obtener la configuración regional preferida del usuario.
*/
public function preferredLocale(): string
{
return $this->locale;
}
}

Una vez que hayas implementado la interfaz, Laravel utilizará automáticamente el idioma preferido al enviar mailables y notificaciones al modelo. Por lo tanto, no es necesario llamar al método locale al usar esta interfaz:

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

Pruebas

Pruebas del Contenido del Correo Electrónico

Laravel proporciona una variedad de métodos para inspeccionar la estructura de tu mailable. Además, Laravel ofrece varios métodos convenientes para probar que tu mailable contiene el contenido que esperas. Estos métodos son: assertSeeInHtml, assertDontSeeInHtml, assertSeeInOrderInHtml, assertSeeInText, assertDontSeeInText, assertSeeInOrderInText, assertHasAttachment, assertHasAttachedData, assertHasAttachmentFromStorage, y assertHasAttachmentFromStorageDisk.

Como podrías esperar, las afirmaciones "HTML" aseguran que la versión HTML de tu mailable contenga una cadena dada, mientras que las afirmaciones "text" aseguran que la versión de texto sin formato de tu mailable contenga una cadena dada:

use App\Mail\InvoicePaid;
use App\Models\User;
 
public function test_mailable_content(): void
{
$user = User::factory()->create();
 
$mailable = new InvoicePaid($user);
 
$mailable->assertFrom('[email protected]');
$mailable->assertTo('[email protected]');
$mailable->assertHasCc('[email protected]');
$mailable->assertHasBcc('[email protected]');
$mailable->assertHasReplyTo('[email protected]');
$mailable->assertHasSubject('Invoice Paid');
$mailable->assertHasTag('example-tag');
$mailable->assertHasMetadata('key', 'value');
 
$mailable->assertSeeInHtml($user->email);
$mailable->assertSeeInHtml('Invoice Paid');
$mailable->assertSeeInOrderInHtml(['Invoice Paid', 'Thanks']);
 
$mailable->assertSeeInText($user->email);
$mailable->assertSeeInOrderInText(['Invoice Paid', 'Thanks']);
 
$mailable->assertHasAttachment('/path/to/file');
$mailable->assertHasAttachment(Attachment::fromPath('/path/to/file'));
$mailable->assertHasAttachedData($pdfData, 'name.pdf', ['mime' => 'application/pdf']);
$mailable->assertHasAttachmentFromStorage('/path/to/file', 'name.pdf', ['mime' => 'application/pdf']);
$mailable->assertHasAttachmentFromStorageDisk('s3', '/path/to/file', 'name.pdf', ['mime' => 'application/pdf']);
}

Pruebas del Envío de Correos Electrónicos

Sugerimos probar el contenido de tus mensajes de correo electrónico por separado de las pruebas que afirman que un determinado mensaje de correo electrónico fue "enviado" a un usuario específico. Por lo general, el contenido de los mensajes de correo electrónico no es relevante para el código que estás probando, y es suficiente con afirmar simplemente que Laravel recibió instrucciones para enviar un mensaje de correo electrónico específico.

Puedes usar el método fake de la fachada Mail para evitar que se envíen correos electrónicos. Después de llamar al método fake de la fachada Mail, puedes afirmar que se instruyó enviar mensajes de correo electrónico a usuarios e incluso inspeccionar los datos que recibieron los mensajes de correo electrónico:

<?php
 
namespace Tests\Feature;
 
use App\Mail\OrderShipped;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;
 
class ExampleTest extends TestCase
{
public function test_orders_can_be_shipped(): void
{
Mail::fake();
 
// Realizar el envío del pedido...
 
// Asegurarse de que no se envíen correos electrónicos...
Mail::assertNothingSent();
 
// Asegurarse de que se haya enviado un correo electrónico...
Mail::assertSent(OrderShipped::class);
 
// Asegurarse de que se haya enviado un correo electrónico dos veces...
Mail::assertSent(OrderShipped::class, 2);
 
// Asegurarse de que no se haya enviado un correo electrónico...
Mail::assertNotSent(AnotherMailable::class);
 
// Asegurarse de que se hayan enviado un total de 3 correos electrónicos...
Mail::assertSentCount(3);
}
}

Si estás encolando mensajes de correo electrónico para su entrega en segundo plano, debes usar el método assertQueued en lugar de assertSent:

Mail::assertQueued(OrderShipped::class);
Mail::assertNotQueued(OrderShipped::class);
Mail::assertNothingQueued();
Mail::assertQueuedCount(3);

Puedes pasar un cierre a los métodos assertSent, assertNotSent, assertQueued o assertNotQueued para afirmar que se envió un mensaje de correo electrónico que cumple con una "prueba de verdad" dada. Si se envió al menos un mensaje de correo electrónico que pasa la prueba de verdad dada, la afirmación será exitosa:

Mail::assertSent(function (OrderShipped $mail) use ($order) {
return $mail->order->id === $order->id;
});

Al llamar a los métodos de afirmación de la fachada Mail, la instancia de mensaje aceptada por el cierre proporcionado expone métodos útiles para examinar el mensaje:

Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($user) {
return $mail->hasTo($user->email) &&
$mail->hasCc('...') &&
$mail->hasBcc('...') &&
$mail->hasReplyTo('...') &&
$mail->hasFrom('...') &&
$mail->hasSubject('...');
});

La instancia de mensaje también incluye varios métodos útiles para examinar los archivos adjuntos en un mensaje:

use Illuminate\Mail\Mailables\Attachment;
 
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) {
return $mail->hasAttachment(
Attachment::fromPath('/path/to/file')
->as('name.pdf')
->withMime('application/pdf')
);
});
 
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) {
return $mail->hasAttachment(
Attachment::fromStorageDisk('s3', '/path/to/file')
);
});
 
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($pdfData) {
return $mail->hasAttachment(
Attachment::fromData(fn () => $pdfData, 'name.pdf')
);
});

Puede que hayas notado que hay dos métodos para afirmar que no se envió correo: assertNotSent y assertNotQueued. A veces, puedes desear afirmar que no se envió correo o que no se encoló. Para lograr esto, puedes usar los métodos assertNothingOutgoing y assertNotOutgoing:

Mail::assertNothingOutgoing();
 
Mail::assertNotOutgoing(function (OrderShipped $mail) use ($order) {
return $mail->order->id === $order->id;
});

Correo Electrónico y Desarrollo Local

Cuando desarrollas una aplicación que envía correos electrónicos, probablemente no quieras enviar correos electrónicos a direcciones de correo electrónico reales. Laravel proporciona varias formas de "desactivar" el envío real de correos electrónicos durante el desarrollo local.

Controlador de Registro

Como alternativa, puedes utilizar un servicio como HELO o Mailtrap y el controlador smtp para enviar tus mensajes de correo electrónico a un buzón "falso" donde puedas verlos en un cliente de correo electrónico real. Este enfoque tiene la ventaja de permitirte inspeccionar realmente los correos electrónicos finales en el visor de mensajes de Mailtrap.

HELO / Mailtrap / Mailpit

Si estás utilizando Laravel Sail, puedes previsualizar tus mensajes usando Mailpit. Cuando Sail esté en ejecución, puedes acceder a la interfaz de Mailpit en: http://localhost:8025.

Si estás utilizando Laravel Sail, puedes previsualizar tus mensajes usando Mailpit. Cuando Sail esté en ejecución, puedes acceder a la interfaz de Mailpit en: http://localhost:8025.

Uso de una Dirección Global to

Finalmente, puedes especificar una dirección global "to" invocando el método alwaysTo ofrecido por la fachada Mail. Por lo general, este método se debe llamar desde el método boot de uno de los proveedores de servicios de tu aplicación:

use Illuminate\Support\Facades\Mail;
 
/**
* Inicializar cualquier servicio de la aplicación.
*/
public function boot(): void
{
if ($this->app->environment('local')) {
Mail::alwaysTo('[email protected]');
}
}

Eventos

Laravel dispara dos eventos durante el proceso de envío de mensajes de correo. El evento MessageSending se dispara antes de enviar un mensaje, mientras que el evento MessageSent se dispara después de que se ha enviado un mensaje. Recuerda, estos eventos se disparan cuando se está enviando el correo, no cuando se encola. Puedes registrar escuchadores de eventos para este evento en el proveedor de servicios App\Providers\EventServiceProvider de tu aplicación:

use App\Listeners\LogSendingMessage;
use App\Listeners\LogSentMessage;
use Illuminate\Mail\Events\MessageSending;
use Illuminate\Mail\Events\MessageSent;
 
/**
* Las asignaciones de escuchadores de eventos para la aplicación.
*
* @var array
*/
protected $listen = [
MessageSending::class => [
LogSendingMessage::class,
],
 
MessageSent::class => [
LogSentMessage::class,
],
];

Transportes Personalizados

Laravel incluye una variedad de transportes de correo; sin embargo, es posible que desees escribir tus propios transportes para entregar correos electrónicos a través de otros servicios que Laravel no admite de serie. Para empezar, define una clase que extienda la clase Symfony\Component\Mailer\Transport\AbstractTransport. Luego, implementa los métodos doSend y __toString() en tu transporte:

use MailchimpTransactional\ApiClient;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Transport\AbstractTransport;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\MessageConverter;
 
class MailchimpTransport extends AbstractTransport
{
/**
* Crear una nueva instancia de transporte Mailchimp.
*/
public function __construct(
protected ApiClient $client,
) {
parent::__construct();
}
 
/**
* {@inheritDoc}
*/
protected function doSend(SentMessage $message): void
{
$email = MessageConverter::toEmail($message->getOriginalMessage());
 
$this->client->messages->send(['message' => [
'from_email' => $email->getFrom(),
'to' => collect($email->getTo())->map(function (Address $email) {
return ['email' => $email->getAddress(), 'type' => 'to'];
})->all(),
'subject' => $email->getSubject(),
'text' => $email->getTextBody(),
]]);
}
 
/**
* Obtener la representación de cadena del transporte.
*/
public function __toString(): string
{
return 'mailchimp';
}
}

Una vez que hayas definido tu transporte personalizado, puedes registrarlo a través del método extend proporcionado por la fachada Mail. Por lo general, esto se debe hacer dentro del método boot del proveedor de servicios AppServiceProvider de tu aplicación. Se pasará un argumento $config al cierre proporcionado al método extend. Este argumento contendrá la matriz de configuración definida para el remitente de correo en el archivo de configuración config/mail.php de la aplicación:

use App\Mail\MailchimpTransport;
use Illuminate\Support\Facades\Mail;
 
/**
* Inicializar cualquier servicio de la aplicación.
*/
public function boot(): void
{
Mail::extend('mailchimp', function (array $config = []) {
return new MailchimpTransport(/* ... */);
});
}

Una vez que tu transporte personalizado haya sido definido y registrado, puedes crear una definición de remitente de correo en el archivo de configuración config/mail.php de tu aplicación que utilice el nuevo transporte:

'mailchimp' => [
'transport' => 'mailchimp',
// ...
],

Transportes Adicionales de Symfony

Laravel incluye soporte para algunos transportes de correo mantenidos por Symfony, como Mailgun y Postmark. Sin embargo, es posible que desees ampliar Laravel con soporte para transportes mantenidos por Symfony adicionales. Puedes hacerlo requiriendo el transportador de correo de Symfony necesario a través de Composer y registrando el transporte en Laravel. Por ejemplo, puedes instalar y registrar el transportador de "Brevo" (anteriormente "Sendinblue") de Symfony:

composer require symfony/brevo-mailer symfony/http-client

Una vez que se haya instalado el paquete del transportador de Brevo, puedes agregar una entrada para las credenciales de la API de Brevo en el archivo de configuración services de tu aplicación:

'brevo' => [
'key' => 'your-api-key',
],

A continuación, puedes usar el método extend de la fachada Mail para registrar el transporte en Laravel. Por lo general, esto se debe hacer dentro del método boot de un proveedor de servicios:

use Illuminate\Support\Facades\Mail;
use Symfony\Component\Mailer\Bridge\Brevo\Transport\BrevoTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
 
/**
* Inicializar cualquier servicio de la aplicación.
*/
public function boot(): void
{
Mail::extend('brevo', function () {
return (new BrevoTransportFactory)->create(
new Dsn(
'brevo+api',
'default',
config('services.brevo.key')
)
);
});
}

Una vez que se haya registrado tu transporte, puedes crear una definición de remitente de correo en el archivo de configuración config/mail.php de tu aplicación que utilice el nuevo transporte:

'brevo' => [
'transport' => 'brevo',
// ...
],