Посмотрев, как ловко принтер в офисе отправляет письма от кого угодно куда угодно, решил реализовать простой отправитель писем. Из подручных инструментов оказались Yii 2 фреймворк со встроенным в него модулем swiftmailer, виртуальная Ubuntu на VirtualBox (можно и без нее, если установить php и web-сервер локально).

Итак, начнем.

Устанавливаем basic приложение Yii 2 в папку сервера. После получения следующей картинки можно двигаться дальше:



Далее необходимо изменить конфигурационный файл приложения /config/web.php. Параметр 'useFileTransport' изначально выставлен в true, для целей отлова ошибок. При таком значении письма в файловом формате попадают в папку /runtime/mail. Там можно проверить основные заголовки письма и убедиться в правильности настроек.

Для корректной отправки необходимо использовать в качестве транспорта действующий почтовый сервис. Вот пример конфигурации для почты gmail.com:

//config/web.php
'mail' => [
        'class' => 'yii\swiftmailer\Mailer',
        'useFileTransport' => false,
        'transport' => [
            'class' => 'Swift_SmtpTransport',
            'host' => 'smtp.gmail.com',
            'username' => 'username@gmail.com',
            'password' => 'password',
            'port' => '587',
            'encryption' => 'tls',
            ],
    ],

Для отправки внутри корпоративной среды можно использовать как имя сервера, так и его IP адрес. В моем случае имеется корпоративная среда, построенная на базе продуктов Microsoft. Ее и рассматриваю в качестве примера. Если у Exchange сервера не настроена обязательная проверка пользователя, то можно совершенно ничего не указывать в полях 'username' и 'password'. Однако нет гарантии, что отправленное письмо не попадет в папку «Спам» у получателя.

'mailer' => [
            'class' => 'yii\swiftmailer\Mailer',
            'useFileTransport' => false,
            'transport' => [
            'class' => 'Swift_SmtpTransport',
            'host' => 'exchange.example.com', //вставляем имя или адрес почтового сервера
            'username' => '', 
            'password' => '',
            'port' => '25',
            'encryption' => '',
            ],
],

Чтобы письмо не отфильтровалось антиспамом, нужно ввести доменные имя пользователя и пароль для авторизации на сервере Exchange.

Далее создадим модель MailerForm.php в папке /models:

MailerForm.php
//models/MailerForm.php

<?php

namespace app\models;

use Yii;
use yii\base\Model;

class MailerForm extends Model
{
    public $fromEmail;
    public $fromName;
    public $toEmail;
    public $subject;
    public $body;

    public function rules()
    {
        return [
            [['fromEmail', 'fromName', 'toEmail', 'subject', 'body'], 'required'],
            ['fromEmail', 'email'],
            ['toEmail', 'email']
        ];
    }

    public function sendEmail()
    {
        if ($this->validate()) {
            Yii::$app->mailer->compose()
                ->setTo($this->toEmail)
                ->setFrom([$this->fromEmail => $this->fromName])
                ->setSubject($this->subject)
                ->setTextBody($this->body)
                ->send();

            return true;
        }
        return false;
    }
}


Сделаем представление mailer.php для формы в папке /views/site/:

mailer.php
//views/site/mailer.php

<?php

/* @var $this yii\web\View */
/* @var $form yii\bootstrap\ActiveForm */
/* @var $model app\models\MailerForm */

use yii\helpers\Html;
use yii\bootstrap\ActiveForm;

$this->title = 'Mailer';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="site-contact">
    <h1><?= Html::encode($this->title) ?></h1>

    <?php if (Yii::$app->session->hasFlash('mailerFormSubmitted')) : ?>

        <div class="alert alert-success">
            Your email has been sent
        </div>

    <?php else : ?>

        <p>
            This form for sending email from anywhere to anywhere
        </p>

        <div class="row">
            <div class="col-lg-5">

                <?php $form = ActiveForm::begin(['id' => 'mailer-form']); ?>

                    <?= $form->field($model, 'fromName') ?>

                    <?= $form->field($model, 'fromEmail') ?>

                    <?= $form->field($model, 'toEmail') ?>

                    <?= $form->field($model, 'subject') ?>

                    <?= $form->field($model, 'body')->textArea(['rows' => 6]) ?>

                    <div class="form-group">
                        <?= Html::submitButton('Submit', ['class' => 'btn btn-primary', 'name' => 'contact-button']) ?>
                    </div>

                <?php ActiveForm::end(); ?>

            </div>
        </div>
    <?php endif; ?>
</div>


Далее необходимо добавить действие в контроллере /controllers/SiteController.php. В самом начале сайта нужно не забыть добавить use app\models\MailerForm для подключения пространства имен модели MailerForm. А в самом классе добавить метод actionMailer().

<?php

namespace app\controllers;

use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\filters\VerbFilter;
use app\models\LoginForm;
use app\models\ContactForm;
use app\models\MailerForm; //добавляемая строка

class SiteController extends Controller
{
//…существующий код…
public function actionMailer()
    {
        $model = new MailerForm();
        if ($model->load(Yii::$app->request->post()) && $model->sendEmail()) {
            Yii::$app->session->setFlash('mailerFormSubmitted');
            return $this->refresh();
        }
          return $this->render('mailer', [
              'model' => $model,
          ]);
    }
//…существующий код…
}

