Почта

Содержание:


Введение

Laravel предосталвяет простой и понятный API для популярной библиотеку SwiftMailer с драйверами для SMTP, Mailgun, Postmark, Amazon SES и sendmail. Это позволяет вам начать отправлять почту на локальной версии или сервисе основанным на облаке, на ваш выбор.

Требования к драйверу

Основанные на API драйверы, такие как Mailgun или Postmark часто проще и быстрее чем сервера SMTP. Если возможно, вам стоит использовать один из этих драйверов. Все API драйверы требуют библиотеку HTTP Guzzle, которая может быть установлена через Composer:

composer require guzzlehttp/guzzle

Драйвер Mailgun

Чтобы использовать драйвер Mailgun, нужно сначала установить Guzzle, после чего установить значение опции driver в файле конфигурации config/mail.php на mailgun. Следующим шагом необходимо убедиться в том, что ваш файл конфигурации config/services.php содержит следующие строки:

'mailgun' => [
    'domain' => 'your-mailgun-domain',
    'secret' => 'your-mailgun-key',
],

Если вы не используете "US" регион Mailgun, вы можете определить ваш регион в файле конфигурации services:

'mailgun' => [
    'domain' => 'your-mailgun-domain',
    'secret' => 'your-mailgun-key',
    'endpoint' => 'api.eu.mailgun.net',
],

Драйвер Postmark

Чтобы использовать драйвер Postmark, установить SwiftMailer для Postmark через Composer:

composer require wildbit/swiftmailer-postmark

После чего необходимо установить Guzzle и прописать опцию driver как postmark в вашем файле конфигурации config/mail.php. Наконец, необходимо провести сверку в вашем файле конфиграции config/services.php на предмет наличия следующих строк:

'postmark' => [
    'token' => 'your-postmark-token',
],

Драйвер SES

Чтобы использовать драйвер Amazon SES понадобится установить AWS SDK для PHP. Вы можете установить эту библиотеку путём добавления следующих строк для файла composer.json секции require и запустить команду composer update:

"aws/aws-sdk-php": "~3.0"

После, установите опцию driver в вашем файле конфигурации config/mail.php в значение ses и проведите проверку наличия следующих строк в файле config/services.php:

'ses' => [
    'key' => 'your-ses-key',
    'secret' => 'your-ses-secret',
    'region' => 'ses-region',  // e.g. us-east-1
],

Если вам необходимо включить дополнительные опции, при выполнении запроса SES SendRawEmail, вы можете определить массив options внутри вашей конфигурации ses:

'ses' => [
    'key' => 'your-ses-key',
    'secret' => 'your-ses-secret',
    'region' => 'ses-region',  // e.g. us-east-1
    'options' => [
        'ConfigurationSetName' => 'MyConfigurationSet',
        'Tags' => [
            [
                'Name' => 'foo',
                'Value' => 'bar',
            ],
        ],
    ],
],

Генерация почты

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

php artisan make:mail OrderShipped

Написание почты

Вся конфигурация класса mailable уже реализована в методе build. Внутри этого метода вы можете вызывать различные методы такие как from, subject, view, и attach, чтобы настроить вид письма и другие данные отправки такие как от, тема.

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

Использование метода from

Во-первых, давайте настроим отправителя письма. Или какой адрес в письме будет отображаться для поля "from". Существует 2 способа настроить отправителя. Во-первых, вы можете использовать метод from внутри класса mailable метода build:

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    return $this->from('example@example.com')
                ->view('emails.orders.shipped');
}

Использование глобального адреса from

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

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

In addition, you may define a global "reply_to" address within your config/mail.php configuration file:

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

Настройка вида

Внутри метода build класса mailable, вы можете использовать метод view для указания шаблона, который необходимо использовать при генерации содержимого письма. В силу того, что каждое электронное письмо использует шаблонизатор Blade для отображения контента, вы можете использовать всю мощь шаблонизатора Blade при составлениии электронных писем:

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    return $this->view('emails.orders.shipped');
}
Вы можете создать директорию resources/views/emails для хранения всех ваших шаблонов писем. Можно располагать и в любой другой папке внутри директории resources/views.

Обычные текстовые письма

Если вы хотите определить обычную версию вашего электронного письма, вы можете использовать метод text. Как и в случае с методом view, метод text принимает метод шаблона, который будет использован для отображения контента электронного письма. Вы можете определить как HTML версию письма, так и текстовую версию сообщения:

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    return $this->view('emails.orders.shipped')
                ->text('emails.orders.shipped_plain');
}

