Estamos actualizando el sitio. Durante unos días es posible que veas fallos de diseño o de traducción. La documentación sigue disponible: si una página se ve mal, recárgala más tarde.

Correo

10.x 7 de mar. de 2026

#Introducción

Enviar correo electrónico no tiene que ser complicado. Laravel ofrece una API de correo limpia y sencilla impulsada por el popular componente Symfony Mailer. Laravel y Symfony Mailer proporcionan drivers para enviar correo vía SMTP, Mailgun, Postmark, Amazon SES y sendmail, permitiéndole comenzar rápidamente a enviar correos a través de un servicio local o en la nube de su elección.

#Configuración

Los servicios de correo de Laravel pueden configurarse mediante el archivo de configuración config/mail.php de su aplicación. Cada mailer configurado en este archivo puede tener su propia configuración única e incluso su propio "transport", permitiendo que su aplicación use diferentes servicios de correo para enviar ciertos mensajes. Por ejemplo, su aplicación podría usar Postmark para enviar correos transaccionales mientras usa Amazon SES para enviar correos masivos.

Dentro de su archivo de configuración mail, encontrará un arreglo de configuración mailers. Este arreglo contiene una entrada de configuración de ejemplo para cada uno de los principales drivers / transportes de correo soportados por Laravel, mientras que el valor de configuración default determina qué mailer se usará por defecto cuando su aplicación necesite enviar un mensaje de correo.

#Requisitos del Driver / Transporte

Los drivers basados en API como Mailgun, Postmark y MailerSend suelen ser más simples y rápidos que enviar correo vía servidores SMTP. Siempre que sea posible, recomendamos usar uno de estos drivers.

#Driver Mailgun

Para usar el driver Mailgun, instale el transporte Mailgun Mailer de Symfony vía Composer:

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

Luego, configure la opción default en el archivo config/mail.php de su aplicación a mailgun. Después de configurar el mailer por defecto de su aplicación, verifique que el archivo config/services.php contenga las siguientes opciones:

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

Si no está usando la región Mailgun de Estados Unidos, puede definir el endpoint de su 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'),
],

#Driver Postmark

Para usar el driver Postmark, instale el transporte Postmark Mailer de Symfony vía Composer:

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

Luego, configure la opción default en el archivo config/mail.php de su aplicación a postmark. Después de configurar el mailer por defecto de su aplicación, verifique que el archivo config/services.php contenga las siguientes opciones:

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

Si desea especificar el stream de mensajes Postmark que debe usar un mailer dado, puede agregar la opción de configuración message_stream_id al arreglo de configuración del mailer. Este arreglo de configuración se encuentra en el archivo config/mail.php de su aplicación:

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

De esta forma, también puede configurar múltiples mailers Postmark con diferentes streams de mensajes.

#Driver SES

Para usar el driver Amazon SES debe primero instalar el SDK de Amazon AWS para PHP. Puede instalar esta librería mediante el gestor de paquetes Composer:

composer require aws/aws-sdk-php

Luego, configure la opción default en su archivo config/mail.php a ses y verifique que el archivo 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 las credenciales temporales de AWS mediante un token de sesión, puede agregar una clave token a la configuración SES de su 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 desea definir opciones adicionales que Laravel debe pasar al método SendEmail del SDK de AWS al enviar un correo, puede definir un arreglo options dentro de su 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'],
        ],
    ],
],

#Driver MailerSend

MailerSend, un servicio de correo transaccional y SMS, mantiene su propio driver de correo basado en API para Laravel. El paquete que contiene el driver puede instalarse mediante el gestor de paquetes Composer:

composer require mailersend/laravel-driver

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

MAIL_MAILER=mailersend
MAIL_FROM_ADDRESS=app@yourdomain.com
MAIL_FROM_NAME="App Name"

MAILERSEND_API_KEY=your-api-key

Para aprender más sobre MailerSend, incluyendo cómo usar plantillas alojadas, consulte la documentación del driver MailerSend.

#Configuración de Failover

A veces, un servicio externo que ha configurado para enviar el correo de su aplicación puede estar caído. En estos casos, puede ser útil definir una o más configuraciones de respaldo para la entrega de correo que se usarán si el driver principal está inactivo.

