Zend Framework → Отправка писем в спул
Под отправкой писем в спул, я подразумеваю именно стратегию, когда реальная отправка письма происходит в фоновом процессе, а не в том, который отправку письма инициализировал. Поясню на примере данного блога. Некто отправляет комментарий, отвечая на комментарий другого пользователя. Этим действием запускается механизм, который отправляет письмо мне, т.е. хозяину блога, о том, что кто-то что-то написал. Дальше отправляется письмо тому, на чей комментарий ответили. Ну и, допустим, что письма о комментарии отправляются всем, кто подписался на комментарии к конкретному топику блога. Так вот зачем нашему некто ожидать, пока всем письма отправятся? В случае же массовых рассылок, когда адресатов сотни и тысячи, по другому и нельзя, по моему.
Решением данной ситуации и будет отправка писем в спул, т.е. помещение их в некую очередь, откуда они будут извлекаться фоновым скриптом, и рассылаться адресатам.
Не смотря на то, что запись эта относится к категории Zend Framework, я использовал стороннюю библиотеку, Swiftmailer, которую можно взять с официального сайта. Конечно, и в зенде существуют компоненты, позволяющие решить данную задачу без посторонней помощи, это Zend_Mail и Zend_Queue, но почему бы не воспользоваться готовым решением, отлаженным и без явных ошибок?
Для начала создаём метод, отправляющий письма в спул.
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, являются валидными для свифт-мейлера. Отправка таких неоднозначных емейлов приводит к возникновению исключений, которые нам не нужны. Ниже код валидатора, где опять скрещиваются зенд и свифт-мейлер.
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, чтобы можно было менять их централизованно.
//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"
Ну и сам скрипт. Учтите, что пути к файлам и папкам могут быть и другие.
//подключаем пути к библиотекам 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);
Вот, собственно, и всё.
Адрес электронной почты нигде не отображается, необходим только для обратной связи.
Веб-сайт вводите в формате http://example.org, при желании, конечно.