Практически ни одно веб-приложение не обходится без отправки электронной почты. А это значит, что нужно как-то протестировать данную функцию приложения. В этой заметке я хочу показать как это можно сделать.
Некоторое время назад мне потребовалось протестировать генерацию писем нашим приложением. Проведя небольшое исследование, решил что можно пойти двумя путями:
- установить почтовый прокси и настроить приложение (или php) на отправку почты через него
- использовать специальный почтовый транспорт.
Фактически, первый вариант может удовлетворить в большинстве случаев. Но чтобы им воспользоваться, нужно вмешиваться в операционную систему — устанавливать скрипты или приложения, вносить изменения в php.ini. Часто это не представляет проблемы, но не всегда.
Я же решил воспользоваться вторым вариантом, т.к. сделать это оказалось достаточно просто.
В Zend Framework есть специальный компонент, отвечающий за рассылку почты — Zend_Mail. Этот компонент предоставляет единый интерфейс для различных почтовых транспортов (таких как php-функция mail или прямое соединение с smtp-сервером). Написать собственный транспорт не составляет большого труда, что, собственно, я и сделал.
Пример использования почтового транспорта
Для того, чтобы проверить содержимое генерируемых нашим приложением писем, я написал небольшой почтовый транспорт. Код транспорта можете посмотреть и скачать с github-а, а далее я покажу как им можно воспользоваться. Но перед этим я хочу остановиться на возможностях этого транспорта:
- работа в двух режимах:
- имя файла дампа постоянно при отправке нескольких писем
- имя файла генерируется для каждого письма индивидуально
- возможность сохранения данных как с перезаписью, так и с дописыванием в конец существующего файла
- письма сохраняются в файлы формата *.eml, что позволяет посмотреть их в почтовом клиенте
- возможность использовать собственную функцию для генерации имени файла письма
А теперь вернемся к использованию транспорта.
Чтобы указать Zend_Mail каким образом следует отправлять почту, следует передать экземпляр нужного транспорта в метод отправки почты (см. документацию).
Во-первых, указываем автолоадеру пространство имен:
# application/config/application.in
autoloaderNamespaces[] = "bpLib_"
Во-вторых, перед вызовом метода send Zend_Mail-а создадим экземпляр файлового транспорта:
$transport = new bpLib_Mail_Transport_File(
'/tmp',
bpLib_Mail_Transport_File::MODE_REGULAR
);
Конструктор файлового транспорта принимает 3 параметра:
- путь к каталогу, в который будут сохраняться письма
- режим работы (имена постоянные/меняющиеся; дозапись/перезапись)
- имя callback-функции
По первому параметру, я думаю, все ясно, поясню остальные. Режим работы задается маской — в нулевом бите режим формирования имен файлов, в первом режим записи в файл. Таким образом существует три варианта:
- bpLib_Mail_Transport_File::MODE_REGULAR — для постоянного имени файла с перезаписью содержимого файла
- bpLib_Mail_Transport_File::MODE_REGULAR | bpLib_Mail_Transport_File::MODE_APPEND — для постоянного имени файла с дополнением файла
- bpLib_Mail_Transport_File::MODE_RANDOM — для индивидуальных имен файлов у каждого письма
Четвертый вариант (индивидуальные имена с дополнением файла) хоть и возможен, но бессмыслен.
Третий параметр представляет собой название callback-функции, вызываемой для генерации имени файла. Формат параметра аналогичен функции call_user_func_array. Внутрь функции передается экземпляр транспорта. Таким образом, функция имеет доступ ко всем данным письма: заголовки, тело, вложения, что позволяет генерировать имена файлов в зависимости от содержимого письма. В качестве примера приведу метод, используемый по умолчанию:
protected function randomFilename()
{
return date('Y-m-d-H-i-s').'-'.rand(10000,99999).'.eml';;
}
Ну и наконец передаем созданный нами экземпляр транспорта в метод send:
$mail = new Zend_Mail('UTF-8');
$mail->setSubject("SUBJECT")
->addTo('recipient@mail.com')
->setFrom('from@mail.com', 'From User')
->setBodyText("some text...")
->send($transport)
;
Собственно это все, что нужно для использования.
К сожалению, нельзя подключить этот транспорт в качестве основного в файле настроек приложения, т.к. ресурс, отвечающий за почтовый компонент, ориентирован исключительно на транспорты Zend Framework-а. Но выход из положения есть! Можно в файле начальной загрузки написать метод, устанавливающий файловый транспорт в качестве транспорта по-умолчанию:
$transport = new bpLib_Mail_Transport_File(
'/tmp',
bpLib_Mail_Transport_File::MODE_REGULAR
);
Zend_Mail::setDefaultTransport($transport);
На этом я пожалуй закончу описание транспорта. Возможно в одной из следующих заметок я опишу как можно установить и настроить почтовый прокси.
До новых встреч!
Метки: config, debug, mail, php, zend framework, zend_mail, zend_mail_transport