Para lograr esto, debe definir un mailer dentro del archivo de configuración mail de su aplicación que use el transporte failover. El arreglo de configuración para el mailer failover de su aplicación debe contener un arreglo de mailers que referencien el orden en que los mailers configurados deben ser elegidos para la entrega:

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

    // ...
],

Una vez definido su mailer failover, debe establecer este mailer como el mailer por defecto usado por su aplicación especificando su nombre como valor de la clave de configuración default dentro del archivo de configuración mail de su aplicación:

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

#Configuración Round Robin

El transporte roundrobin le permite distribuir la carga de envío de correos entre múltiples mailers. Para comenzar, defina un mailer dentro del archivo de configuración mail de su aplicación que use el transporte roundrobin. El arreglo de configuración para el mailer roundrobin de su aplicación debe contener un arreglo de mailers que referencien qué mailers configurados deben usarse para la entrega:

'mailers' => [
    'roundrobin' => [
        'transport' => 'roundrobin',
        'mailers' => [
            'ses',
            'postmark',
        ],
    ],

    // ...
],

Una vez definido su mailer round robin, debe establecer este mailer como el mailer por defecto usado por su aplicación especificando su nombre como valor de la clave de configuración default dentro del archivo de configuración mail de su aplicación:

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

El transporte round robin selecciona un mailer aleatorio de la lista de mailers configurados y luego cambia al siguiente mailer disponible para cada correo subsecuente. En contraste con el transporte failover, que ayuda a lograr alta disponibilidad, el transporte roundrobin proporciona balanceo de carga.

#Generación de Mailables

Al construir aplicaciones Laravel, cada tipo de correo enviado por su aplicación se representa como una clase "mailable". Estas clases se almacenan en el directorio app/Mail. No se preocupe si no ve este directorio en su aplicación, ya que se generará automáticamente cuando cree su primera clase mailable usando el comando Artisan make:mail:

php artisan make:mail OrderShipped

#Escritura de Mailables

Una vez que haya generado una clase mailable, ábrala para explorar su contenido. La configuración de la clase mailable se realiza en varios métodos, incluyendo 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 Blade que se usará para generar el contenido del mensaje.

#Configuración del Remitente

#Usando el Envelope

Primero, exploremos cómo configurar el remitente del correo. O, en otras palabras, quién será el "from" del correo. Hay dos formas de configurar el remitente. Primero, puede especificar la dirección "from" en el envelope del mensaje:

use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Envelope;

/**
 * Obtener el envelope del mensaje.
 */
public function envelope(): Envelope
{
    return new Envelope(
        from: new Address('jeffrey@example.com', 'Jeffrey Way'),
        subject: 'Order Shipped',
    );
}

Si lo desea, también puede especificar una dirección replyTo:

return new Envelope(
    from: new Address('jeffrey@example.com', 'Jeffrey Way'),
    replyTo: [
        new Address('taylor@example.com', 'Taylor Otwell'),
    ],
    subject: 'Order Shipped',
);

#Usando una dirección global from

Sin embargo, si su aplicación usa la misma dirección "from" para todos sus correos, puede volverse tedioso agregarla a cada clase mailable que genere. En su lugar, puede especificar una dirección global "from" en el archivo de configuración config/mail.php. Esta dirección se usará si no se especifica otra dirección "from" dentro de la clase mailable:

'from' => [
    'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
    'name' => env('MAIL_FROM_NAME', 'Example'),
],

Además, puede definir una dirección global "reply_to" dentro de su archivo config/mail.php:

'reply_to' => ['address' => 'example@example.com', 'name' => 'App Name'],

#Configuración de la Vista

Dentro del método content de una clase mailable, puede definir la view, o qué plantilla debe usarse al renderizar el contenido del correo. Dado que cada correo típicamente usa una plantilla Blade para renderizar su contenido, tiene todo el poder y conveniencia del motor de plantillas Blade al construir el HTML de su correo:

/**
 * Obtener la definición del contenido del mensaje.
 */
public function content(): Content
{
    return new Content(
        view: 'mail.orders.shipped',
    );
}
Примечание