После этих манипуляций пройдя по ссылке index.php?r=site/mailer можно попасть на форму отправки почты.



Последним штрихом добавим пункт меню для удобства пользования. В файле /views/layouts/main.php в находим следующий блок:

echo Nav::widget([
        'options' => ['class' => 'navbar-nav navbar-right'],
        'items' => [
            ['label' => 'Home', 'url' => ['/site/index']],
            ['label' => 'About', 'url' => ['/site/about']],
            ['label' => 'Contact', 'url' => ['/site/contact']],

И добавляем строчку:

['label' => 'Mailer', 'url' => ['/site/mailer']],

Все, готово!

P.S.: Ни в коем случае не злоупотребляйте подложными письмами с поддельными отправителями. И не рассылайте спам.

Если лень все делать руками, можно просто клонировать проект из https://github.com/danvop/mailer. Там же инструкция по разворачиванию.

Комментарии (12)


  1. Igogo2012
    28.03.2016 11:58
    +2

    Ну этот пост точно не для хабра…
    А еще в репе не хранят папки runtime и web/assets, лучше удалите их, в них yii ложит свои логи и кэш


    1. EnChikiben
      28.03.2016 12:02
      +2

      папки такие хранят, но с gitignore потому как yii сам их создать не сможет


    1. danvop
      28.03.2016 12:14

      Этот пост может быть полезен. Больше нечего добавить


      1. istui
        28.03.2016 12:37
        +1

        Статья «как бы не для хабра», но вот я как раз начал изучать yii и материалы именно этой статьи полезны. И похожие ситуации часто возникают.

        Несколько недель назад на хабре разворачивались дискусии на тему «почему хабр уже не торт». Было высказано много предложений по улучшению Хабра. Так почему бы не ввести еще хаб/атрибут статьи EntryLevel?

        Я сейчас говорю не про конкретную публикацию, а ситуацию в целом. Статьи EntryLevel не должны содержать откровенного бреда «возьмем ардуино и датчик температуры и сделаем градусник на C# через COM-порт». Это должны быть нормально подготовленные, новые уроки, но рассчитанные на малый порог вхождения в какой-то узкой области. Те, кто ее знают хорошо (либо вообще по умолчанию все), могут скрыть такие статьи.


        1. istui
          28.03.2016 12:41
          +2

          отвечая сразу на возможный вопрос "почему именно на Хабре" — т.к. здесь сильное и грамотное коммьюнити. Откровенный бред сразу заминусуют, в то же время качественные (но несложные материалы) предложат, как улучшить.


        1. Mendel
          28.03.2016 12:53

          Слишком мало. Слишком.
          Если бы человек используя Gii написал свой ЗдравствуйМир на пяток CRUD-контроллеров и сделал бы некую визитку со статьями, категориями, ЧАВО, прайсом и формой обратной связи — то при всей ЗдравствуйМировости такой статьи я думаю она получила бы кучу плюсов, просто потому что показывала бы хоть какой-то набор действий, последовательность мысли и т.п.
          А так это повтор нескольких строчек документации (качественной документации) на задаче не имеющей практического значения.
          Зачем? К чему? Чтобы повторить этот ЗдравствуйМир нужно иметь уже минимальные знания по фреймворку. Хоть бегло прочить документацию. А всё что есть в статье в документации уже есть.....


          1. istui
            28.03.2016 12:56
            +1

            вот я как раз такой контент и имею в виду.
            а автору — хочу сказать спасибо все равно и пожелание быстрее расти)


    1. zenn
      28.03.2016 12:14
      +1

      А еще насколько я помню по принципам best practice вызов validate() модели при работе с формами лучше выполнять из контроллера, а не метода модели. Т.е. вот это:

      if ($model->load(Yii::$app->request->post()) && $model->sendEmail()) {
                  Yii::$app->session->setFlash('mailerFormSubmitted');
                  return $this->refresh();
       }

      нужно привести к виду:
      if ($model->load(Yii::$app->request->post()) && $model->validate()) {
                  $model->sendEmail();
                  Yii::$app->session->setFlash('mailerFormSubmitted');
                  return $this->refresh();
       }

      ну и соответственно убрать ->validate из метода модели и бессмысленные ретурны :)
      П.с. — да, статья вовсе не для хабра, в 2008 или ранее возможно бы и было полезно, но такого рода материалов уже не счесть итак.


      1. danvop
        28.03.2016 12:19

        спасибо за совет.


  1. Mendel
    28.03.2016 12:47
    +5

    ЗдравствуйМир он такой ЗдравствуйМир)
    В принципе основную функцию он выполнил — человек из песочницы вышел, инвайт получил.
    Надеюсь автор подтянет свой уровень до уровня хабра и оправдает тот кредит доверия который ему дало НЛО.
    Все когда-то начинали со своего ЗдравствуйМир.


  1. XanderBass
    28.03.2016 22:05
    +2

    Скрипт отправки почты на Yii 2 *оглушительный фейспалм* дожили, ёлы-палы.


  1. nepster09
    30.03.2016 10:51
    +1

    Только еще один момент, отправка email может занимать достаточно долгое времени в некоторых ситуациях. Лучше бы это дело отправлять в фоне (или в очереди). Но далеко не все разработчики Yii2 знают про существование очередей или командной шины.