Zend Framework → Отправка писем в спул
Под отправкой писем в спул, я подразумеваю именно стратегию, когда реальная отправка письма происходит в фоновом процессе, а не в том, который отправку письма инициализировал. Поясню на примере данного блога. Некто отправляет комментарий, отвечая на комментарий другого пользователя. Этим действием запускается механизм, который отправляет письмо мне, т.е. хозяину блога, о том, что кто-то что-то написал. Дальше отправляется письмо тому, на чей комментарий ответили. Ну и, допустим, что письма о комментарии отправляются всем, кто подписался на комментарии к конкретному топику блога. Так вот зачем нашему некто ожидать, пока всем письма отправятся? В случае же массовых рассылок, когда адресатов сотни и тысячи, по другому и нельзя, по моему.
Решением данной ситуации и будет отправка писем в спул, т.е. помещение их в некую очередь, откуда они будут извлекаться фоновым скриптом, и рассылаться адресатам.
Не смотря на то, что запись эта относится к категории Zend Framework, я использовал стороннюю библиотеку, Swiftmailer, которую можно взять с официального сайта. Конечно, и в зенде существуют компоненты, позволяющие решить данную задачу без посторонней помощи, это Zend_Mail и Zend_Queue, но почему бы не воспользоваться готовым решением, отлаженным и без явных ошибок?
Для начала создаём метод, отправляющий письма в спул.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php
public function sendEmailToSpool($recipientEmail, $recipientName, $subject, $mailBody)
{
//подключаем swift mailer
$pathToSwiftmailer = realpath(APPLICATION_PATH . '/../path/to/swift_required.php');
require_once($pathToSwiftmailer);
$message = Swift_Message::newInstance();
$message->setFrom('from@example.org')
->setContentType('text/html');
//создаём транспорт для спула
$spoolPath = realpath(APPLICATION_PATH . '/../path/to/spool');
$spool = new Swift_FileSpool($spoolPath);
$emailValidator = new My_EmailValidator();
if ($emailValidator->isValid($recipientEmail)) {
$message->setSubject($subject)
->setTo(array($recipientEmail => $recipientName))
->setBody($mailBody);
//отправляем сообщение в очередь
$spool->queueMessage($message);
}
}
|
В коде можно встретить нестандартный валидатор для писем. Появление его обусловлено тем, что не все письма, валидные по мнению Zend_Validate_EmailAddress, являются валидными для свифт-мейлера. Отправка таких неоднозначных емейлов приводит к возникновению исключений, которые нам не нужны. Ниже код валидатора, где опять скрещиваются зенд и свифт-мейлер.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?php
class My_EmailValidator extends Zend_Validate_EmailAddress
{
public function isValid($value)
{
if (parent::isValid($value)) {
$pathToSwiftmailer = realpath(APPLICATION_PATH . '/../path/to/swift_required.php');
require_once($pathToSwiftmailer);
$swiftGrammarObject = new Swift_Mime_Grammar();
$addressDefinition = $swiftGrammarObject->getDefinition('addr-spec');
if (!preg_match('/^' . $addressDefinition . '$/D', $value)) {
$this->_error(self::INVALID);
return false;
}
return true;
} else {
$this->_error(self::INVALID);
return false;
}
}
}
|
Ну и последнее. Пишем cron-скрипт, который и будет отправлять письма. В качестве транспорта выбран SMTP, но это не принципиально, может быть любой другой. Параметры для SMTP будут подтягиваться из файла application.ini, чтобы можно было менять их централизованно.
1 2 3 4 5 6 7 8 9 10 | //application.ini
[production]
//прочие параметры
mail_smtp.host = "smtp.host"
mail_smtp.port = "25"
mail_smtp.username = "noreply@example.com"
mail_smtp.password = "0000"
mail_smtp.from = "noreply@example.com"
|
Ну и сам скрипт. Учтите, что пути к файлам и папкам могут быть и другие.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <?php
//подключаем пути к библиотекам
set_include_path(implode(PATH_SEPARATOR, array(
realpath(dirname(__FILE__) . '/../library'),
get_include_path(),
)));
//извлекаем конфигурацию SMTP
require_once(realpath(dirname(__FILE__) . '/../library/Zend/Config/Ini.php'));
$configObject = new Zend_Config_Ini(realpath(dirname(__FILE__) . '/../path/to/application.ini'),
'production');
$optionsArray = $configObject->mail_smtp->toArray();
$pathToSwiftmailer = realpath(dirname(__FILE__) . '/../path/to/swift_required.php');
require_once($pathToSwiftmailer);
//создаём спул
$spoolPath = realpath(dirname(__FILE__) . '/../path/to/spool');
$spool = new Swift_FileSpool($spoolPath);
$spool->setMessageLimit(20);
$spool->setTimeLimit(30);
//создаём SMTP-transport
$transport = Swift_SmtpTransport::newInstance();
$transport->setHost($optionsArray['host'])
->setPort($optionsArray['port'])
->setUsername($optionsArray['username'])
->setPassword($optionsArray['password']);
$spool->flushQueue($transport);
|
Вот, собственно, и всё.
Комментарии