Puede que desee crear un directorio resources/views/emails para alojar todas sus plantillas de correo; sin embargo, es libre de ubicarlas donde prefiera dentro del directorio resources/views.

#Correos en Texto Plano

Si desea definir una versión en texto plano de su correo, puede especificar la plantilla de texto plano 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 usará para renderizar el contenido del correo. Puede definir tanto una versión HTML como una versión en texto plano de su mensaje:

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

Para mayor claridad, el parámetro html puede usarse como un alias del parámetro view:

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

#Datos para la Vista

#A través de Propiedades Públicas

Normalmente, querrá pasar algunos datos a su vista que pueda utilizar al renderizar el HTML del correo. Hay dos formas de hacer que los datos estén disponibles para su vista. Primero, cualquier propiedad pública definida en su clase mailable estará automáticamente disponible para la vista. Por ejemplo, puede pasar datos al constructor de su clase mailable y asignar esos datos a 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 del mensaje.
     */
    public function __construct(
        public Order $order,
    ) {}

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

Una vez que los datos se han asignado a una propiedad pública, estarán automáticamente disponibles en su vista, por lo que puede acceder a ellos como accedería a cualquier otro dato en sus plantillas Blade:

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

#A través del parámetro with:

Si desea personalizar el formato de los datos de su correo antes de enviarlos a la plantilla, puede pasar manualmente sus datos a la vista mediante el parámetro with de la definición Content. Normalmente, seguirá pasando datos a través del constructor de la clase mailable; sin embargo, debe asignar estos datos a propiedades protected o private para que no estén automáticamente disponibles en 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 del mensaje.
     */
    public function __construct(
        protected Order $order,
    ) {}

    /**
     * Obtener la definición del contenido del mensaje.
     */
    public function content(): Content
    {
        return new Content(
            view: 'mail.orders.shipped',
            with: [
                'orderName' => $this->order->name,
                'orderPrice' => $this->order->price,
            ],
        );
    }
}

Una vez que los datos se han pasado al método with, estarán automáticamente disponibles en su vista, por lo que puede acceder a ellos como accedería a cualquier otro dato en sus plantillas Blade:

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

#Adjuntos

Para agregar adjuntos a un correo, debe añadirlos al arreglo que retorna el método attachments del mensaje. Primero, puede agregar un adjunto proporcionando una ruta de archivo al método fromPath proporcionado por la clase Attachment:

use Illuminate\Mail\Mailables\Attachment;

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

Al adjuntar archivos a un mensaje, también puede especificar el nombre para mostrar y/o el tipo MIME del adjunto usando los métodos as y withMime:

/**
 * Obtener los 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 ha almacenado un archivo en uno de sus discos del sistema de archivos, puede adjuntarlo al correo usando el método de adjunto fromStorage:

/**
 * Obtener los 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 puede especificar el nombre y tipo MIME del adjunto:

/**
 * Obtener los 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 puede usarse si necesita especificar un disco de almacenamiento distinto al disco por defecto:

/**
 * Obtener los 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'),
    ];
}

#Adjuntos con Datos en Crudo

El método de adjunto fromData puede usarse para adjuntar una cadena de bytes en crudo como adjunto. Por ejemplo, podría usar este método si ha generado un PDF en memoria y desea adjuntarlo al correo sin escribirlo en disco. El método fromData acepta un closure que resuelve los bytes de datos en crudo así como el nombre que debe asignarse al adjunto:

/**
 * Obtener los 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'),
    ];
}

#Adjuntos Inline

Incrustar imágenes inline en sus correos suele ser complicado; sin embargo, Laravel ofrece una forma conveniente de adjuntar imágenes a sus correos. Para incrustar una imagen inline, use el método embed en la variable $message dentro de su plantilla de correo. Laravel hace que la variable $message esté disponible automáticamente en todas sus plantillas de correo, por lo que no necesita preocuparse por pasarla manualmente:

<body>
    Here is an image:

    <img src="{{ $message->embed($pathToImage) }}">
</body>
Внимание

La variable $message no está disponible en plantillas de mensajes en texto plano, ya que estos mensajes no utilizan adjuntos inline.

#Incrustar Adjuntos con Datos en Crudo

Si ya tiene una cadena de datos de imagen en crudo que desea incrustar en una plantilla de correo, puede llamar al método embedData en la variable $message. Al llamar a embedData, debe 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 Adjuntables

Aunque adjuntar archivos a mensajes mediante rutas de cadena simples suele ser suficiente, en muchos casos las entidades adjuntables dentro de su aplicación están representadas por clases. Por ejemplo, si su aplicación adjunta una foto a un mensaje, puede que también tenga un modelo Photo que representa esa foto. En ese caso, ¿no sería conveniente simplemente pasar el modelo Photo al método attach? Los objetos adjuntables le permiten hacer precisamente eso.

Para comenzar, implemente la interfaz Illuminate\Contracts\Mail\Attachable en el objeto que será adjuntable a los mensajes. Esta interfaz exige que su clase defina un método toMailAttachment que retorne 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 adjuntable del modelo.
     */
    public function toMailAttachment(): Attachment
    {
        return Attachment::fromPath('/path/to/file');
    }
}