Отображение данных

Через публичные свойства

Обычно, вы хотите передать некоторые данные в ваше представлеине, которые вы можете использовать при рендеринге HTML электронного письма. Есть два способа сделать данные доступными для представления. Во-первых, любые публичные свойства, определённые в вашем классе mailable, будут автоматически доступны для вашего представления. Поэтому, например, вы можете передать данные в конструктор почтового класса и установить данные как общедоступные свойства, определённые на классе:

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

    /**
     * The order instance.
     *
     * @var Order
     */
    public $order;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->view('emails.orders.shipped');
    }
}

После добавления данных в публичные свойства, они атоматически будут доступны для вашего представления, поэтому вы сможете обратиться к ним также, как и к любым другим данным в шаблоне Blade:

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

Через метод with:

Если вы хотите настроить данные электронного письма до момента их отправки в шаблон, вы можете вручную передать ваше данные в представление через метод with. Обыкновенно, вы все равно будете передавать данные через конструктор. Однако, для данных установлены свойства protected или private, таким образом данные не доступны для шаблона автоматически. Поэтому, необходимо передавать данные в виде массива через вызов метод with:

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

    /**
     * The order instance.
     *
     * @var Order
     */
    protected $order;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->view('emails.orders.shipped')
                    ->with([
                        'orderName' => $this->order->name,
                        'orderPrice' => $this->order->price,
                    ]);
    }
}

После того, как данные были прикреплены через метод with, вы можете использовать их также, как и любые другие данные в вашем Blade шаблоне:

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

Прикреплённые фалы

Чтобы добавить вложения к письму, используйте метод attach внутри метода build почтового класса. Метод attach принимает полный путь до файла в качестве первого аргумента:

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    return $this->view('emails.orders.shipped')
                ->attach('/path/to/file');
}

Прикрепляя файл к сообщению, вы можете также указать отображаемое имя и / или MIME тип путём передачи массива в качестве второго аргумента в метод attach:

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    return $this->view('emails.orders.shipped')
                ->attach('/path/to/file', [
                    'as' => 'name.pdf',
                    'mime' => 'application/pdf',
                ]);
}

Прикрепление файлов из диска

Если вы храните файл на одном из ваших дисков, вы можте прикрепить их к электронному письму используя метод attachFromStorage:

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
   return $this->view('email.orders.shipped')
               ->attachFromStorage('/path/to/file');
}

Если необходимо, вы можете указать имя для прикрепляемого файла и дополнительные опции используя второй и третий аргумент для метода attachFromStorage:

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
   return $this->view('email.orders.shipped')
               ->attachFromStorage('/path/to/file', 'name.pdf', [
                   'mime' => 'application/pdf'
               ]);
}

Метод attachFromStorageDisk можно использовать в случае, когда необходимо указать диск хранения, который отличается от диска по умолчанию:

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
   return $this->view('email.orders.shipped')
               ->attachFromStorageDisk('s3', '/path/to/file');
}

Прикрепление необработанных данных

Метод attachData может быть использован для того, чтобы прикрепить набор данных в качестве вложения. Например, вы можете использовать этот метод, если вы хотите сгенерировать файл PDF в памяти и хотите вложить этот файл в письмо без сохранения на диск. Метод attachData принимает набор данных в качестве первого аргумента, название в качестве второго аргумента и массив опций как третий аргумент:

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    return $this->view('emails.orders.shipped')
                ->attachData($this->pdf, 'name.pdf', [
                    'mime' => 'application/pdf',
                ]);
}

Вписанные файлы

Вложение изображений в ваши электронные письма обычно может быть обременительным. Ларавел предоставляет удобный способ присоединить изображения в ваши электронные письма и получить соответсвующий CID. Чтобы добавить изображение используйте метод embed для переменной $message внутри вашего шаблона письма. Ларавел автоматически делает переменную $message доступной для всех ваших шаблонов писем, поэтому у вас нет необходимости беспокоится о том, чтобы передавать переменную вручную:

<body>
    Here is an image:

    <img src="{{ $message->embed($pathToImage) }}">
</body>
Переменная $message не доступна для текстовых сообщений в силу того, что сами вложения не доступны для таких вложений.

Вписать необработанные данные во вложения

Если у вас есть данные, которые вы хотели бы вписать в шаблон электронного письма, вы можете использовать метод embedData для переменной $message:

