Введение
Laravel предоставляет простой API к популярной библиотеке SwiftMailer c драйверами для SMTP, Mailgun, Mandrill (для Laravel 5.2 и ранее), SparkPost, Amazon SES, функции PHP mail, и sendmail, поэтому вы можете быстро приступить к рассылке почты с помощью локального или облачного сервиса на ваш выбор.
Требования для драйверов
Драйверы на основе API, такие как Mailgun и SparkPost, зачастую работают проще и быстрее, чем SMTP-серверы. По возможности лучше использовать именно их. Для работы таких драйверов необходима HTTP-библиотека Guzzle, которую можно установить через менеджер пакетов Composer:
shcomposer require guzzlehttp/guzzle
Для использования драйвера Mailgun установите Guzzle и задайте для параметра driver значение mailgun в конфигурационном файле config/mail.php. Затем проверьте, что в конфигурационном файле config/services.php есть следующие параметры:
'mailgun' => [
'domain' => 'your-mailgun-domain',
'secret' => 'your-mailgun-key',
],
Чтобы использовать драйвер Amazon SES, сначала установите Amazon AWS SDK для PHP. Вы можете установить эту библиотеку, добавив следующую строку в раздел require файла composer.json и выполнив команду shcomposer update
:
"aws/aws-sdk-php": "~3.0"
Затем задайте для параметра driver значение ses в конфигурационном файле config/mail.php и проверьте, что в конфигурационном файле config/services.php есть следующие параметры:
'ses' => [
'key' => 'your-ses-key',
'secret' => 'your-ses-secret',
'region' => 'ses-region', // например, us-east-1
],
добавлено в 5.3 ()
Создание отправляемых объектов
В Laravel каждый отправляемый приложением тип email-сообщения представлен «отправляемым» классом. Эти классы хранятся в папке app/Mail. Если у вас нет такой папки, она будет сгенерирована при создании первого отправляемого класса командой shmake:mail
:
shphp artisan make:mail OrderShipped
Написание отправляемых объектов
Все настройки отправляемого класса происходят в методе PHPbuild()
. В этом методе вы можете вызывать различные другие методы, такие как PHPfrom()
, PHPsubject()
, PHPview()
и PHPattach()
, для настройки содержимого и доставки email-сообщения.
Настройка отправителя
Сначала давайте рассмотрим настройку отправителя email. Другими словами — от кого будет приходить email. Есть два способа настроить отправителя. Первый — с помощью метода PHPfrom()
в методе PHPbuild()
вашего отправляемого класса:
/**
* Создание сообщения.
*
* @return $this
*/
public function build()
{
return $this->from('example@example.com')
->view('emails.orders.shipped');
}
Используя глобальный адрес from
Если ваше приложение использует одинаковый адрес отправителя для всех своих email-сообщений, то будет излишне вызывать метод PHPfrom()
в каждом генерируемом классе. Вместо этого вы можете указать глобальный адрес from в файле настроек config/mail.php. Этот адрес будет использован тогда, когда в отправляемом классе не указан никакой другой адрес отправителя:
'from' => ['address' => 'example@example.com', 'name' => 'App Name'],
Настройка представления
В методе PHPbuild()
отправляемого класса вы можете использовать метод PHPview()
для указания шаблона для построения содержимого email-сообщения. Поскольку обычно для построения содержимого всех email-сообщений используется Blade-шаблон, вам доступна вся мощь и всё удобство шаблонизатора Blade для создания HTML-кода ваших email-сообщений:
/**
* Создание сообщения.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped');
}
Вы можете создать папку resources/views/emails для размещения всех ваших email-шаблонов, или любую другую папку в каталоге resources/views.
Если вы хотите определить текстовую версию вашего email, используйте метод PHPtext()
. Подобно методу PHPview()
метод PHPtext()
принимает имя шаблона, который будет использован для построения содержимого email-сообщения. Вы можете определить обе версии вашего сообщения — HTML и текстовую:
/**
* Создание сообщения.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->text('emails.orders.shipped_plain');
}
Данные представления
Обычно необходимо передать какие-либо данные в представление, которые можно использовать при построении HTML-кода email-сообщения. Есть два способа сделать данные доступными для вашего представления. Первый — любое общедоступное (public) свойство, определённое в вашем отправляемом классе, автоматически станет доступным для представления. Например, вы можете передать данные в конструктор вашего отправляемого класса и поместить эти данные в общедоступные свойства, определённые в классе:
<?php
namespace App\Mail;
use App\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
/**
* Экземпляр заказа.
*
* @var Order
*/
public $order;
/**
* Создание нового экземпляра сообщения.
*
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* Создание сообщения.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped');
}
}
Когда данные помещены в общедоступное свойство, они автоматически станут доступны в вашем представлении, и вы можете обращаться к ним как к любым другим данным Blade-шаблонах:
<div>
Price: {{ $order->price }}
</div>
Если вы хотите настроить формат данных вашего email-сообщения до того, как они будут отправлены в шаблон, вы можете вручную передать данные в представление методом PHPwith()
. Вы будете по-прежнему передавать данные через конструктор отправляемого класса, но вам надо поместить эти данные в свойства protected или private, чтобы данные не были автоматически доступны шаблону. Затем при вызове метода PHPwith()
передайте массив данных, которые должны быть доступны шаблону:
<?php
namespace App\Mail;
use App\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
/**
* Экземпляр заказа.
*
* @var Order
*/
protected $order;
/**
* Создание нового экземпляра сообщения.
*
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* Создание сообщения.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->with([
'orderName' => $this->order->name,
'orderPrice' => $this->order->price,
]);
}
}
После передачи данных в метод PHPwith()
они автоматически станут доступны для вашего представления, и вы сможете обращаться к ним как к любым другим данным Blade-шаблонах:
<div>
Price: {{ $orderPrice }}
</div>
Вложения
добавлено в 5.3 ()
Для добавления к письму вложений используйте метод PHPattach()
в методе PHPbuild()
отправляемого класса. Метод PHPattach()
принимает первым аргументом полный путь к файлу:
/**
* Создание сообщения.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attach('/path/to/file');
}
При добавлении файлов можно указать их MIME-тип и/или отображаемое имя, передав массив вторым аргументом метода PHPattach()
:
добавлено в 5.3 ()
/**
* Создание сообщения.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attach('/path/to/file', [
'as' => 'name.pdf',
'mime' => 'application/pdf',
]);
}
добавлено в 5.2 () 5.1 () 5.0 ()
$message->attach($pathToFile, ['as' => $display, 'mime' => $mime]);
добавлено в 5.3 ()
Метод PHPattachData()
можно использовать для добавления «сырой» строки байтов в качестве вложения. Например, вы можете использовать этот метод, если вы сгенерировали PDF в памяти и хотите прикрепить его к письму, не записывая на диск. Метод PHPattachData()
принимает «сырые» данные первым аргументом, имя файла вторым аргументом, и массив параметров третьим аргументом:
/**
* Создание сообщения.
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attachData($this->pdf, 'name.pdf', [
'mime' => 'application/pdf',
]);
}
добавлено в 5.2 ()
Метод PHPattachData()
можно использовать для добавления «сырой» строки байтов в качестве вложения. Например, вы можете использовать этот метод, если вы сгенерировали PDF в памяти и хотите прикрепить его к письму, не записывая на диск:
$message->attachData($pdf, 'invoice.pdf');
$message->attachData($pdf, 'invoice.pdf', ['mime' => $mime]);
Строчные вложения
Обычно добавление строчных вложений — утомительное занятие, однако Laravel делает его проще, позволяя вам добавлять изображения и получать соответствующие CID.
Строчные вложения — файлы, не видимые получателю в списке вложений, но используемые внутри HTML-тела сообщения; CID — уникальный идентификатор внутри данного сообщения, используемый вместо URL в таких атрибутах, как src — прим. пер.
Для вставки строчного изображения используйте метод PHPembed()
на переменной PHP$message
в шаблоне вашего email. Laravel автоматически делает переменную PHP$message
доступной для всех шаблонов ваших сообщений, поэтому вам не надо передавать их вручную:
добавлено в 5.3 ()
<body>
Вот какая-то картинка:
<img src="{{ $message->embed($pathToFile) }}">
</body>
добавлено в 5.2 () 5.1 () 5.0 ()
<body>
Вот какая-то картинка:
<img src="<?php echo $message->embed($pathToFile); ?>">
</body>
Вставка файла из потока данных
Если у вас уже есть строка сырых данных для вставки в шаблон email-сообщения, вы можете использовать метод PHPembedData()
на переменной PHP$message
:
добавлено в 5.3 ()
<body>
А вот картинка, полученная из строки с данными:
<img src="{{ $message->embedData($data, $name) }}">
</body>
добавлено в 5.2 () 5.1 () 5.0 ()
<body>
А вот картинка, полученная из строки с данными:
<img src="<?php echo $message->embedData($data, $name); ?>">
</body>
Отправка почты
добавлено в 5.3 ()
Для отправки сообщений используйте метод PHPto()
фасада Mail. Метод PHPto()
принимает email-адрес, экземпляр пользователя или коллекцию пользователей. Если вы передадите объект или коллекцию объектов, то обработчик почты автоматически использует их свойства email и name для настройки получателей email-сообщения, поэтому эти атрибуты должны быть доступны в ваших объектах. После настройки получателей вы можете передать экземпляр вашего отправляемого класса в метод PHPsend()
:
<?php
namespace App\Http\Controllers;
use App\Order;
use App\Mail\OrderShipped;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Http\Controllers\Controller;
class OrderController extends Controller
{
/**
* Доставка данного заказа.
*
* @param Request $request
* @param int $orderId
* @return Response
*/
public function ship(Request $request, $orderId)
{
$order = Order::findOrFail($orderId);
// Доставка заказа...
Mail::to($request->user())->send(new OrderShipped($order));
}
}
Само собой при отправке сообщений вы можете указать не только получателей to. Вы можете задать получателей to, cc и bcc одним сцепленным вызовом метода:
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->send(new OrderShipped($order));
добавлено в 5.2 () 5.1 () 5.0 ()
Laravel позволяет хранить почтовые сообщения в представлениях. Например, вы можете расположить свои сообщения в папке emails, создав её в папке resources/views.
Для отправки сообщения используется метод PHPsend()
фасада Mail. Этот метод принимает три аргумента. Первый — имя представления, которое содержит текст сообщения. Второй — массив данных, передаваемых в представление. Третий — функция-замыкание, получающая экземпляр сообщения, и позволяющая вам настроить различные параметры сообщения, такие как получатели, тема и т.д.:
<?php
namespace App\Http\Controllers;
use Mail;
use App\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Отправка пользователю напоминания по e-mail.
*
* @param Request $request
* @param int $id
* @return Response
*/
public function sendEmailReminder(Request $request, $id)
{
$user = User::findOrFail($id);
Mail::send('emails.reminder', ['user' => $user], function ($m) use ($user) {
$m->from('hello@app.com', 'Your Application');
$m->to($user->email, $user->name)->subject('Your Reminder!');
});
}
}
Поскольку в этом примере мы передаём массив с ключом user, мы можем отобразить имя пользователя в нашем представлении с помощью такого PHP-кода:
<?php echo $user->name; ?>
Переменная PHP$message
всегда передаётся в представления и позволяет вам прикреплять вложения. Поэтому вам не стоит передавать одноимённую переменную с данными для представления.
Как уже было сказано, третий аргумент метода PHPsend()
— замыкание, которое позволяет указать различные настройки для самого сообщения. С помощью этого замыкания вы можете задать другие атрибуты сообщения, такие как явная рассылка на несколько адресов, скрытая рассылка на несколько адресов, и т.д.:
Mail::send('emails.welcome', $data, function ($message) {
$message->from('us@example.com', 'Laravel');
$message->to('foo@example.com')->cc('bar@example.com');
});
Ниже приведён список доступных методов для экземпляра построителя сообщения PHP$message
:
$message->from($address, $name = null);
$message->sender($address, $name = null);
$message->to($address, $name = null);
$message->cc($address, $name = null);
$message->bcc($address, $name = null);
$message->replyTo($address, $name = null);
$message->subject($subject);
$message->priority($level);
$message->attach($pathToFile, array $options = []);
// Прикрепить файл из сырой $data string...
$message->attachData($data, $name, array $options = []);
// Получить низкоуровневый экземпляр сообщения SwiftMailer...
$message->getSwiftMessage();
Экземпляр сообщения, передаваемый замыканию метода PHPMail::send()
, наследует класс сообщения SwiftMailer, что позволяет вам вызывать любые методы этого класса для создания своего сообщения.
По умолчанию ожидается, что передаваемое в метод PHPsend()
представление содержит HTML. Но передавая первым аргументом метода PHPsend()
массив, вы можете указать простое текстовое представление вдобавок к HTML-представлению:
Mail::send(['html.view', 'text.view'], $data, $callback);
А если вам надо отправить только простой текст, вы можете указать это при помощи ключа text в массиве:
Mail::send(['text' => 'view'], $data, $callback);
Если вам надо отправить непосредственно простую строку, используйте метод PHPraw()
:
Mail::raw('Text to e-mail', function ($message) {
//
});
Очереди отправки
Помещение сообщения в очередь отправки
Из-за того, что отправка сообщений может сильно повлиять на время обработки запроса, многие разработчики помещают их в очередь на фоновую отправку. Laravel позволяет легко делать это, используя единое API очередей. Для помещения сообщения в очередь просто используйте метод PHPqueue()
фасада Mail после настройки получателей сообщения:
добавлено в 5.3 ()
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->queue(new OrderShipped($order));
добавлено в 5.2 () 5.1 () 5.0 ()
Mail::queue('emails.welcome', $data, function ($message) {
//
});
Этот метод автоматически позаботится о помещении задачи в очередь, поэтому сообщение будет отправлено в фоне. Не забудьте настроить механизм очередей перед использованием данной возможности.
Вы можете задержать отправку сообщения на нужное число секунд методом PHPlater()
. Первый аргумент метода — экземпляр DateTime, указывающий, когда необходимо отправить сообщение:
добавлено в 5.3 ()
$when = Carbon\Carbon::now()->addMinutes(10);
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->later($when, new OrderShipped($order));
добавлено в 5.2 () 5.1 () 5.0 ()
Mail::later(5, 'emails.welcome', $data, function ($message) {
//
});
Помещение сообщения в определённую очередь
добавлено в 5.3 ()
Поскольку все генерируемые командой shmake:mail
отправляемые классы используют типаж Illuminate\Bus\Queueable, вы можете вызывать методы PHPonQueue()
и PHPonConnection()
на любом экземпляре отправляемого класса, что позволяет вам указывать название подключения и имя очереди для сообщения:
$message = (new OrderShipped($order))
->onConnection('sqs')
->onQueue('emails');
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->queue($message);
Помещение в очередь по умолчанию
Если у вас есть отправляемые классы, которые необходимо всегда помещать в очередь, вы можете реализовать контракт ShouldQueue в классе. Тогда даже при вызове метода PHPsend()
отправляемый объект будет помещаться в очередь, поскольку он реализует контракт ShouldQueue:
use Illuminate\Contracts\Queue\ShouldQueue;
class OrderShipped extends Mailable implements ShouldQueue
{
//
}
Почта и локальная разработка
На стадии разработки приложения обычно предпочтительно отключить доставку отправляемых сообщений. В Laravel есть несколько способов «отключить» реальную отправку почтовых сообщений во время разработки.
Вместо отправки сообщений почтовый драйвер log будет заносить все сообщения в ваши журналы для возможности их просмотра. Подробнее о настройке различных окружений для приложения читайте в документации по настройке.
добавлено в 5.0 ()
Другой вариант — задать универсального получателя для всех сообщений от фреймворка. при этом все сообщения, генерируемые вашим приложением, будут отсылаться на заданный адрес, вместо адреса, указанного при отправке сообщения. Это можно сделать с помощью параметра to в файле настроек config/mail.php:
'to' => [
'address' => 'example@example.com',
'name' => 'Example'
],
И наконец, вы можете использовать сервис MailTrap и драйвер smtp для отправки ваших почтовых сообщений на фиктивный почтовый ящик, где вы сможете посмотреть их при помощи настоящего почтового клиента. Преимущество этого вариант в том, что вы можете проверить то, как в итоге будут выглядеть ваши почтовые сообщения, при помощи средства для просмотра сообщений Mailtrap.
События
Laravel генерирует событие непосредственно перед отправкой почтовых сообщений. Учтите, это событие возникает при отправке сообщения, а не при помещении его в очередь. Вы можете зарегистрировать слушатель для этого события в своём EventServiceProvider:
/**
* Отображения слушателя событий для приложения.
*
* @var array
*/
protected $listen = [
'Illuminate\Mail\Events\MessageSending' => [
'App\Listeners\LogSentMessage',
],
];
Laravel генерирует событие mailer.sending непосредственно перед отправкой почтовых сообщений. Учтите, это событие возникает при отправке сообщения, а не при помещении его в очередь. Вы можете зарегистрировать слушатель события в своём EventServiceProvider:
/**
* Регистрация всех остальных событий для вашего приложения.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
$events->listen('mailer.sending', function ($message) {
//
});
}
Комментарии (8)
Здравствуйте ! У меня один небольшой вопрос. Можно ли средствами Laravel 5 отправить e-mail с помощью сервиса Mandrill, при этом используя шаблоны сервиса Mandrill, а не шаблоны blade?
Буду очень благодарен за помощь.
Блин так и не понял ничего... как это все работает((
Заробрались ? Подскажите порядок действий ?
Какой момент именно вам не понятен?
поддерживаю комментатора выше
Смотрел видосы по установке Auth — стандартный компонент регистрации , делал так как и они , но письма не отправляются , кроме писем при сбросе пароля. Грешил на сервак почтовый , но письма при сбросе приходят , а при регистрации нет . Подскажите как решили , по пунктам , можно видео или статьью записать .
Вылезла ошибка при использование сервиса Mailgun. cURL error 60: SSL certificate problem: unable to get local issuer certificate. Где мне отключить проверку на сертификацию?
Здравствуйте.
Только вникаю в Laravel, не судите строго.
Данные из формы добавляются в БД (на этом этапе все без проблем) далее подключается модель отправки почты и появляется ошибка "Too few arguments to function App\Mail\Question::__construct()", вроде скопировал все с документации, но все равно вылазят ошибки.
Вот тут весь алгоритм отправки письма: https://pastebin.com/1iARkmzL
Подскажите, что я делаю не так?