Una vez que haya definido su objeto adjuntable, puede retornar una instancia de ese objeto desde el método attachments al construir un mensaje de correo:

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

Por supuesto, los datos de los adjuntos pueden almacenarse en un servicio remoto de almacenamiento de archivos como Amazon S3. Por eso, Laravel también le permite generar instancias de adjuntos a partir de datos almacenados en uno de los discos del sistema de archivos de su aplicación:

// Crear un adjunto desde un archivo en su disco por defecto...
return Attachment::fromStorage($this->path);

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

Además, puede crear instancias de adjuntos a partir de datos que tenga en memoria. Para lograr esto, proporcione un closure al método fromData. El closure debe retornar los datos en crudo que representan el adjunto:

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

Laravel también proporciona métodos adicionales que puede usar para personalizar sus adjuntos. Por ejemplo, puede 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');

#Encabezados

A veces puede necesitar adjuntar encabezados adicionales al mensaje saliente. Por ejemplo, puede necesitar establecer un Message-Id personalizado u otros encabezados de texto arbitrarios.

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

use Illuminate\Mail\Mailables\Headers;

/**
 * Obtener los encabezados del mensaje.
 */
public function headers(): Headers
{
    return new Headers(
        messageId: 'custom-message-id@example.com',
        references: ['previous-message@example.com'],
        text: [
            'X-Custom-Header' => 'Custom Value',
        ],
    );
}

#Etiquetas y Metadatos

Algunos proveedores de correo electrónico de terceros como Mailgun y Postmark soportan "etiquetas" y "metadatos" en los mensajes, que pueden usarse para agrupar y rastrear los correos enviados por su aplicación. Puede agregar etiquetas y metadatos a un mensaje de correo a través de la definición de su 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 su aplicación utiliza el driver Mailgun, puede consultar la documentación de Mailgun para más información sobre etiquetas y metadatos. De igual forma, la documentación de Postmark también puede consultarse para más información sobre su soporte para etiquetas y metadatos.

Si su aplicación utiliza Amazon SES para enviar correos, debe usar el método metadata para adjuntar “tags” de SES al mensaje.

#Personalizando el Mensaje de Symfony

Las capacidades de correo de Laravel están impulsadas por Symfony Mailer. Laravel le permite registrar callbacks personalizados que se invocarán con la instancia del mensaje Symfony antes de enviar el mensaje. Esto le brinda la oportunidad de personalizar profundamente el mensaje antes de enviarlo. Para lograr esto, defina un parámetro using en la definición de su 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) {
                // ...
            },
        ]
    );
}

#Mailables Markdown

Los mensajes mailable en Markdown le permiten aprovechar las plantillas y componentes preconstruidos de las notificaciones por correo en sus mailables. Dado que los mensajes están escritos en Markdown, Laravel puede renderizar hermosas y responsivas plantillas HTML para los mensajes, generando automáticamente una contraparte en texto plano.

#Generando Mailables Markdown

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

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

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

use Illuminate\Mail\Mailables\Content;

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

