Yii2 отправка писем через gmail.
  • 1317

Yii2 отправка писем через SMTP сервер gmail.

Автор: admin | 08 декабря (Сб.) 2018г. в 22ч.30м.

В этом уроке рассмотрим как в yii2 реализовать отправку писем на email пользователя с помощью бесплатного SMTP-сервера от google. На многих сайтах при регистрации отправляется письмо на почтовый ящик, который был указан пользователем в форме регистрации для подтверждения регистрации пользователя с помощью перехода по ссылке. Создадим такой же функционал подтверждения регистрации пользователя на сайте. Для отправки почты нужно настроить компонент mailer в конфигурационном файле yii2. Для отправки писем нужен SMTP-сервер. Будем использовать сервер от google. Как его настроить можно почитать в доках от google
'components' => [
        'mailer' => [
            'class' => 'yii\swiftmailer\Mailer',
            'viewPath' => '@common/mail',
            // 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' => false,
            'transport' => [
                    'class' => 'Swift_SmtpTransport',
                    'host' => 'smtp.gmail.com',
                    'username' => 'this_admim_mail@gmail.com',
                    'password' => '12345677654321',
                    'port' => '587',
                    'encryption' => 'tls',
                    'streamOptions' => [ 'ssl' => [ 'allow_self_signed' => true, 'verify_peer' => false, 'verify_peer_name' => false, ], ]
                            ],

        ],​

Следует обратить внимание на свойство streamOptions  . Данное свойство содержит настройки, которые необходимы для отправки почты без проверки ssl сертификата. Иначе может вылететь ошибка такого плана: PHP Fatal error: Uncaught exception 'Swift_TransportException' with message 'Unable to connect with TLS encryption' . А с данными параметрами отправка работает и на локальной машине.

Следующим шагом создадим LoginController в котором опишем actionSignup()

<?php

namespace frontend\controllers;

use Yii;
use yii\helpers\Url;
use yii\helpers\Html;
use yii\web\Controller;
use common\models\LoginForm;
use frontend\models\PasswordResetRequestForm;
use frontend\models\ResetPasswordForm;
use frontend\models\SignupForm;
use frontend\models\ConfirmEmailForm;//модель подтверждения регистрации по ссылке с email

use yii\filters\AccessControl;
use yii\filters\VerbFilter;

class LoginController extends Base
{

    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'only' => ['logout', 'signup'],
                'rules' => [
                    [
                        'actions' => ['signup'],
                        'allow' => true,
                        'roles' => ['?'],
                    ],
                    [
                        'actions' => ['logout'],
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
//                    'logout' => ['post'],
                ],
            ],
        ];
    }

    //Добавляем капчу
    public function actions()
    {
        return [
            'captcha' => [
                'class' => 'yii\captcha\CaptchaAction',
                'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
                'maxLength' => 5,
            ],
        ];
    }

    //регистрация на сайте
    public function actionSignup()
    {
        $model = new SignupForm();
        if ($model->load(Yii::$app->request->post())) {
            if ($user = $model->signup()) {
                $mes = "На Ваш email отправлено письмо с кодом подтверждения регистрации .
                        Пожалуйста, проверте Вашу почту <b>".$model->email."</b> - найдите наше
                        письмо со ссылкой для подтверждения и кликните по ней .    ";
                Yii::$app->getSession()->setFlash('send_email', $mes);
                return $this->render('empty');
            }
        }

        return $this->render('signup', [
            'model' => $model,
        ]);
    }

    //подтверждение регистации по ссылке ,пришедшей с Email и присвоение роли user
    public function actionConfirmEmail($token)
    {
        try {
            $model = new ConfirmEmailForm($token);
        } catch (InvalidParamException $e) {
            throw new BadRequestHttpException($e->getMessage());
        }

        if ($model->confirmEmail()) {
            Yii::$app->getSession()->setFlash('successConfirmEmail', 'Спасибо! Ваш Email успешно подтверждён и Вы прошли регистрацию .Теперь можете войти под своим логином на сайт ');
            return Yii::$app->getResponse()->redirect('login');
        } else {
            Yii::$app->getSession()->setFlash('error', 'Ошибка подтверждения Email.');
            return $this->goHome();
        }
    }

//Далее другие методы
}​

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

Далее в views у нас размещается форма регистрации такого вида:
<?php
//ФОРМА РЕГИСТРАЦИИ ПОЛЬЗОВАТЕЛЕЙ
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\captcha\Captcha;


/* @var $this yii\web\View */
/* @var $form yii\bootstrap\ActiveForm */
/* @var $model \frontend\models\SignupForm */
$this->title = 'Регистрация';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="site-signup">
    <h1><?= Html::encode($this->title) ?></h1>
    <p class="center">Заполните все поля для регистрации :</p>
    <div class="row">

            <?php $form = ActiveForm::begin([
                'id' => 'form-signup',
                'options' => ['class' => 'form-horizontal col-sm-offset-4 col-xs-offset-3 col-sm-4 col-xs-6'],
                                            ]); ?>
            <?= $form->field($model, 'username') ?>
                <?= $form->field($model, 'email') ?>
                <?= $form->field($model, 'password')->passwordInput() ?>
                <?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
                'captchaAction' => 'login/captcha',
                'template' => '<div><p>{image}</p><p>{input}</p></div>',
            ]) ?>
            <div class="form-group">
            <?= Html::submitButton('Signup', ['class' => 'btn btn-primary', 'name' => 'signup-button']) ?>
            </div>