Это не совсем так, есть еще 3ий путь — использовать любой другой почтовый сервер. Например зарегестрировать dev акк гугло почты, передать логин пароль в Zend_Mail_Transport_Smtp и... всё, можно тестировать.
Однако, я вижу приведенное тут решение весьма и весьма удобным в ряде случаев. Думаю подрихтовать и выйдет отличный пропозал. Не хочешь попробовать?
«dev акк»? Это что за аккаунт такой? Никогда не встречал. Где о нем пишут?
В принципе я согласен. Только у меня большие проблемы с написанием текстов на английском. Вот если с кем-нибудь скооперироваться, то можно было бы заняться.
Кстати, возможно лучше переименовать в ..._Debug вместо ..._File
А что именно подрихтовывать надо?
Ну образно, имееться в виду тестовый аккаунт. Берете любой бесплатный сервис почты, например gmail. Регистрируете почту.
Например разрабатываешь ты mysupersite.com, регистрируешь почту dev.mysupersite@gmail.com для всячесих изощерений, оно по идее пригодиться не только для этого.
Берешь Zend_Mail_Transport_Smtp, передаешь туда логин пароль, настройки сервера smtp (хост порт, для гугла например smtp.gmail.com, 465), всё, можно тестировать отправку почты, ничего не надо устанавливать и писать. Понятно?
Я имею в виду оформить код нормально, по аккуратнее и в соотвествии со стандартами ЗФ. В принципе это дело десятой потому что кода пару строк, главное — идея. Насчет переименовывания File в Debug пожалуй можно, думаю комьюнити выскажется по этому поводу если сделаете пропозал.
Не думаю что тут нужно много тестов, поэтому это мне и видиться привлекательным пропозалом — просто и со вкусом :) В принципе если ты согласен то я готов сделать все остальное, заполнить пропозал, исправить (совместно) все что попросят. Если у тебя есть CLA подписанный, то просто сделаем пропозал на двоих, или если нету — тогда можешь подписать и добавим тебя в список пропозеров когда ответ придет. Если не согласен, то можно скооперироваться в другом виде, предлагай. С составлением английских текстов необходимого уровня у меня проблем нет.
Да, понятно. Этот способ не шибко хорош тем, что осуществляется фактическая отправка писем, а это не всегда допустимо. Например, если тестируется функционал на реальных адресах пользователей, тогда рассылать просто недопустимо, а проверить надо.
Либо я что-то все же не понял
Да, для рассылок, когда надо проверять не как генерируюца письма, а и то как они и куда уходят, ваш транспорт как раз и пригодиться.
Кстати, мне удебнее на «ты» общаться. Был бы признателен...
Да, мне тоже, я стараюсь, но порой совершенно случайно перехожу на «вы», причем в независимости от того кому я пишу :)
Хм... я вроде старался по стандартам код писать. Ну разве что шапки phpdoc-а на зендовские заменить. Но готов остальное оформление поправить, если есть такая необходимость
Если ты про модульные тесты, то они есть (в гитхабе можешь посмотреть). Возможно они требуют доработки...
Нет, я не против. Подписанного CLA у меня нет.
Сорри, опечатка, «тексты» я имел в виду.
Окей, тогда я подготовлю пропозал базовый (возможно будет время сегодня или на выходных) и скину ссылку тебе на ознакомление и внесение правок.
Я так думаю надо уже под зф2.0 пропозал делать, надо будет это уточнить.
Ок. Буду ждать