1. Глубже в детали
  2. Почта

Присоединяйся к нашему Telegram сообществу @webblend!

Здесь ты найдешь сниппеты по 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 установите транспорт 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 установите транспорт 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 с разными потоками сообщений.

Драйвер SES

Для использования драйвера 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

MailerSend, сервис для отправки транзакционных электронных писем и SMS, поддерживает свой собственный драйвер почты API для Laravel. Пакет, содержащий драйвер, может быть установлен с помощью менеджера пакетов Composer:

composer require mailersend/laravel-driver

После установки пакета добавьте переменную окружения MAILERSEND_API_KEY в файл .env вашего приложения. Кроме того, переменная окружения MAIL_MAILER должна быть определена как mailersend:

MAIL_MAILER=mailersend
MAIL_FROM_ADDRESS=[email protected]
MAIL_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'),

Генерация Mailables

При построении приложений Laravel каждый тип отправляемого приложением электронного письма представлен как класс "mailable". Эти классы хранятся в каталоге app/Mail. Не беспокойтесь, если вы не видите этот каталог в своем приложении, так как он будет сгенерирован для вас при создании первого класса mailable с использованием команды Artisan make:mail:

php artisan make:mail OrderShipped

Создание Mailables

После создания класса 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(
from: new Address('[email protected]', 'Jeffrey Way'),
subject: 'Order Shipped',
);
}

Если хотите, вы также можете указать адрес для replyTo:

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

Использование глобального адреса "От кого"

Однако, если ваше приложение использует один и тот же адрес "отправителя" для всех своих электронных писем, может быть неудобно добавлять его в каждый созданный класс mailable. Вместо этого вы можете указать глобальный адрес "отправителя" в файле конфигурации config/mail.php. Этот адрес будет использоваться, если в классе mailable не указан другой адрес "отправителя":

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

Кроме того, вы можете определить глобальный адрес "reply_to" в файле конфигурации config/mail.php:

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

Настройка представления

В методе 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(
messageId: '[email protected]',
references: ['[email protected]'],
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 к сообщению.

Настройка сообщения Symfony

Возможности почты 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) {
// ...
},
]
);
}

Mailables с Markdown

Сообщения в формате Markdown могут использовать заранее созданные шаблоны и компоненты уведомлений по электронной почте в ваших Mailable. Поскольку сообщения написаны в формате Markdown, Laravel может создавать красивые адаптивные HTML-шаблоны для сообщений, автоматически генерируя при этом плоский текстовый аналог.

Генерация Mailables с Markdown

Чтобы создать 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

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, каждый из которых содержит соответствующие представления всех доступных компонентов. Вы можете свободно настраивать эти компоненты так, как вам угодно.

Настройка CSS

После экспорта компонентов каталог 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 для каждого получателя:

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

Отправка почты через определенный Mailer

По умолчанию 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
{
// ...
}

Mailables в очереди и транзакции с базой данных

Когда 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();
}
}

Примечание Чтобы узнать больше о том, как работать с этими проблемами, ознакомьтесь с документацией по очередям и транзакциям с базой данных.

Отображение Mailables

Иногда вам может потребоваться сохранить HTML-контент Mailable без его отправки. Для этого вы можете вызвать метод render Mailable. Этот метод вернет оцененный HTML-контент Mailable в виде строки:

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

Предварительный просмотр Mailables в браузере

При проектировании шаблона Mailable удобно быстро предварительно просматривать отрендеренный Mailable в вашем браузере, как типичный шаблон Blade. По этой причине Laravel позволяет вам возвращать любой Mailable напрямую из замыкания маршрута или контроллера. Когда Mailable возвращается, он будет отрендерен и отображен в браузере, позволяя вам быстро предварительно просматривать его дизайн, не отправляя его по фактическому адресу электронной почты:

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

Локализация Mailables

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

Тестирование

Тестирование содержимого Mailable

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->assertFrom('[email protected]');
$mailable->assertTo('[email protected]');
$mailable->assertHasCc('[email protected]');
$mailable->assertHasBcc('[email protected]');
$mailable->assertHasReplyTo('[email protected]');
$mailable->assertHasSubject('Invoice Paid');
$mailable->assertHasTag('example-tag');
$mailable->assertHasMetadata('key', 'value');
 
$mailable->assertSeeInHtml($user->email);
$mailable->assertSeeInHtml('Invoice Paid');
$mailable->assertSeeInOrderInHtml(['Invoice Paid', 'Thanks']);
 
$mailable->assertSeeInText($user->email);
$mailable->assertSeeInOrderInText(['Invoice Paid', 'Thanks']);
 
$mailable->assertHasAttachment('/path/to/file');
$mailable->assertHasAttachment(Attachment::fromPath('/path/to/file'));
$mailable->assertHasAttachedData($pdfData, 'name.pdf', ['mime' => 'application/pdf']);
$mailable->assertHasAttachmentFromStorage('/path/to/file', 'name.pdf', ['mime' => 'application/pdf']);
$mailable->assertHasAttachmentFromStorageDisk('s3', '/path/to/file', 'name.pdf', ['mime' => 'application/pdf']);
}

Тестирование отправки Mailable

Мы предлагаем тестировать содержимое ваших 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 / Mailpit

В качестве альтернативы вы можете использовать сервис, такой как 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')) {
Mail::alwaysTo('[email protected]');
}
}

События

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',
// ...
],

Дополнительные транспорты Symfony

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',
// ...
],