Документация Laravel 10.x
Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.
Отправка электронной почты не должна быть сложной. Laravel предоставляет чистый, простой API электронной почты, основанный на популярном Symfony Mailer. Laravel и Symfony Mailer предоставляют драйверы для отправки электронной почты через SMTP, Mailgun, Postmark, Amazon SES и sendmail
, что позволяет вам быстро начать отправлять почту через локальный или облачный сервис на ваш выбор.
Электронные почтовые службы Laravel можно настроить через файл конфигурации вашего приложения config/mail.php
. Каждый почтовый сервис, настроенный в этом файле, может иметь свою уникальную конфигурацию и даже свой уникальный "транспорт", позволяя вашему приложению использовать различные почтовые сервисы для отправки определенных электронных сообщений. Например, ваше приложение может использовать Postmark для отправки транзакционных электронных писем, а Amazon SES - для отправки массовых электронных писем.
В файле конфигурации mail
вы найдете массив конфигурации mailers
. Этот массив содержит пример конфигурации для каждого из основных почтовых драйверов / транспортов, поддерживаемых Laravel. Значение default
в конфигурации определяет, какой почтовый сервис будет использоваться по умолчанию, когда ваше приложение должно отправить электронное сообщение.
Драйверы на основе API, такие как Mailgun, Postmark и MailerSend, часто более просты и быстры в использовании, чем отправка почты через серверы SMTP. По возможности мы рекомендуем использовать один из этих драйверов.
Для использования драйвера Mailgun установите транспорт Mailgun Mailer Symfony через Composer:
composer require symfony/mailgun-mailer symfony/http-client
Затем установите параметр default
в файле конфигурации config/mail.php
вашего приложения в mailgun
. После настройки основного почтового сервиса вашего приложения проверьте, содержит ли ваш файл конфигурации config/services.php
следующие параметры:
'mailgun' => [ 'transport' => 'mailgun', 'domain' => env('MAILGUN_DOMAIN'), 'secret' => env('MAILGUN_SECRET'),],
Если вы не используете Mailgun region в Соединенных Штатах, вы можете определить конечную точку вашего региона в файле конфигурации services
:
'mailgun' => [ 'domain' => env('MAILGUN_DOMAIN'), 'secret' => env('MAILGUN_SECRET'), 'endpoint' => env('MAILGUN_ENDPOINT', 'api.eu.mailgun.net'),],
Для использования драйвера Postmark установите транспорт Postmark Mailer Symfony через Composer:
composer require symfony/postmark-mailer symfony/http-client
Затем установите параметр default
в файле конфигурации config/mail.php
вашего приложения в postmark
. После настройки основного почтового сервиса вашего приложения проверьте, содержит ли ваш файл конфигурации config/services.php
следующие параметры:
'postmark' => [ 'token' => env('POSTMARK_TOKEN'),],
Если вы хотите указать поток сообщений Postmark, который должен использоваться определенным почтовым сервисом, вы можете добавить опцию конфигурации message_stream_id
в массив конфигурации почтового сервиса. Этот массив конфигурации можно найти в файле конфигурации config/mail.php
вашего приложения:
'postmark' => [ 'transport' => 'postmark', 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),],
Таким образом, вы также можете настроить несколько почтовых сервисов Postmark с разными потоками сообщений.
Для использования драйвера Amazon SES вы должны сначала установить библиотеку Amazon AWS SDK для PHP. Вы можете установить эту библиотеку с помощью менеджера пакетов Composer:
composer require aws/aws-sdk-php
Затем установите опцию default
в вашем файле конфигурации config/mail.php
в ses
и убедитесь, что ваш файл конфигурации config/services.php
содержит следующие параметры:
'ses' => [ 'key' => env('AWS_ACCESS_KEY_ID'), 'secret' => env('AWS_SECRET_ACCESS_KEY'), 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),],
Чтобы использовать временные удостоверения AWS через токен сеанса, вы можете добавить ключ token
в конфигурацию вашего приложения SES:
'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'),],
Если вы хотите определить дополнительные параметры, которые Laravel должен передать методу SendEmail
AWS SDK при отправке электронной почты, вы можете определить массив options
в вашей конфигурации 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, сервис для отправки транзакционных электронных писем и SMS, поддерживает свой собственный драйвер почты API для Laravel. Пакет, содержащий драйвер, может быть установлен с помощью менеджера пакетов Composer:
composer require mailersend/laravel-driver
После установки пакета добавьте переменную окружения MAILERSEND_API_KEY
в файл .env
вашего приложения. Кроме того, переменная окружения MAIL_MAILER
должна быть определена как mailersend
:
MAIL_MAILER=mailersendMAIL_FROM_NAME="App Name" MAILERSEND_API_KEY=your-api-key
Чтобы узнать больше о MailerSend, включая использование хостинга шаблонов, ознакомьтесь с документацией по драйверу MailerSend.
Иногда внешний сервис, настроенный для отправки почты вашего приложения, может быть недоступен. В таких случаях полезно определить одну или несколько резервных конфигураций доставки почты, которые будут использоваться, если ваш основной драйвер доставки недоступен.
Для достижения этой цели вы должны определить почтовый сервис в файле конфигурации вашего приложения mail
, который использует транспорт failover
. Массив конфигурации для почтового сервиса failover
вашего приложения должен содержать массив mailers
, который ссылается на порядок выбора драйверов почты для доставки:
'mailers' => [ 'failover' => [ 'transport' => 'failover', 'mailers' => [ 'postmark', 'mailgun', 'sendmail', ], ], // ...],
После определения почтового сервиса failover установите его в качестве почтового сервиса по умолчанию для вашего приложения, указав его имя в качестве значения ключа default
в файле конфигурации вашего приложения mail
:
'default' => env('MAIL_MAILER', 'failover'),
При построении приложений Laravel каждый тип отправляемого приложением электронного письма представлен как класс "mailable". Эти классы хранятся в каталоге app/Mail
. Не беспокойтесь, если вы не видите этот каталог в своем приложении, так как он будет сгенерирован для вас при создании первого класса mailable с использованием команды Artisan make:mail
:
php artisan make:mail OrderShipped
После создания класса mailable откройте его, чтобы мы могли изучить его содержимое. Настройка класса mailable выполняется в нескольких методах, включая методы envelope
, content
и attachments
.
Метод envelope
возвращает объект Illuminate\Mail\Mailables\Envelope
, который определяет тему и, иногда, получателей сообщения. Метод content
возвращает объект Illuminate\Mail\Mailables\Content
, который определяет шаблон Blade, который будет использоваться для создания содержимого сообщения.
В первую очередь давайте рассмотрим настройку отправителя электронного письма. Или, другими словами, кто будет "отправителем" электронного письма. Есть два способа настройки отправителя. Во-первых, вы можете указать адрес "от" в конверте вашего сообщения:
use Illuminate\Mail\Mailables\Address;use Illuminate\Mail\Mailables\Envelope; /** * Получить конверт сообщения. */public function envelope(): Envelope{ return new Envelope( subject: 'Order Shipped', );}
Если хотите, вы также можете указать адрес для replyTo
:
return new Envelope( replyTo: [ ], subject: 'Order Shipped',);
Однако, если ваше приложение использует один и тот же адрес "отправителя" для всех своих электронных писем, может быть неудобно добавлять его в каждый созданный класс mailable. Вместо этого вы можете указать глобальный адрес "отправителя" в файле конфигурации config/mail.php
. Этот адрес будет использоваться, если в классе mailable не указан другой адрес "отправителя":
'from' => [ 'name' => env('MAIL_FROM_NAME', 'Example'),],
Кроме того, вы можете определить глобальный адрес "reply_to" в файле конфигурации config/mail.php
:
В методе content
класса mailable вы можете определить view
- шаблон, который будет использоваться при отображении содержимого электронного письма. Поскольку для отображения содержимого каждого электронного письма обычно используется шаблон Blade, у вас есть полная мощность и удобство шаблонизатора Blade при создании HTML-содержимого электронного письма:
/** * Получить определение содержимого сообщения. */public function content(): Content{ return new Content( view: 'emails.orders.shipped', );}
Примечание Возможно, вы захотите создать каталог
resources/views/emails
для размещения всех ваших шаблонов электронной почты; однако вы можете разместить их где угодно внутри вашего каталогаresources/views
.
Если вы хотите определить версию вашего электронного письма в виде обычного текста, вы можете указать шаблон обычного текста при создании определения Content
сообщения. Как и параметр view
, параметр text
должен быть именем шаблона, который будет использоваться для отображения содержимого электронного письма. Вы можете определить как HTML-, так и обычно-текстовую версию вашего сообщения:
/** * Получить определение содержимого сообщения. */public function content(): Content{ return new Content( view: 'emails.orders.shipped', text: 'emails.orders.shipped-text' );}
Для ясности параметр html
может использоваться в качестве псевдонима параметра view
:
return new Content( html: 'emails.orders.shipped', text: 'emails.orders.shipped-text');
Обычно вам захочется передать некоторые данные в ваш шаблон, которые вы можете использовать при отображении HTML-содержимого электронного письма. Есть два способа сделать данные доступными для вашего шаблона. Во-первых, любое общедоступное свойство, определенное в вашем классе mailable, автоматически станет доступным для шаблона. Таким образом, например, вы можете передавать данные в конструктор вашего класса mailable и устанавливать эти данные в общедоступные свойства, определенные в классе:
<?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; /** * Создать новый экземпляр сообщения. */ public function __construct( public Order $order, ) {} /** * Получить определение содержимого сообщения. */ public function content(): Content { return new Content( view: 'emails.orders.shipped', ); }}
Как только данные были установлены в общедоступное свойство, они автоматически становятся доступными в вашем шаблоне, поэтому вы можете обращаться к ним так, как обращаетесь к любым другим данным в шаблонах Blade:
<div> Price: {{ $order->price }}</div>
with
:Если вы хотите настроить формат данных вашего электронного письма перед его отправкой в шаблон, вы можете вручную передавать данные в виде параметра with
метода Content
в вашем шаблоне. Обычно вы все равно передаете данные через конструктор класса mailable; однако вы должны устанавливать эти данные в protected
или private
свойства, чтобы они не автоматически стали доступными в шаблоне:
<?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; /** * Создать новый экземпляр сообщения. */ public function __construct( protected Order $order, ) {} /** * Получить определение содержимого сообщения. */ public function content(): Content { return new Content( view: 'emails.orders.shipped', with: [ 'orderName' => $this->order->name, 'orderPrice' => $this->order->price, ], ); }}
Как только данные были переданы методу with
, они автоматически становятся доступными в вашем шаблоне, поэтому вы можете обращаться к ним так, как обращаетесь к любым другим данным в шаблонах Blade:
<div> Price: {{ $orderPrice }}</div>
Чтобы добавить вложения к электронному письму, вы добавите вложения в массив, возвращаемый методом attachments
сообщения. Сначала вы можете добавить вложение, предоставив путь к файлу методу fromPath
, предоставленному классом Attachment
:
use Illuminate\Mail\Mailables\Attachment; /** * Получить вложения для сообщения. * * @return array<int, \Illuminate\Mail\Mailables\Attachment> */public function attachments(): array{ return [ Attachment::fromPath('/path/to/file'), ];}
При добавлении файлов к сообщению вы также можете указать отображаемое имя и/или MIME-тип вложения с использованием методов as
и withMime
:
/** * Получить вложения для сообщения. * * @return array<int, \Illuminate\Mail\Mailables\Attachment> */public function attachments(): array{ return [ Attachment::fromPath('/path/to/file') ->as('name.pdf') ->withMime('application/pdf'), ];}
Если вы сохранили файл на одном из дисков файловой системы, вы можете прикрепить его к электронному письму с использованием метода прикрепления fromStorage
:
/** * Получить вложения для сообщения. * * @return array<int, \Illuminate\Mail\Mailables\Attachment> */public function attachments(): array{ return [ Attachment::fromStorage('/path/to/file'), ];}
Конечно, вы также можете указать имя и MIME-тип вложения:
/** * Получить вложения для сообщения. * * @return array<int, \Illuminate\Mail\Mailables\Attachment> */public function attachments(): array{ return [ Attachment::fromStorage('/path/to/file') ->as('name.pdf') ->withMime('application/pdf'), ];}
Метод fromStorageDisk
может использоваться, если вам нужно указать диск хранения, отличный от вашего основного диска:
/** * Получить вложения для сообщения. * * @return array<int, \Illuminate\Mail\Mailables\Attachment> */public function attachments(): array{ return [ Attachment::fromStorageDisk('s3', '/path/to/file') ->as('name.pdf') ->withMime('application/pdf'), ];}
Метод прикрепления fromData
может использоваться для прикрепления строки сырых байтов в виде вложения. Например, вы можете использовать этот метод, если сгенерировали PDF в памяти и хотите прикрепить его к электронному письму, не записывая его на диск. Метод fromData
принимает замыкание, которое разрешает сырые данные, а также имя, которое следует присвоить вложению:
/** * Получить вложения для сообщения. * * @return array<int, \Illuminate\Mail\Mailables\Attachment> */public function attachments(): array{ return [ Attachment::fromData(fn () => $this->pdf, 'Report.pdf') ->withMime('application/pdf'), ];}
Вставка встроенных изображений в ваши электронные письма обычно неудобна; однако Laravel предоставляет удобный способ прикрепления изображений к электронным письмам. Чтобы встроить встроенное изображение, используйте метод embed
на переменной $message
в вашем шаблоне электронного письма. Laravel автоматически делает переменную $message
доступной для всех ваших шаблонов электронной почты, поэтому вам не нужно беспокоиться о ее передаче вручную:
<body> Here is an image: <img src="{{ $message->embed($pathToImage) }}"></body>
Внимание Переменная
$message
недоступна в шаблонах простого текста, поскольку простые текстовые сообщения не используют встроенные вложения.
Если у вас уже есть строка с данными изображения, которую вы хотите встроить в шаблон электронного письма, вы можете вызвать метод embedData
на переменной $message
. При вызове метода embedData
вам нужно предоставить имя файла, которое следует присвоить встроенному изображению:
<body> Here is an image from raw data: <img src="{{ $message->embedData($data, 'example-image.jpg') }}"></body>
Хотя прикрепление файлов к сообщениям с использованием простых строковых путей часто достаточно, во многих случаях сущности, прикрепляемые в вашем приложении, представлены классами. Например, если ваше приложение прикрепляет фотографию к сообщению, у вашего приложения может быть также модель Photo
, представляющая эту фотографию. В таком случае было бы удобно просто передать модель Photo
методу attach
? Объекты, которые можно прикреплять, позволяют вам сделать это.
Для начала реализуйте интерфейс Illuminate\Contracts\Mail\Attachable
в объекте, который может быть прикреплен к сообщениям. Этот интерфейс требует, чтобы ваш класс определял метод toMailAttachment
, который возвращает экземпляр 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{ /** * Получить прикрепляемое представление модели. */ public function toMailAttachment(): Attachment { return Attachment::fromPath('/path/to/file'); }}
После того как вы определили объект, который можно прикрепить, вы можете вернуть экземпляр этого объекта из метода attachments
, создавая сообщение электронной почты:
/** * Получить вложения для сообщения. * * @return array<int, \Illuminate\Mail\Mailables\Attachment> */public function attachments(): array{ return [$this->photo];}
Конечно, данные вложения могут храниться на удаленном сервисе хранения файлов, таком как Amazon S3. Поэтому Laravel также позволяет создавать экземпляры вложений из данных, которые хранятся на одном из дисков файловой системы вашего приложения:
// Создать вложение из файла на вашем основном диске...return Attachment::fromStorage($this->path); // Создать вложение из файла на конкретном диске...return Attachment::fromStorageDisk('backblaze', $this->path);
Кроме того, вы можете создавать экземпляры вложений из данных, которые находятся в памяти. Для этого предоставьте замыкание методу fromData
. Замыкание должно возвращать сырые данные, представляющие вложение:
return Attachment::fromData(fn () => $this->content, 'Photo Name');
Laravel также предоставляет дополнительные методы, которые вы можете использовать для настройки ваших вложений. Например, вы можете использовать методы as
и withMime
для настройки имени файла и MIME-типа:
return Attachment::fromPath('/path/to/file') ->as('Photo Name') ->withMime('image/jpeg');
Иногда вам может потребоваться прикрепить дополнительные заголовки к исходящему сообщению. Например, вам может потребоваться установить пользовательский Message-Id
или другие произвольные текстовые заголовки.
Для этого определите метод headers
в вашем классе Mailable. Метод headers
должен возвращать экземпляр Illuminate\Mail\Mailables\Headers
. Этот класс принимает параметры messageId
, references
и text
. Конечно же, вы можете предоставить только те параметры, которые вам нужны для вашего конкретного сообщения:
use Illuminate\Mail\Mailables\Headers; /** * Получить заголовки сообщения. */public function headers(): Headers{ return new Headers( text: [ 'X-Custom-Header' => 'Custom Value', ], );}
Некоторые сторонние почтовые провайдеры, такие как Mailgun и Postmark, поддерживают "теги" и "метаданные" сообщений, которые могут использоваться для группировки и отслеживания электронных писем, отправленных вашим приложением. Вы можете добавлять теги и метаданные к электронному сообщению через определение вашего Envelope
:
use Illuminate\Mail\Mailables\Envelope; /** * Получить конверт сообщения. * * @return \Illuminate\Mail\Mailables\Envelope */public function envelope(): Envelope{ return new Envelope( subject: 'Order Shipped', tags: ['shipment'], metadata: [ 'order_id' => $this->order->id, ], );}
Если ваше приложение использует драйвер Mailgun, вы можете ознакомиться с документацией Mailgun для получения дополнительной информации о тегах и метаданных. Также можно обратиться к документации Postmark для получения дополнительной информации о поддержке тегов и метаданных.
Если ваше приложение использует Amazon SES для отправки электронных писем, вы должны использовать метод metadata
для прикрепления тегов SES к сообщению.
Возможности почты Laravel основаны на Symfony Mailer. Laravel позволяет регистрировать пользовательские обратные вызовы, которые будут вызываться с экземпляром Symfony Message перед отправкой сообщения. Это предоставляет вам возможность глубоко настроить сообщение перед его отправкой. Для этого определите параметр using
в вашем Envelope
:
use Illuminate\Mail\Mailables\Envelope;use Symfony\Component\Mime\Email; /** * Получить конверт сообщения. */public function envelope(): Envelope{ return new Envelope( subject: 'Order Shipped', using: [ function (Email $message) { // ... }, ] );}
Сообщения в формате Markdown могут использовать заранее созданные шаблоны и компоненты уведомлений по электронной почте в ваших Mailable. Поскольку сообщения написаны в формате Markdown, Laravel может создавать красивые адаптивные HTML-шаблоны для сообщений, автоматически генерируя при этом плоский текстовый аналог.
Чтобы создать Mailable с соответствующим шаблоном Markdown, вы можете использовать опцию --markdown
команды Artisan make:mail
:
php artisan make:mail OrderShipped --markdown=emails.orders.shipped
Затем при настройке Content
в методе content
Mailable используйте параметр markdown
вместо параметра view
:
use Illuminate\Mail\Mailables\Content; /** * Получить определение содержимого сообщения. */public function content(): Content{ return new Content( markdown: 'emails.orders.shipped', with: [ 'url' => $this->orderUrl, ], );}
Markdown Mailable используют комбинацию компонентов Blade и синтаксиса Markdown, что позволяет легко создавать почтовые сообщения, используя предварительно созданные компоненты пользовательского интерфейса электронной почты 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>
Примечание Не используйте избыточный отступ при написании Markdown-писем. Согласно стандартам Markdown, парсеры Markdown рендерят вложенный контент как блоки кода.
Компонент кнопки выводит центрированную ссылку-кнопку. Компонент принимает два аргумента: url
и необязательный color
. Поддерживаемые цвета: primary
, success
и error
. Вы можете добавить столько компонентов кнопок в сообщение, сколько вам нужно:
<x-mail::button :url="$url" color="success">View Order</x-mail::button>
Компонент панели выводит блок текста в панели, которая имеет слегка отличающийся цвет фона по сравнению с остальной частью сообщения. Это позволяет выделить блок текста:
<x-mail::panel>This is the panel content.</x-mail::panel>
Компонент таблицы позволяет преобразовать таблицу Markdown в HTML-таблицу. Компонент принимает таблицу Markdown в качестве своего содержимого. Выравнивание столбцов таблицы поддерживается с использованием стандартного синтаксиса выравнивания таблиц Markdown:
<x-mail::table>| Laravel | Table | Example || ------------- |:-------------:| --------:|| Col 2 is | Centered | $10 || Col 3 is | Right-Aligned | $20 |</x-mail::table>
Вы можете экспортировать все компоненты почты Markdown в свое собственное приложение для настройки. Чтобы экспортировать компоненты, используйте команду Artisan vendor:publish
для публикации тега актива laravel-mail
:
php artisan vendor:publish --tag=laravel-mail
Эта команда опубликует компоненты почты Markdown в каталог resources/views/vendor/mail
. Каталог mail
будет содержать каталоги html
и text
, каждый из которых содержит соответствующие представления всех доступных компонентов. Вы можете свободно настраивать эти компоненты так, как вам угодно.
После экспорта компонентов каталог resources/views/vendor/mail/html/themes
будет содержать файл default.css
. Вы можете настраивать CSS в этом файле, и ваши стили автоматически будут преобразованы в инлайн-стили CSS в HTML-представлениях ваших сообщений электронной почты Markdown.
Если вы хотите создать совершенно новую тему для компонентов Markdown Laravel, вы можете разместить файл CSS в каталоге html/themes
. После того как вы назвали и сохранили свой файл CSS, обновите параметр theme
файла конфигурации config/mail.php
вашего приложения, чтобы он соответствовал имени вашей новой темы.
Чтобы настроить тему для отдельного Mailable, вы можете установить свойство $theme
класса Mailable в имя темы, которую следует использовать при отправке этого Mailable.
Для отправки сообщения используйте метод to
на фасаде Mail
. Метод to
принимает адрес электронной почты, экземпляр пользователя или коллекцию пользователей. Если вы передаете объект или коллекцию объектов, почтовый сервис автоматически использует их свойства email
и name
при определении получателей электронных писем, поэтому убедитесь, что эти атрибуты доступны в ваших объектах. После указания получателей вы можете передать экземпляр вашего класса Mailable методу 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{ /** * Отправить данный заказ. */ public function store(Request $request): RedirectResponse { $order = Order::findOrFail($request->order_id); // Отправить заказ... Mail::to($request->user())->send(new OrderShipped($order)); return redirect('/orders'); }}
Вы не ограничены только указанием получателей "to" при отправке сообщения. Вы свободны устанавливать получателей "to", "cc" и "bcc", объединяя их соответствующие методы:
Mail::to($request->user()) ->cc($moreUsers) ->bcc($evenMoreUsers) ->send(new OrderShipped($order));
Иногда вам может потребоваться отправить Mailable списку получателей, перебирая массив получателей / адресов электронной почты. Однако, поскольку метод to
добавляет адреса электронной почты в список получателей Mailable, каждая итерация цикла отправит электронное письмо каждому предыдущему получателю. Поэтому всегда пересоздавайте экземпляр Mailable для каждого получателя:
Mail::to($recipient)->send(new OrderShipped($order));}
По умолчанию Laravel будет отправлять электронные письма с использованием почтового сервиса, настроенного как почтовый сервис default
в файле конфигурации mail
вашего приложения. Однако вы можете использовать метод mailer
для отправки сообщения с использованием конкретной конфигурации почтового сервиса:
Mail::mailer('postmark') ->to($request->user()) ->send(new OrderShipped($order));
Поскольку отправка электронных сообщений может негативно сказаться на время ответа вашего приложения, многие разработчики предпочитают постановку электронных сообщений в очередь для отправки в фоновом режиме. Laravel делает это легким с использованием своего встроенного единого API для очередей. Чтобы поставить сообщение в очередь, используйте метод queue
на фасаде Mail
после указания получателей сообщения:
Mail::to($request->user()) ->cc($moreUsers) ->bcc($evenMoreUsers) ->queue(new OrderShipped($order));
Этот метод автоматически поместит задачу в очередь, чтобы сообщение было отправлено в фоновом режиме. Вы должны настроить свои очереди перед использованием этой функции.
Если вы хотите задержать отправку сообщения из очереди, вы можете использовать метод later
. В качестве первого аргумента метод later
принимает экземпляр DateTime
, указывающий, когда сообщение должно быть отправлено:
Mail::to($request->user()) ->cc($moreUsers) ->bcc($evenMoreUsers) ->later(now()->addMinutes(10), new OrderShipped($order));
Поскольку все классы Mailable, созданные с использованием команды make:mail
, используют трейт Illuminate\Bus\Queueable
, вы можете вызывать методы onQueue
и onConnection
на любом экземпляре класса Mailable, что позволяет вам указать соединение и имя очереди для сообщения:
$message = (new OrderShipped($order)) ->onConnection('sqs') ->onQueue('emails'); Mail::to($request->user()) ->cc($moreUsers) ->bcc($evenMoreUsers) ->queue($message);
Если у вас есть классы Mailable, которые всегда должны поставляться в очередь, вы можете реализовать контракт ShouldQueue
в классе. Теперь, даже если вы вызовете метод send
при отправке почты, Mailable все равно будет поставлен в очередь, так как он реализует этот контракт:
use Illuminate\Contracts\Queue\ShouldQueue; class OrderShipped extends Mailable implements ShouldQueue{ // ...}
Когда Mailable поставляются в очередь в пределах транзакций базы данных, они могут быть обработаны очередью до того, как транзакция базы данных была подтверждена. Когда это происходит, любые обновления, которые вы внесли в модели или записи базы данных во время транзакции базы данных, могут еще не отразиться в базе данных. Кроме того, любые модели или записи базы данных, созданные в пределах транзакции, могут не существовать в базе данных. Если ваш Mailable зависит от этих моделей, при обработке задачи, отправляющей Mailable в очереди, могут возникнуть непредвиденные ошибки.
Если параметр after_commit
вашего соединения с очередью установлен в значение false
, вы все равно можете указать, что конкретный Mailable, поставленный в очередь, должен быть отправлен после завершения всех открытых транзакций базы данных, вызвав метод afterCommit
при отправке сообщения электронной почты:
Mail::to($request->user())->send( (new OrderShipped($order))->afterCommit());
В качестве альтернативы, вы можете вызвать метод afterCommit
из конструктора вашего 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; /** * Создать новый экземпляр сообщения. */ public function __construct() { $this->afterCommit(); }}
Примечание Чтобы узнать больше о том, как работать с этими проблемами, ознакомьтесь с документацией по очередям и транзакциям с базой данных.
Иногда вам может потребоваться сохранить HTML-контент Mailable без его отправки. Для этого вы можете вызвать метод render
Mailable. Этот метод вернет оцененный HTML-контент Mailable в виде строки:
use App\Mail\InvoicePaid;use App\Models\Invoice; $invoice = Invoice::find(1); return (new InvoicePaid($invoice))->render();
При проектировании шаблона Mailable удобно быстро предварительно просматривать отрендеренный Mailable в вашем браузере, как типичный шаблон Blade. По этой причине Laravel позволяет вам возвращать любой Mailable напрямую из замыкания маршрута или контроллера. Когда Mailable возвращается, он будет отрендерен и отображен в браузере, позволяя вам быстро предварительно просматривать его дизайн, не отправляя его по фактическому адресу электронной почты:
Route::get('/mailable', function () { $invoice = App\Models\Invoice::find(1); return new App\Mail\InvoicePaid($invoice);});
Laravel позволяет отправлять Mailable на языке, отличном от текущего языка запроса, и даже запоминать этот язык, если письмо поставлено в очередь.
Для этого фасад Mail
предлагает метод locale
для установки желаемого языка. Приложение переключится на этот язык во время оценки шаблона Mailable, а затем вернется к предыдущему языку после завершения оценки:
Mail::to($request->user())->locale('es')->send( new OrderShipped($order));
Иногда приложения сохраняют предпочтительный язык каждого пользователя. Реализовав контракт HasLocalePreference
на одной или нескольких ваших моделях, вы можете указать Laravel использовать этот сохраненный язык при отправке почты:
use Illuminate\Contracts\Translation\HasLocalePreference; class User extends Model implements HasLocalePreference{ /** * Получить предпочтительный язык пользователя. */ public function preferredLocale(): string { return $this->locale; }}
После реализации интерфейса Laravel автоматически будет использовать предпочтительный язык при отправке Mailable и уведомлений модели. Следовательно, нет необходимости вызывать метод locale
, когда используется этот интерфейс:
Mail::to($request->user())->send(new OrderShipped($order));
Laravel предоставляет разнообразные методы для проверки структуры вашего Mailable. Кроме того, Laravel предоставляет несколько удобных методов для проверки того, что ваш Mailable содержит ожидаемый контент. Эти методы: assertSeeInHtml
, assertDontSeeInHtml
, assertSeeInOrderInHtml
, assertSeeInText
, assertDontSeeInText
, assertSeeInOrderInText
, assertHasAttachment
, assertHasAttachedData
, assertHasAttachmentFromStorage
, и assertHasAttachmentFromStorageDisk
.
Как вы, возможно, ожидаете, утверждения "HTML" проверяют, что HTML-версия вашего Mailable содержит данный фрагмент, в то время как утверждения "text" проверяют, что простой текстовый вариант вашего Mailable содержит данный фрагмент:
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']);}
Мы предлагаем тестировать содержимое ваших Mailables отдельно от ваших тестов, которые утверждают, что определенный Mailable был "отправлен" конкретному пользователю. Как правило, содержимое Mailables не имеет отношения к коду, который вы тестируете, и достаточно просто утверждать, что Laravel был настроен отправлять определенный Mailable.
Вы можете использовать метод fake
фасада Mail
, чтобы предотвратить отправку почты. После вызова метода fake
фасада Mail
, вы можете утверждать, что Mailables были настроены для отправки пользователям, и даже проверять данные, которые получили 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(); // Выполнить доставку заказа... // Проверить, что не было отправлено почтовых сообщений... Mail::assertNothingSent(); // Проверить, что было отправлено почтовое сообщение... Mail::assertSent(OrderShipped::class); // Проверить, что почтовое сообщение было отправлено дважды... Mail::assertSent(OrderShipped::class, 2); // Проверить, что почтовое сообщение не было отправлено... Mail::assertNotSent(AnotherMailable::class); // Проверить, что было отправлено всего 3 почтовых сообщения... Mail::assertSentCount(3); }}
Если вы помещаете Mailables в очередь для доставки в фоне, вы должны использовать метод assertQueued
вместо assertSent
:
Mail::assertQueued(OrderShipped::class);Mail::assertNotQueued(OrderShipped::class);Mail::assertNothingQueued();Mail::assertQueuedCount(3);
Вы можете передать замыкание методам assertSent
, assertNotSent
, assertQueued
или assertNotQueued
, чтобы утверждать, что было отправлено Mailable, которое проходит заданный "тест истинности". Если хотя бы одно Mailable было отправлено и проходит заданный тест, то утверждение будет успешным:
Mail::assertSent(function (OrderShipped $mail) use ($order) { return $mail->order->id === $order->id;});
При вызове методов утверждения фасада Mail
, экземпляр Mailable, принимаемый предоставленным замыканием, предоставляет полезные методы для изучения 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('...');});
Экземпляр Mailable также включает несколько полезных методов для изучения вложений 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') );});
Вы, возможно, заметили, что есть два метода для утверждения, что почта не была отправлена: assertNotSent
и assertNotQueued
. Иногда вы можете захотеть утверждать, что почта не была отправлена или помещена в очередь. Для этого вы можете использовать методы assertNothingOutgoing
и assertNotOutgoing
:
Mail::assertNothingOutgoing(); Mail::assertNotOutgoing(function (OrderShipped $mail) use ($order) { return $mail->order->id === $order->id;});
При разработке приложения, которое отправляет электронную почту, вероятно, вы не захотите фактически отправлять электронные письма на реальные адреса электронной почты. Laravel предоставляет несколько способов «отключения» фактической отправки электронных писем во время локальной разработки.
Вместо отправки ваших электронных писем драйвер log
будет записывать все сообщения электронной почты в ваши файлы журнала для последующего их рассмотрения. Обычно этот драйвер используется только во время локальной разработки. Дополнительную информацию о настройке вашего приложения для каждого окружения вы найдете в документации по конфигурации.
В качестве альтернативы вы можете использовать сервис, такой как HELO или Mailtrap, и драйвер smtp
для отправки ваших сообщений электронной почты на «фиктивный» почтовый ящик, где вы можете просматривать их в настоящем почтовом клиенте. Этот подход позволяет вам фактически проверять окончательные электронные письма в просмотрщике сообщений Mailtrap.
Если вы используете Laravel Sail, вы можете предварительно просматривать ваши сообщения, используя Mailpit. Когда Sail работает, вы можете получить доступ к интерфейсу Mailpit по адресу: http://localhost:8025
.
Наконец, вы можете указать глобальный адрес "to", вызвав метод alwaysTo
фасада Mail
. Обычно этот метод следует вызывать из метода boot
одного из поставщиков служб вашего приложения:
use Illuminate\Support\Facades\Mail; /** * Загрузить все службы приложения. */public function boot(): void{ if ($this->app->environment('local')) { }}
Laravel генерирует два события в процессе отправки сообщений по электронной почте. Событие MessageSending
возникает перед отправкой сообщения, в то время как событие MessageSent
возникает после отправки сообщения. Помните, что эти события возникают, когда почта отправляется, а не когда она помещается в очередь. Вы можете зарегистрировать слушателей событий для этого события в вашем поставщике служб App\Providers\EventServiceProvider
:
use App\Listeners\LogSendingMessage;use App\Listeners\LogSentMessage;use Illuminate\Mail\Events\MessageSending;use Illuminate\Mail\Events\MessageSent; /** * Отображение сопоставлений слушателей событий для приложения. * * @var array */protected $listen = [ MessageSending::class => [ LogSendingMessage::class, ], MessageSent::class => [ LogSentMessage::class, ],];
В Laravel предусмотрено множество транспортов электронной почты; однако вы можете захотеть написать свои транспорты для доставки электронной почты через другие службы, которые Laravel не поддерживает из коробки. Для начала определите класс, который расширяет класс Symfony\Component\Mailer\Transport\AbstractTransport
. Затем реализуйте методы doSend
и __toString()
в вашем транспорте:
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{ /** * Создание нового экземпляра транспорта 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(), ]]); } /** * Получение строкового представления транспорта. */ public function __toString(): string { return 'mailchimp'; }}
После того как вы определили свой собственный транспорт, вы можете зарегистрировать его с помощью метода extend
, предоставленного фасадом Mail
. Обычно это следует сделать в методе boot
сервис-провайдера вашего приложения AppServiceProvider
. В замыкание, предоставленное методу extend
, будет передан аргумент $config
. Этот аргумент будет содержать массив конфигурации, определенный для почтового сервиса в файле конфигурации вашего приложения config/mail.php
:
use App\Mail\MailchimpTransport;use Illuminate\Support\Facades\Mail; /** * Загрузить все службы приложения. */public function boot(): void{ Mail::extend('mailchimp', function (array $config = []) { return new MailchimpTransport(/* ... */); });}
Как только ваш собственный транспорт будет определен и зарегистрирован, вы можете создать определение почтового сервиса в файле конфигурации вашего приложения config/mail.php
, которое использует новый транспорт:
'mailchimp' => [ 'transport' => 'mailchimp', // ...],
Laravel включает поддержку некоторых существующих транспортов для почты, поддерживаемых Symfony, таких как Mailgun и Postmark. Однако вы можете желать расширить поддержку Laravel для дополнительных транспортов, поддерживаемых Symfony. Вы можете сделать это, добавив необходимый Symfony mailer через Composer и зарегистрировав транспорт в Laravel. Например, вы можете установить и зарегистрировать Symfony mailer "Brevo" (ранее "Sendinblue"):
composer require symfony/brevo-mailer symfony/http-client
После установки пакета Brevo mailer вы можете добавить запись с вашими учетными данными API Brevo в файл конфигурации сервисов вашего приложения services
:
'brevo' => [ 'key' => 'your-api-key',],
Затем вы можете использовать метод extend
фасада Mail
для регистрации транспорта в Laravel. Обычно это следует сделать в методе boot
сервис-провайдера:
use Illuminate\Support\Facades\Mail;use Symfony\Component\Mailer\Bridge\Brevo\Transport\BrevoTransportFactory;use Symfony\Component\Mailer\Transport\Dsn; /** * Загрузить все службы приложения. */public function boot(): void{ Mail::extend('brevo', function () { return (new BrevoTransportFactory)->create( new Dsn( 'brevo+api', 'default', config('services.brevo.key') ) ); });}
После регистрации вашего транспорта вы можете создать определение почтового сервиса в файле конфигурации вашего приложения config/mail.php, которое использует новый транспорт:
'brevo' => [ 'transport' => 'brevo', // ...],