<?php ActiveForm::end(); ?>

    </div>
</div>​
Как видите это самая обычная форма регистрации. В данной форме есть поле email ,в которое новый пользователь будет заполнять свой email, на который будет отправляться письмо с подтверждением регистрации в котором будет ссылка для подтверждения подлинности email.
Теперь опишем модель SignupForm ,которая связана с эформой регистрации и экшеном:
<?php
namespace frontend\models;

use yii\base\Model;
use common\models\User;
use Yii;

/**
 * Signup form
 */
class SignupForm extends Model
{
    public $username;
    public $email;
    public $password;
    public $verifyCode;

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            ['username', 'filter', 'filter' => 'trim'],
            ['username', 'required'],
            ['username', 'match', 'pattern' => '#^[\w_-]+$#i'],
            ['username', 'unique', 'targetClass' => User::className(), 'message' => 'This username has already been taken.'],
            ['username', 'string', 'min' => 2, 'max' => 255],

            ['email', 'filter', 'filter' => 'trim'],
            ['email', 'required'],
            ['email', 'email'],
            ['email', 'unique', 'targetClass' => User::className(), 'message' => 'This email address has already been taken.'],

            ['password', 'required'],
            ['password', 'string', 'min' => 6],

            ['verifyCode', 'captcha', 'captchaAction' => 'login/captcha'],
        ];
    }

    /**
     * @return array customized attribute labels
     */
    public function attributeLabels()
    {
        return [
            'verifyCode' => 'Код для проверки',
        ];
    }
    /**
     * Signs user up.
     *
     * @return User|null the saved model or null if saving fails
     */
    public function signup()
    {
        if ($this->validate()) {
            $user = new User();
            $user->username = $this->username;
            $user->email = $this->email;
            $user->setPassword($this->password);
            $user->role = 'user';//из перечня групп в app\commands\RbacController
            $user->status = User::STATUS_WAIT;
            $user->generateAuthKey();
            $user->generateEmailConfirmToken();//генерация случайной строки для подтверждения по почте

            if ($user->save()) {
                //отправка письма с подтверждением регистрации пользователя по уникальному токену
                Yii::$app->mailer->useFileTransport = false;
                Yii::$app->mailer->compose('SignupEmailToken', ['user' => $user])
                    ->setFrom([Yii::$app->params['adminEmail'] => Yii::$app->name])//параметр $app->params['supportEmail'] из папки конфиг - файла params
                    ->setTo($this->email)
                    ->setSubject(Yii::$app->name . ': подтверждение регистрации ')
                    ->send();
            }

            return $user;
        }

        return null;
    }
}
​

Тут особое внимание нужно обратить на метод signup() ,который обробатывает регистрацию и отправляет email на почту пользователя, указанную при регистрации. Для оформления письма я использовал шаблон вида, с использованием html разметки, чтобы наше письмо было выглядело красиво ). Данный шаблон расположен в common/mail/SignupEmailToken.php Именно этот файл и указан в 

Yii::$app->mailer->compose('SignupEmailToken', ['user' => $user])

В файл SignupEmailToken.php можно передавать параметры. В данном примере это ['user' => $user]
Как видно из кода нам не нужно указывать полный путь к файлу видов для оформления письма. Это так потому, что мы указали путь к папке видов в конфигурации приложения в common/main.php в свойстве viewPath:

'components' => [
        'mailer' => [
            'class' => 'yii\swiftmailer\Mailer',
            'viewPath' => '@common/mail',

Вот сам файл SignupEmailToken.php

<?php
use yii\helpers\Html;
 //ШАБЛОН письма, отправляемого при регистрации на почту юзера - подтверждения почты через уникальный токен
/* @var $this yii\web\View */
/* @var $user app\modules\user\models\User */

$SignupTokenLink = Yii::$app->urlManager->createAbsoluteUrl(['confirm-email', 'token' => $user->email_confirm_token]);
?>

Здравствуйте, <?= Html::encode($user->username) ?>!

Для подтверждения адреса пройдите по ссылке:

<?= Html::a(Html::encode($SignupTokenLink), $SignupTokenLink) ?>

Если Вы не регистрировались на нашем сайте, то просто удалите это письмо.

Так же, как и для файлов видов в frontend/views/ для представлений почты есть свои файлы шаблонов layouts. Шаблон расположен по layouts/html внутри папки mail.

Вот такая получается структура в папке @common/mail

-mail
       -layouts
                  -html.php
       SignupEmailToken.php

В данном случае шаблон находится в файле 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() ?>​

Тело письма выводится в шаблоне как обычно в данной строке <?= $content ?>

Ну и конечно не забываем указать в роутах правило:
//вход ,регистрация ,восстан. пароля, замена пароля
'<action:(login|logout|signup|confirm-email|request-password-reset|reset-password)>' => 'login/<action>',​
Теперь все готово и можно протестировать форму регистрации.

P.S.

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

Ну а для того, чтобы подробнее узнать что такое SMTP-сервер посмотрите этот коротенький ролик.

Приветствую!

Меня зовут Сергей. Я - автор этого блога.

Если Вам был полезен материал на моем сайте, поддержите пожалуйста мой проект, чтобы о нем узнали другие люди - кликните plizz :) на иконку в соц. сети, чтобы поделиться материалом с другими.