#Escribiendo Mensajes Markdown

Los mailables Markdown usan una combinación de componentes Blade y sintaxis Markdown que le permiten construir fácilmente mensajes de correo mientras aprovecha los componentes de interfaz de usuario de correo 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>
Примечание

No utilice una indentación excesiva al escribir correos en Markdown. Según los estándares de Markdown, los analizadores de Markdown renderizarán el contenido indentado como bloques de código.

#Componente Botón

El componente botón renderiza un enlace de botón centrado. El componente acepta dos argumentos, un url y un color opcional. Los colores soportados son primary, success y error. Puede agregar tantos componentes de botón como desee en un mensaje:

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

#Componente Panel

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

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

#Componente Tabla

El componente tabla le permite transformar una tabla Markdown en una tabla HTML. El componente acepta la tabla Markdown como su contenido. Se soporta la alineación de columnas usando la sintaxis de alineación predeterminada de tablas Markdown:

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

#Personalizando los Componentes

Puede exportar todos los componentes de correo Markdown a su propia aplicación para personalizarlos. Para exportar los componentes, use el comando Artisan vendor:publish para publicar la etiqueta de activos laravel-mail:

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 todos los componentes disponibles. Usted es libre de personalizar estos componentes como desee.

#Personalizando el CSS

Después de exportar los componentes, el directorio resources/views/vendor/mail/html/themes contendrá un archivo default.css. Puede personalizar el CSS en este archivo y sus estilos se convertirán automáticamente en estilos CSS en línea dentro de las representaciones HTML de sus mensajes Markdown.

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

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

#Enviando Correo

Para enviar un mensaje, use el método to en el 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 pasa un objeto o una colección de objetos, el mailer usará automáticamente sus propiedades email y name para determinar los destinatarios del correo, así que asegúrese de que estos atributos estén disponibles en sus objetos. Una vez que haya especificado sus destinatarios, puede pasar una instancia de su 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á limitado a especificar solo los destinatarios "to" al enviar un mensaje. Puede establecer destinatarios "to", "cc" y "bcc" encadenando sus métodos respectivos:

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

#Iterando sobre los destinatarios

Ocasionalmente, puede necesitar enviar un mailable a una lista de destinatarios iterando sobre un arreglo de destinatarios o direcciones de correo. Sin embargo, dado que el método to agrega direcciones de correo a la lista de destinatarios del mailable, cada iteración enviará otro correo a todos los destinatarios anteriores. Por lo tanto, siempre debe recrear la instancia del mailable para cada destinatario:

foreach (['taylor@example.com', 'dries@example.com'] as $recipient) {
    Mail::to($recipient)->send(new OrderShipped($order));
}

#Enviando correo usando un mailer específico

Por defecto, Laravel enviará correos usando el mailer configurado como default en el archivo de configuración mail de su aplicación. Sin embargo, puede usar el método mailer para enviar un mensaje usando una configuración de mailer específica:

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

#Encolando correo

#Encolando un mensaje de correo

Dado que enviar mensajes de correo puede afectar negativamente el tiempo de respuesta de su aplicación, muchos desarrolladores optan por encolar los mensajes para enviarlos en segundo plano. Laravel facilita esto usando su API unificada de colas. Para encolar un mensaje, use el método queue en el facade Mail después de especificar los destinatarios:

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. Deberá configurar sus colas antes de usar esta función.

#Encolado de mensajes con retraso

Si desea retrasar la entrega de un mensaje encolado, puede usar el método later. Como primer argumento, later acepta una instancia DateTime que indica cuándo debe enviarse el mensaje:

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

#Enviando a colas específicas

Dado que todas las clases mailable generadas con el comando make:mail usan el trait Illuminate\Bus\Queueable, puede llamar a los métodos onQueue y onConnection en cualquier instancia mailable, permitiéndole 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 tiene clases mailable que siempre desea que se encolen, puede implementar el contrato ShouldQueue en la clase. Ahora, incluso si llama al método send al enviar correo, el mailable seguirá siendo encolado porque implementa el contrato:

use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Mailable implements ShouldQueue
{
    // ...
}

#Mailables encolados y transacciones de base de datos