<body>
    Here is an image from raw data:

    <img src="{{ $message->embedData($data, $name) }}">
</body>

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

Метод withSwiftMessage для класса Mailable позволяет вам регистрировать обратную связь, которая будет вызвана с необработанных экземпляром сообщения SwiftMailer до момента отправки сообщения. Это даёт вам возможность настроить сообщение до того, как оно будет доставлено:

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    $this->view('emails.orders.shipped');

    $this->withSwiftMessage(function ($message) {
        $message->getHeaders()
                ->addTextHeader('Custom-Header', 'HeaderValue');
    });
}

Шаблоны писем

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

Генерация шаблонов писем

Чтобы сгенерировать шаблон с разметкой Markdown, вы можете использовать опцию --markdown для команды Artisan make:mail:

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

После, при настройке писем внутри метода build, вызывайте метод markdown вместео метода view. Метод markdown принимает имя шаблона Markdown и опционально массив данных для доступа в шаблон:

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    return $this->from('example@example.com', 'Example')
                ->markdown('emails.orders.shipped');
}

Написаине шаблона письма

Шаблоны используют комбинацию компонентов Blade и синтакс Markdown, который позволяет вам легко строить сообщения при использовании готовых компонентов Laravel:

@component('mail::message')
                    # Order Shipped

                    Your order has been shipped!

                    @component('mail::button', ['url' => $url])
                        View Order
                    @endcomponent

                    Thanks,<br>
                    {{ config('app.name') }}
                @endcomponent
Не используйте лишние отступы при написании писем с Markdown, потому что парсер выведет содержимое с отступами как блоки кода.

Компонент Button

Компонент Button отображает центрированную ссылку в виде кнопки. Компонент принимает два аргумента: url и дополнительный color. Есть ряд поддерживаемых цветов: primary, success, и error. Вы можете добавить так много кнопок в сообщение как считаете нужным:

@component('mail::button', ['url' => $url, 'color' => 'success'])
                    View Order
                @endcomponent

Компонент Panel

Компонент отображает данный блок текста в панели, у которой немного отличается цвет фона от остального сообщения. Это позволяет вам обратить внимание на данный блок текста:

@component('mail::panel')
                    This is the panel content.
                @endcomponent

Компонент Table

Компонент позволяет вам трансформировать таблицу Markdown в обыкновенную HTML таблицу. Компонент принимает таблицу в качестве содержимого. Поддерживается различное центрирование в колонках при помощи синтаксиса Markdown для таблиц:

@component('mail::table')
                    | Laravel       | Table         | Example  |
                    | ------------- |:-------------:| --------:|
                    | Col 2 is      | Centered      | $10      |
                    | Col 3 is      | Right-Aligned | $20      |
                @endcomponent

Настрока компонентов

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

Если вы хотите построить построить полностью новую тему для компонентов Laravel Markdown, вы можете разместить файл CSS внутри директории html/themes. После того, как вы назвали и сохранили файл CSS, обновите опцию theme файла конфигурации mail таким образом, чтобы оно соответсвовало названию вашей новой темы.

Для настройки темы для индивидуального сообщения, вы можете установить свойство $theme класса mailable как имя темы, которая будет использована при отправке сообщения.


Отправка почты

Для отправки сообщения, используйте метод to для фасада Mail. Метод to принимает адрес электронной почты, экземпляр пользователя или коллекцию пользователей. Если вы передадите объект или коллекцию объектов, почтовик автоматически использует их свойтсва email и name при установке получателей электронной почты. Поэтому, убедитесь в том, что эти атрибуды доступны для ваших объектов. После того, как вы указали получателей, вы можете передать экзепляр класса почты в метод send:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Mail\OrderShipped;
use App\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;

