Yii2. Отправка почты
14.08.2019
Теги: Web-разработка • Yii2 • Форма • Фреймворк
Для отправки почты Yii2 предлагает расширение swiftmailer
, которое нужно просто настроить. Настраивается оно в файле config/web.php
. Вот настройки класса swiftmailer
по умолчанию:
$config = [ /*...*/, 'components' => [ /*...*/ 'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', // send all mails to a file by default. You have to set // 'useFileTransport' to false and configure a transport // for the mailer to send real emails. 'useFileTransport' => true, ], /*...*/ ], /*...*/ ];
Обратите внимание на настройку useFileTransport
: когда она имеет значение true
— письмо не отправляется реально, его отправка просто эмулируется. Файл письма при этом будет сохранен в папку runtime/mail
.
Тестирование отправки почты
Давайте протестируем отправку почты. Для этого создадим форму обратной связи, которая будет доступна на адресу /site/feedback
.
<?php namespace app\controllers; use Yii; use app\models\Feedback; use yii\web\Controller; class SiteController extends Controller { /*...*/ public function actionFeedback() { $model = new Feedback(); /* * Если пришли post-данные, загружаем их в модель... */ if ($model->load(Yii::$app->request->post())) { // ...и проверяем эти данные if ( ! $model->validate()) { /* * Данные не прошли валидацию */ Yii::$app->session->setFlash( 'feedback-success', false ); // сохраняем в сессии введенные пользователем данные Yii::$app->session->setFlash( 'feedback-data', [ 'name' => $model->name, 'email' => $model->email, 'body' => $model->body ] ); /* * Сохраняем в сессии массив сообщений об ошибках. Массив имеет вид * [ * 'name' => [ * 'Поле «Ваше имя» обязательно для заполнения', * ], * 'email' => [ * 'Поле «Ваш email» обязательно для заполнения', * 'Поле «Ваш email» должно быть адресом почты' * ] * ] */ Yii::$app->session->setFlash( 'feedback-errors', $model->getErrors() ); } else { /* * Данные прошли валидацию */ // отправляем письмо на почту администратора $textBody = 'Имя: ' . strip_tags($model->name) . PHP_EOL; $textBody .= 'Почта: ' . strip_tags($model->email) . PHP_EOL . PHP_EOL; $textBody .= 'Сообщение: ' . PHP_EOL . strip_tags($model->body); $htmlBody = '<p><b>Имя</b>: ' . strip_tags($model->name) . '</p>'; $htmlBody .= '<p><b>Почта</b>: ' . strip_tags($model->email) . '</p>'; $htmlBody .= '<p><b>Сообщение</b>:</p>'; $htmlBody .= '<p>' . nl2br(strip_tags($model->body)) . '</p>'; Yii::$app->mailer->compose() ->setFrom(Yii::$app->params['senderEmail']) ->setTo(Yii::$app->params['adminEmail']) ->setSubject('Заполнена форма обратной связи') ->setTextBody($textBody) ->setHtmlBody($htmlBody) ->send(); // данные прошли валидацию, отмечаем этот факт Yii::$app->session->setFlash( 'feedback-success', true ); } // выполняем редирект, чтобы избежать повторной отправки формы return $this->refresh(); } return $this->render('feedback', ['model' => $model]); } /*...*/ }
<?php namespace app\models; use yii\base\Model; class Feedback extends Model { public $name; public $email; public $body; public function attributeLabels() { return [ 'name' => 'Ваше имя', 'email' => 'Ваш e-mail', 'body' => 'Ваше сообщение', ]; } public function rules() { return [ // удалить пробелы для всех трех полей формы [['name', 'email', 'body'], 'trim'], // поле name обязательно для заполнения ['name', 'required', 'message' => 'Поле «Ваше имя» обязательно для заполнения'], // поле email обязательно для заполнения ['email', 'required', 'message' => 'Поле «Ваш email» обязательно для заполнения'], // поле email должно быть корректным адресом почты ['email', 'email', 'message' => 'Поле «Ваш email» должно быть адресом почты'], // поле body обязательно для заполнения ['body', 'required', 'message' => 'Поле «Сообщение» обязательно для заполнения'], // поля name и email должны быть не более 50 символов [ ['name', 'email'], 'string', 'max' => 50, 'tooLong' => 'Поле должно быть длиной не более 50 символов' ], // поле body должно быть не более 1000 символов [ 'body', 'string', 'max' => 1000, 'tooLong' => 'Сообщение должно быть длиной не более 1000 символов' ], ]; } }
<?php use yii\helpers\Html; use yii\bootstrap\ActiveForm; $this->title = 'Обратная связь'; /* * Если данные формы не прошли валидацию, получаем из сессии сохраненные * данные, чтобы заполнить ими поля формы, не заставляя пользователя * заполнять форму повторно */ $name = ''; $email = ''; $body = ''; if (Yii::$app->session->hasFlash('feedback-data')) { $data = Yii::$app->session->getFlash('feedback-data'); $name = Html::encode($data['name']); $email = Html::encode($data['email']); $body = Html::encode($data['body']); } ?> <div class="container"> <?php $success = false; if (Yii::$app->session->hasFlash('feedback-success')) { $success = Yii::$app->session->getFlash('feedback-success'); } ?> <div id="response"> <?php if (!$success): ?> <?php if (Yii::$app->session->hasFlash('feedback-errors')): ?> <div class="alert alert-warning alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Закрыть"> <span aria-hidden="true">×</span> </button> <p>При заполнении формы допущены ошибки</p> <?php $allErrors = Yii::$app->session->getFlash('feedback-errors'); ?> <ul> <?php foreach ($allErrors as $errors): ?> <?php foreach ($errors as $error): ?> <li><?= $error; ?></li> <?php endforeach; ?> <?php endforeach; ?> </ul> </div> <?php endif; ?> <?php else: ?> <div class="alert alert-success alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Закрыть"> <span aria-hidden="true">×</span> </button> <p>Ваше сообщение успешно отправлено</p> </div> <?php endif; ?> </div> <?php $form = ActiveForm::begin(['id' => 'feedback', 'class' => 'form-horizontal']); ?> <?= $form->field($model, 'name')->textInput(['value' => $name]); ?> <?= $form->field($model, 'email')->input('email', ['value' => $email]); ?> <?= $form->field($model, 'body')->textarea(['rows' => 5, 'value' => $body]); ?> <div class="form-group"> <?= Html::submitButton('Отправить', ['class' => 'btn btn-primary']) ?> </div> <?php ActiveForm::end(); ?> </div>
Адрес почты отправителя и получателя мы берем из настроек приложения config/params.php
:
<?php return [ 'adminEmail' => 'admin@example.com', 'senderEmail' => 'noreply@example.com', 'senderName' => 'Example.com mailer', ];
Файл письма в директории runtime/mail
:
Message-ID: <3bcd3bb26e670ca057eaafb376d365d9@www.example.com> Date: Wed, 14 Aug 2019 11:57:03 +0300 Subject: =?utf-8?Q?=D0=97=D0=B0=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5=D0=BD?= =?utf-8?Q?=D0=B0_=D1=84=D0=BE=D1=80=D0=BC=D0=B0_=D0=BE=D0=B1=D1=80=D0=B0?= =?utf-8?Q?=D1=82=D0=BD=D0=BE=D0=B9_=D1=81=D0=B2=D1=8F=D0=B7=D0=B8?= From: noreply@example.com To: admin@example.com MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="_=_swift_1565773023_5daac4bcd4b10c645568b6655a1eb78a_=_" --_=_swift_1565773023_5daac4bcd4b10c645568b6655a1eb78a_=_ Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable =D0=98=D0=BC=D1=8F: =D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9 =D0=9F=D0=BE=D1=87=D1=82=D0=B0: ivanov@mail.ru =D0=A1=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B5:=20 =D0=9A=D0=B0=D0=BA=D0=BE=D0=B5-=D1=82=D0=BE =D1=81=D0=BE=D0=BE=D0=B1=D1= =89=D0=B5=D0=BD=D0=B8=D0=B5 --_=_swift_1565773023_5daac4bcd4b10c645568b6655a1eb78a_=_ Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable <p><b>=D0=98=D0=BC=D1=8F</b>: =D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9</p= ><p><b>=D0=9F=D0=BE=D1=87=D1=82=D0=B0</b>: ivanov@mail.ru</p><p><b>= =D0=A1=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B5</b>:</p><p>=D0=9A= =D0=B0=D0=BA=D0=BE=D0=B5-=D1=82=D0=BE =D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0= =B5=D0=BD=D0=B8=D0=B5</p> --_=_swift_1565773023_5daac4bcd4b10c645568b6655a1eb78a_=_--
Шаблоны для писем
Способ отправки, который мы рассмотрели выше, подходит для небольших писем. Но если планируется отправить большое письмо, удобнее использовать view-шаблоны, размещенные в директории mail
. Давайте создадим в этой директории файл feedback.php
:
<?php use yii\helpers\Html; ?> <p><strong>Имя</strong>: <?= Html::encode($name); ?></p> <p><strong>Email</strong>: <?= Html::encode($email); ?></p> <p><strong>Сообщение</strong>:</p> <p><?= nl2br(Html::encode($body)); ?></p>
А отправлять почту мы теперь будем так:
$mail = Yii::$app->mailer->compose( 'feedback', [ 'name' => strip_tags($model->name), 'email' => strip_tags($model->email), 'body' => strip_tags($model->body) ] ); $mail->setFrom(Yii::$app->params['senderEmail']) ->setTo(Yii::$app->params['adminEmail']) ->setSubject('Заполнена форма обратной связи') ->send();
Наш view-шаблон можно обернуть layout-шаблоном, который расположен в файле mail/layouts/html.php
:
<?php use yii\helpers\Html; /* @var $this \yii\web\View view component instance */ /* @var $message \yii\mail\MessageInterface the message being composed */ /* @var $content string main view render result */ ?> <?php $this->beginPage() ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=<?= Yii::$app->charset ?>" /> <title><?= Html::encode($this->title) ?></title> <?php $this->head() ?> </head> <body> <?php $this->beginBody() ?> <?= $content ?> <?php $this->endBody() ?> </body> </html> <?php $this->endPage() ?>
Для этого указываем в конфигурации путь к layout-шаблону:
$config = [ /*...*/, 'components' => [ /*...*/ 'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', 'htmlLayout' => 'layouts/html', 'useFileTransport' => true, ], /*...*/ ], /*...*/ ];
И в view-шаблоне задаем title
:
<?php use yii\helpers\Html; $this->title = 'Заполнена форма обратной связи'; ?> <p><strong>Имя</strong>: <?= Html::encode($name); ?></p> <p><strong>Email</strong>: <?= Html::encode($email); ?></p> <p><strong>Сообщение</strong>:</p> <p><?= nl2br(Html::encode($body)); ?></p>
В итоге получим такое письмо:
Message-ID: <28000ba51fa0db3459bc8e51f8fab757@www.example.com> Date: Thu, 15 Aug 2019 09:11:49 +0300 Subject: =?utf-8?Q?=D0=97=D0=B0=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5=D0=BD?= =?utf-8?Q?=D0=B0_=D1=84=D0=BE=D1=80=D0=BC=D0=B0_=D0=BE=D0=B1=D1=80=D0=B0?= =?utf-8?Q?=D1=82=D0=BD=D0=BE=D0=B9_=D1=81=D0=B2=D1=8F=D0=B7=D0=B8?= From: noreply@example.com To: admin@example.com MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="_=_swift_1565849509_f5996ab5ab87f6be9c0a48cd7b75f89f_=_" --_=_swift_1565849509_f5996ab5ab87f6be9c0a48cd7b75f89f_=_ Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable =D0=98=D0=BC=D1=8F: =D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9 Email: ivanov@mail.ru =D0=A1=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B5: =D0=9A=D0=B0=D0=BA=D0=BE=D0=B5-=D1=82=D0=BE =D1=81=D0=BE=D0=BE=D0=B1=D1= =89=D0=B5=D0=BD=D0=B8=D0=B5 --_=_swift_1565849509_f5996ab5ab87f6be9c0a48cd7b75f89f_=_ Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org= /TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns=3D"http://www.w3.org/1999/= xhtml"> <head> <meta http-equiv=3D"Content-Type" content=3D"text/ht= ml; charset=3DUTF-8" /> <title>=D0=97=D0=B0=D0=BF=D0=BE=D0=BB=D0= =BD=D0=B5=D0=BD=D0=B0 =D1=84=D0=BE=D1=80=D0=BC=D0=B0 =D0=BE=D0=B1=D1=80= =D0=B0=D1=82=D0=BD=D0=BE=D0=B9 =D1=81=D0=B2=D1=8F=D0=B7=D0=B8</title> = </head> <body> <p><strong>=D0=98=D0=BC=D1=8F</strong>: =D0= =95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9</p> <p><strong>Email</strong>: ivanov@mail.ru</p> <p><strong>=D0=A1=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B5</strong>:= </p> <p>=D0=9A=D0=B0=D0=BA=D0=BE=D0=B5-=D1=82=D0=BE =D1=81=D0=BE=D0=BE=D0=B1= =D1=89=D0=B5=D0=BD=D0=B8=D0=B5</p> </body> </html> --_=_swift_1565849509_f5996ab5ab87f6be9c0a48cd7b75f89f_=_--
Если не устраивает layout-шаблон, который предлагается по умолчанию, можно создать свой и указать это в настройках:
$config = [ /*...*/, 'components' => [ /*...*/ 'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', 'viewPath' => '@app/mail', 'htmlLayout' => 'layouts/main-html', 'textLayout' => 'layouts/main-text', 'messageConfig' => [ 'charset' => 'UTF-8', 'from' => ['noreply@site.com' => 'Site Name'], ], 'useFileTransport' => true, ], /*...*/ ], /*...*/ ];
В этой конфигурации:
viewPath
— путь к шаблонам писемhtmlLayout
иtextLayout
— html и text макеты писемcharset
— кодировка писем по умолчаниюfrom
— адрес почты и имя отправителя по умолчанию
Реальная отправка почты
Вроде все прошло успешно, можно отправлять письма по-настоящему. Редактируем файл config/web.php
:
$config = [ /*...*/, 'components' => [ /*...*/ 'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', 'htmlLayout' => 'layouts/html', 'useFileTransport' => false, 'transport' => [ 'class' => 'Swift_SmtpTransport', 'host' => 'smtp.mail.ru', 'username' => 'имя_пользователя@mail.ru', 'password' => 'пароль_от_почты', 'port' => '465', 'encryption' => 'ssl', ], ], /*...*/ ], /*...*/ ];
И вносим изменения в файл config/params.php
:
return [ 'adminEmail' => 'реальный_адрес_получателя@mail.ru', // должен совпадать с имя_пользователя@mail.ru 'senderEmail' => 'реальный_адрес_отправителя@mail.ru', 'senderName' => 'Example.com mailer', ];
From:
должно совпадать с именем почтового ящика, в котором была осуществлена SMTP-авторизация: если в настройках почтовой программы указан почтовый ящик ivanov@mail.ru
, то именно это имя почтового ящика должно указываться в поле From:
.
Дополнительно
- Магазин на Yii2, часть 21. Оформление заказа, часть вторая
- Магазин на Yii2, часть 20. Оформление заказа, часть первая
- Магазин на Yii2, часть 17. Корзина покупателя, часть первая
- Yii2. Валидация формы. Часть 2
- Yii2. Валидация формы. Часть 1
- Yii2. Метки полей формы
- Блог на Laravel 7, часть 13. Загрузка и ресайз изображений для категорий и постов блога
Поиск: Web-разработка • Yii2 • Форма • Фреймворк • Почта • Swiftmailer • Обратная связь • Feedback