Cuando los mailables encolados se despachan dentro de transacciones de base de datos, pueden procesarse en la cola antes de que la transacción haya sido confirmada. Cuando esto sucede, cualquier actualización que haya hecho a modelos o registros durante la transacción puede no reflejarse aún en la base de datos. Además, cualquier modelo o registro creado dentro de la transacción puede no existir en la base de datos. Si su mailable depende de estos modelos, pueden ocurrir errores inesperados cuando se procese el trabajo que envía el mailable encolado.

Si la opción de configuración after_commit de su conexión de cola está establecida en false, aún puede indicar que un mailable encolado particular debe despacharse después de que todas las transacciones abiertas hayan sido confirmadas llamando al método afterCommit al enviar el mensaje:

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

Alternativamente, puede llamar al método afterCommit desde el constructor de su 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 del mensaje.
     */
    public function __construct()
    {
        $this->afterCommit();
    }
}
Примечание

Para aprender más sobre cómo manejar estos problemas, revise la documentación sobre trabajos encolados y transacciones de base de datos.

#Renderizando Mailables

A veces puede querer capturar el contenido HTML de un mailable sin enviarlo. Para lograr esto, puede 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();

#Previsualizando Mailables en el Navegador

Al diseñar la plantilla de un mailable, es conveniente previsualizar rápidamente el mailable renderizado en su navegador como una plantilla Blade típica. Por esta razón, Laravel permite devolver cualquier mailable directamente desde un closure de ruta o controlador. Cuando se devuelve un mailable, se renderiza y muestra en el navegador, permitiéndole previsualizar su diseño sin necesidad de enviarlo a una dirección de correo real:

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

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

#Localizando Mailables

Laravel le permite enviar mailables en un locale distinto al locale actual de la solicitud, e incluso recordará este locale si el correo es encolado.

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

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

#Locales Preferidos por el Usuario

A veces, las aplicaciones almacenan el locale preferido de cada usuario. Implementando el contrato HasLocalePreference en uno o más de sus modelos, puede indicar a Laravel que use este locale almacenado al enviar correos:

use Illuminate\Contracts\Translation\HasLocalePreference;

class User extends Model implements HasLocalePreference
{
    /**
     * Obtener el locale preferido del usuario.
     */
    public function preferredLocale(): string
    {
        return $this->locale;
    }
}

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

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

#Pruebas

#Probando el Contenido del Mailable

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

Como puede esperar, las aserciones "HTML" verifican que la versión HTML de su mailable contenga una cadena dada, mientras que las aserciones "texto" verifican que la versión en texto plano 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('jeffrey@example.com');
    $mailable->assertTo('taylor@example.com');
    $mailable->assertHasCc('abigail@example.com');
    $mailable->assertHasBcc('victoria@example.com');
    $mailable->assertHasReplyTo('tyler@example.com');
    $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']);
}

#Probando el Envío del Mailable

Sugerimos probar el contenido de sus mailables por separado de las pruebas que verifican que un mailable dado fue "enviado" a un usuario específico. Normalmente, el contenido de los mailables no es relevante para el código que está probando, y es suficiente con simplemente afirmar que Laravel fue instruido para enviar un mailable dado.

Puede usar el método fake del facade Mail para evitar que se envíen correos. Después de llamar al método fake del facade Mail, puede verificar que se indicó el envío de mailables a los usuarios e incluso inspeccionar los datos que recibieron los mailables:

<?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...

        // Afirmar que no se enviaron mailables...
        Mail::assertNothingSent();

        // Afirmar que se envió un mailable...
        Mail::assertSent(OrderShipped::class);

        // Afirmar que un mailable se envió dos veces...
        Mail::assertSent(OrderShipped::class, 2);

        // Afirmar que un mailable no se envió...
        Mail::assertNotSent(AnotherMailable::class);

        // Afirmar que se enviaron 3 mailables en total...
        Mail::assertSentCount(3);
    }
}

Si está encolando mailables para entrega en segundo plano, debe usar el método assertQueued en lugar de assertSent:

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