class OrderController extends Controller
{
    /**
     * Ship the given order.
     *
     * @param  Request  $request
     * @param  int  $orderId
     * @return Response
     */
    public function ship(Request $request, $orderId)
    {
        $order = Order::findOrFail($orderId);

        // Ship order...

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

Вы не ограничены тем, чтобы просто указывать получателей "to" при отправке сообщения. Вы можете указывать получателей "to", "cc", и "bcc" внутри одного одиночного замкнутого вызова метода:

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

Очереди писем

Постановка в очередь сообщений

В силу того, что отправка большого числа сообщений может существенным образом увеличить время ответа вашего приложения, много разработчкиов выбирают постановку сообщений в очередь для фоновой отправки. Ларавел позволяет сделать это легко используя встроенное унифицированне API для очередей. Чтобы добавить сообщение почты, используйте метод queue для фасада Mail после указания получателей сообщений:

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

Этот метод автоматически добавляет пункт в очередь, таким образом сообщение отправляется фоном. Вам потребуется настроить ваши очереди до использования этой особенности.

Отложенна очередь сообщений

Если вы хотите отложить доставку сообщения из очереди, вы можете использовать метод later. В качестве первого аргумента, метод later принимает экземпляр DateTime, который показывает когда сообщение должно отправляться:

$when = now()->addMinutes(10);

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

Проталкивание к определённым очередям

В силу того, что все почтовые классы сгенерированные с использованием команды make:mail используют трейт Illuminate\Bus\Queueable, вы можете применить методы onQueue и onConnection к любому почтовому класса. Они позволяют вам указать соединение и имя очереди для сообщения:

$message = (new OrderShipped($order))
                ->onConnection('sqs')
                ->onQueue('emails');

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->queue($message);

Постановка в очередь по умолчанию

Если у вас есть почтовые классы, которые вы бы хотели видеть всегда в очереди, вы можете расширить контракт ShouldQueue классам. Теперь , даже если вы вызываете метод send при работе, то сообщение все равно будет добавляться в очередь в силу расширения контракта, а не отправляться напрямую:

use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Mailable implements ShouldQueue
{
    //
}

Генерация писем

Иногда вы можете захотеть получить HTML контент письма без его отправки. Чтобы справится с этим, вы можете вызвать метод render. Этот метод вернёт конечный контент письма в качестве строки:

$invoice = App\Invoice::find(1);

return (new App\Mail\InvoicePaid($invoice))->render();

Предпросмотр письма в браузере

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

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

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

Локализация почты

Ларавел позволяет вам отправлять сообщения на различных языках, в том числе отличных от текущего. Даже запомнит указанный язык, если письмо добавлено в очередь.

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

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

Избранные локали пользователя

Иногда, приложения хранят выбранные локали для каждого пользователя. Путём расширения контракта HasLocalePreference одной или более вашей модели, вы можете научить Ларавел использовать сохранённые локали при отправке письма:

use Illuminate\Contracts\Translation\HasLocalePreference;

class User extends Model implements HasLocalePreference
{
    /**
     * Get the user's preferred locale.
     *
     * @return string
     */
    public function preferredLocale()
    {
        return $this->locale;
    }
}

После вашего расширения интрефейса, Ларавел будет автоматически использовать выбранную локаль при отправке писем и уведомлений в модель. Поэтому, больше нет необходимости вызывать метод locale при использовании интерфейса:

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

Почта и локальная разработка

При разработке приложений, которые должны отправлять письма, вам и не нужно отправлять сообщения на реальный почтовый ящик. Ларавел предлагает несколько путей для отмены фактической отправки писем во время локальной разработки.

Лог-драйвер

Вместо отправки сообщений, драйвер почты log будет записывать все ваши сообщения в ваши лог-файлы для инспектирования. Для большей информации о таком окружении для приложения проверьте документацию конфигурации.

Универсальное поле "кому"

Другое решение включенное в Ларавел — это установить универсального получателя писем фреймворка. В этом случае, все письма сгенерированные приложением будут отправлять на указанный адрес, вместо адреса, указанного при отправке сообщение. Так можно сделать через опцию to в файле конфигурации config/mail.php:

'to' => [
    'address' => 'example@example.com',
    'name' => 'Example'
],

Mailtrap

Наконец, вы можете использовать сервис, такой как Mailtrap и драйвер smtp для отправки электронных сообщений на виртуальный почтовый ящик, где вы можете просмотерть их в реальном почтовом клиенте. Такой подход предоставляет возможность инспектировать конечные письма через клиент Mailtrap.


События

Ларавел запускает два события в процессе отправки сообщений почты. Событие MessageSending запускается до момента отправки сообщения, в то время как событие MessageSent будет запущено после отправки сообщения. Нужно запомнить, эти события запускаются при запускаются при отправке sent сообщений, а не при добавления в очередь. Вы можете зараегистрировать слушателя события для этого события в вашем EventServiceProvider:

/**
 * The event listener mappings for the application.
 *
 * @var array
 */
protected $listen = [
    'Illuminate\Mail\Events\MessageSending' => [
        'App\Listeners\LogSendingMessage',
    ],
    'Illuminate\Mail\Events\MessageSent' => [
        'App\Listeners\LogSentMessage',
    ],
];