Documentación de Laravel 10.x
Aquí encontrarás fragmentos de código de Laravel y consejos útiles sobre desarrollo web.
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.
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.
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.
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'),],
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.
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'], ], ],],
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=mailersendMAIL_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.
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'),
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
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.
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( subject: 'Order Shipped', );}
Si lo deseas, también puedes especificar una dirección replyTo
:
return new Envelope( replyTo: [ ], subject: 'Order Shipped',);
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' => [ '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
:
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 directorioresources/views
.
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');
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>
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>
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'), ];}
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'), ];}
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'), ];}
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.
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>
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');
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( text: [ 'X-Custom-Header' => 'Custom Value', ], );}
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.
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) { // ... }, ] );}
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.
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, ], );}
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.
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>
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>
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>
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.
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.
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));
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:
Mail::to($recipient)->send(new OrderShipped($order));}
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));
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.
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));
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);
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{ // ...}
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.
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();
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);});
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));
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));
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->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']);}
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;});
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.
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.
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
.
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')) { }}
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, ],];
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', // ...],
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', // ...],