Puede pasar un closure a los métodos assertSent, assertNotSent, assertQueued o assertNotQueued para afirmar que se envió un mailable que pasa una determinada "prueba de verdad". Si al menos un mailable enviado pasa la prueba, 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 aserción del facade Mail, la instancia mailable aceptada por el closure proporcionado expone métodos útiles para examinar el mailable:

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 mailable también incluye varios métodos útiles para examinar los adjuntos en un mailable:

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

Probablemente haya notado que existen dos métodos para afirmar que no se envió correo: assertNotSent y assertNotQueued. A veces puede querer afirmar que no se envió ni se encoló correo. Para lograr esto, puede usar los métodos assertNothingOutgoing y assertNotOutgoing:

Mail::assertNothingOutgoing();

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

#Correo y Desarrollo Local

Al desarrollar una aplicación que envía correos, probablemente no quiera enviar correos reales a direcciones de correo en vivo. Laravel ofrece varias formas de "deshabilitar" el envío real de correos durante el desarrollo local.

#Driver de Registro (Log)

En lugar de enviar sus correos, el driver log escribirá todos los mensajes de correo en sus archivos de registro para inspección. Normalmente, este driver solo se usa durante el desarrollo local. Para más información sobre cómo configurar su aplicación por entorno, consulte la documentación de configuración.

#HELO / Mailtrap / Mailpit

Alternativamente, puede usar un servicio como HELO o Mailtrap y el driver smtp para enviar sus mensajes a un buzón "falso" donde puede verlos en un cliente de correo real. Este enfoque tiene la ventaja de permitirle inspeccionar realmente los correos finales en el visor de mensajes de Mailtrap.

Si usa Laravel Sail, puede previsualizar sus mensajes usando Mailpit. Cuando Sail está en ejecución, puede acceder a la interfaz de Mailpit en: http://localhost:8025.

#Usando una dirección global to

Finalmente, puede especificar una dirección global "to" invocando el método alwaysTo ofrecido por el facade Mail. Normalmente, este método debe llamarse desde el método boot de uno de los proveedores de servicios de su 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('taylor@example.com');
    }
}

#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 un mensaje ha sido enviado. Recuerde, estos eventos se disparan cuando el correo está siendo enviado, no cuando está encolado. Puede registrar listeners para estos eventos en su proveedor de servicios App\Providers\EventServiceProvider:

use App\Listeners\LogSendingMessage;
use App\Listeners\LogSentMessage;
use Illuminate\Mail\Events\MessageSending;
use Illuminate\Mail\Events\MessageSent;

/**
 * Mapeo de listeners 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, puede que desee escribir sus propios transportes para entregar correo a través de otros servicios que Laravel no soporta por defecto. Para comenzar, defina una clase que extienda la clase Symfony\Component\Mailer\Transport\AbstractTransport. Luego, implemente los métodos doSend y __toString() en su 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 del 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 en cadena del transporte.
     */
    public function __toString(): string
    {
        return 'mailchimp';
    }
}

Una vez que haya definido su transporte personalizado, puede registrarlo mediante el método extend proporcionado por el facade Mail. Normalmente, esto se realiza dentro del método boot del proveedor de servicios AppServiceProvider de su aplicación. Se pasará un argumento $config al closure proporcionado al método extend. Este argumento contendrá el arreglo de configuración definido para el mailer 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 su transporte personalizado ha sido definido y registrado, puede crear una definición de mailer dentro del archivo de configuración config/mail.php de su 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, puede que desee extender Laravel con soporte para transportes adicionales mantenidos por Symfony. Puede hacerlo requiriendo el mailer de Symfony necesario vía Composer y registrando el transporte en Laravel. Por ejemplo, puede instalar y registrar el mailer de Symfony "Brevo" (anteriormente "Sendinblue"):

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

Una vez instalado el paquete del mailer Brevo, puede agregar una entrada para sus credenciales API de Brevo en el archivo de configuración services de su aplicación:

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

Luego, puede usar el método extend del facade Mail para registrar el transporte en Laravel. Normalmente, esto se realiza 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 su transporte ha sido registrado, puede crear una definición de mailer dentro del archivo de configuración config/mail.php de su aplicación que utilice el nuevo transporte:

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