2009-04-25 3 views
16

Я пытаюсь внедрить систему списков рассылки для своего приложения. В настоящее время я использую Zend_Mail_Transport_Smtp('localhost') как мой транспорт, просматриваю список моих подписчиков и отправляю новый Zend_Mail каждому. Тем не менее, я замечаю, что длительность времени, которое требуется для завершения сценария, увеличивается по мере увеличения количества подписчиков.Каков наилучший способ отправки электронной почты сотням получателей из приложения Zend Framework?

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

Я понимаю, что Zend_Mail не занимается почтой в очереди. Может ли кто-нибудь, кто имеет опыт работы с этим, дать мне обзор того, как это можно сделать? Я ничего не знаю о cron/crontab/cronjobs, поэтому, если это связано с этим, пожалуйста, объясните этот процесс.

ответ

19

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

  • Loop над вашим набором пользователей, создание электронной почты для каждого из них и, возможно, настройки содержимого
  • Pass каждый почтовый объект в очередь который будет откладывать отправку электронной почты до позднего времени
  • В каком-то сценарии cron отправьте содержимое очереди несколько сотен за раз. Примечание: вы захотите настроить количество отправляемых сообщений электронной почты, просмотрев журналы ошибок, возвращаемых с момента фактического процесса отправки. Если вы пытаетесь отправить слишком много, я заметил, он достигает точки, где почтовый транспорт больше не будет принимать соединения (я использую Стань)

Есть несколько библиотек, там вы можете использовать, чтобы сделайте это, PEAR Mail Queue (с Mail_Mime) и SwiftMailer позволяют создавать и размещать электронные письма в очереди. Пока Zend Mail предоставляет только создание электронных писем, а не очередей (подробнее об этом позже).

У меня есть опыт в основном с PEAR Mail Queue и есть несколько исправлений. Если вы пытаетесь разместить в очереди большое количество электронных писем (например, зацикливая более 20 000 пользователей и пытаясь получить их в очередь в разумные сроки), использование реализаций кодировки с использованием кавычек Mail Mime выполняется очень медленно. Вы можете ускорить это, переключившись на base64-кодирование.

Что касается Zend Mail, вы можете написать объект Zend Mail Transport, который помещает ваши объекты Zend Mail в очередь PEAR Mail. Я сделал это с некоторым успехом, но для его исправления требуется немного времени.Для этого увеличьте Zend Mail Transport Abstract, внедрите метод _sendMail (в котором вы поместите свой объект Zend Mail в очередь почты) и передайте экземпляр вашего транспортного объекта методу send() вашего объекта Zend Mail или по Zend Mail :: setDefaultTransport().

Суть в том, что есть много способов сделать это, но от вашего имени потребуются некоторые исследования и обучение. Однако это очень разрешимая проблема.

0

Класс Zend Mail выглядит хорошо и прост в использовании, он также позволяет отправлять простой текст и HTML-версию электронного письма, что в маркетинге электронной почты очень важно.

Если вы знакомы с работой рамы, я бы придерживался ее.

Важные вещи, которые необходимо учитывать при отправке сообщения электронной почты в больших объемах людей:

  • Может ли ваш веб-сервер справиться с запросами изображения, когда электронные письма открываются + нагрузка на сервер людей, посещающих ваш сайт.

Если ответ не является или ваш неуверенный, использование теста apache должно помочь вам в разработке, если это возможно. Если вы все еще не уверены, всегда лучше всего отправлять электронные письма (которые могут быть синхронизированы с помощью crontab) для распространения нагрузки.

Надеюсь, это поможет.

+0

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

+0

Я думаю, что Фил говорит, что вы используете cron для дросселирования отправки писем. Например, отправляйте только 100 за раз, каждые 30 минут, пока список не будет исчерпан. – grossvogel

+0

Но похоже, что он предлагает, чтобы crontab использовался в качестве решения для большого трафика? Во всяком случае, всем нам должно быть так повезло, что слишком много трафика с маркетинговой кампанией. Скорее всего, это не проблема. – rick

3

Из документации PHP.net.

Примечание: Следует отметить, что функция mail() не подходит для больших объемов электронной почты в цикле. Эта функция открывает и закрывает SMTP-сокет для каждого письма, что не очень эффективно.
Для отправки большого количества сообщений электронной почты см. Раздел «PEAR::Mail» и »PEAR::Mail_Queue.

Класс Zend Mail, вероятно, довольно хорош (большинство материалов Zend хороши). Но если вы хотите другие варианты. Вот они.

+0

PEAR :: Почта медленна в моем опыте. PHPMailer и swiftmailer превосходны. – rick

2

Вы должны быть в порядке, используя PHP, в тысячи получателей, хотя избегайте почты(), как отмечали другие. Я видел несколько систем, предназначенных для большого количества почты (100 000+ получателей), которые перешли в обход стандартных функций рассылки и пытались работать более непосредственно с MTA. Даже тогда мне было непонятно, что требовалось.

Создание электронной почты для профессионалов - это больше о том, как правильно форматировать (HTML и обычный текст, когда это возможно), люди могут легко отписаться, отскоки обрабатываются правильно, на почтовом сервере есть все необходимые DNS-записи, и сервер не нарушает правила какой-либо крупной системы черных списков. Язык, на котором вы пишете приложение, не является основным фактором в нескольких сотнях или даже нескольких тысячах сообщений.

18

ПРИМЕЧАНИЕ: когда я впервые прочитал ваш вопрос, я подумал, что он сказал сотни тысяч электронных писем сразу. Когда я дважды проверял, я заметил, что это на самом деле говорило от сотен до тысяч. Я слишком ленив, чтобы изменить свой пост сейчас, так что вот некоторые предостережения: по моему опыту, вы, вероятно, можете нормально работать без коммерческого инструмента примерно до 40K. Примерно в 10K вы захотите следить за «минимальным» списком, чтобы предотвратить большую боль, когда вы начнете достигать больших размеров списка. Я действительно рекомендую все это сразу сделать.

Я уже говорил об этом раньше, есть две стороны для отправки электронной почты:

  1. техническая сторона - в основном все из RFC, по протоколу SMTP , форматы электронной почты, DNS записей, и т. д. Это умеренно сложно, но разрешимо.
  2. Магическая сторона - доставка по электронной почте Управление вуду. Вы получите разочарованы, все пойдет на нет Понятная причина, и вы будете рассмотреть вопрос о выезде на другое задание , которое не связано с электронной почтой.

Я рекомендую не писать собственный отправитель. Я уверен, что PHP может отлично справиться, но вы, вероятно, должны провести время в другом месте. Два продукта, которые я использовал в прошлом и рекомендую, это Strongmail и PowerMTA. Будьте осторожны - у них высокая цена, но я могу почти гарантировать, что вы потратите больше средств на собственное решение в долгосрочной перспективе.

Одна область, в которую вы будете прибиты, написав свой собственный на PHP, - это дросселирование/детонация. Почтовые серверы начнут добавлять во сне (30) после того, как вы отправите несколько сообщений, чтобы замедлить работу и остановить вас от спама.

Обычно эти коммерческие массовые отправители запускают протокол SMTP для очередей. Вы продолжаете использовать Zend_Mail, но жесткий код для подключения к вашему серверу. Он будет отправлять почту в очередь так же быстро, как вы можете отправить ее, а затем использовать свой собственный движок для отправки почты в свои адресаты.

В списке 100K вам нужно будет использовать лучшие практики электронной почты. Как минимум, вам нужно:

  • SPF Records, возможно, DKIM, а
  • нескольких IP-адресов для сегментации трафика более - есть 3 IP адресов, по одному для качества адреса, которому вы доверяете, один для IP-адресов среднего риска и один для IP-адресов высокого риска. Эта конструкция помогает минимизировать риск получения почты для ваших лучших клиентов.
  • Правильный обратный DNS для отправки IP-адрес
  • Используйте петлю обратной связи от AOL, Hotmail, Yahoo и других для обработки жалобы на спаме
  • Отказаться и отказами управления - убедитесь, что вы обрезкой этих адресов
  • Возникли Отслеживание открытия/клика также важно - если вы являетесь клиентом в списке A, вы не открываете свои электронные письма, вы должны деградировать их в списке B и так далее. Это важно, потому что интернет-провайдеры превратят неактивные аккаунты в honeypot. Hotmail известен этим.

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

+0

Вы знаете свои вещи. К сожалению, ваш ответ огромен. Как использовать Strongmail или PowerMTA с Zend Mail и покрыть все перечисленные вами пулевые баллы? – rick

+0

Вы можете связать свое приложение с помощью Strongmail, когда я говорю о приложении, которое я имею в виду при хранении данных, это означает, что вам не нужно реализовывать какую-либо строку кода, вы просто делитесь своими данными с сервером Strongmail и отправляете миллионы писем:) – vaske

2

Я реализовал массовую рассылку в php, где каждое электронное письмо было настроено для отдельного человека. Это было не сложно и не занимало слишком много времени. Я использовал swiftmailer и cron. Возможно, Zend Mail тоже в порядке. Я начал с очереди сообщений PEAR, но очередность сообщений электронной почты была слишком медленной.

Процесс массового обслуживания электронной почты пошел так:

  1. Создать шаблон электронной почты и добавьте заполнители (или использовать двигатель шаблона) для областей, где будет заменяться уникальный контент.
  2. В цикле замените заполнители любым уникальным контентом, вставьте в него содержимое электронной почты, тему, адреса, пакетный идентификатор и, при необходимости, значение приоритета в таблицу базы данных.

Я использовал работу cron для отправки партий писем. Временной интервал cron и количество отправленных сообщений в рассылке были важны, так как я был на общем узле с ограничениями. Сценарий, который был вызван работой cron, был доступен только cron. Сценарий читает x количество сообщений электронной почты из таблицы, упорядоченной с помощью идентификатора пакета и, при необходимости, приоритета. Если письмо было успешно отправлено, оно было удалено из очереди базы данных. Если электронное письмо не может быть отправлено, оно оставалось в очереди, и счетчик был увеличен для этой записи. Если счетчик превысил установленное число, тогда сообщение было удалено из очереди.

+0

Несколько полезных советов для ускорения очереди с PEAR_Mail составляют * _seq таблицу MEMORY в Mysql. Я также завернул его в транзакцию на 100 записей –

0

Я разработал систему управления рассылкой новостей с Swiftmailer, и ее очень легко реализовать. Он поддерживает SMTP, шифрование, вложения, пакетную отправку, ...

3

Используйте Zend_Queue, чтобы поместить электронные письма в очередь для асинхронной обработки фона. Для обработки очереди в фоновом режиме вам понадобится задание cron.

protected function _enqueueEmail(WikiEmailArticle $email) 
{ 
    static $intialized = false; 

    if (!$initialized) { 

     $this->_initializeMailQueue("wikiappwork_queue"); 
     $initialized = true; 
    } 

    $this->_mailQueue->send(serialize($email)); 
} 
protected function _initializeMailQueue() 
{ 
    /* See: 1.) http://framework.zend.com/manual/en/zend.queue.adapters.html and 
    *  2.) Zend/Queue/Adapter/Db/mysql.sql. 
    */ 

$ini = Zend_Controller_Front::getInstance()->getParam('bootstrap') 
              ->getOptions(); 

    $queueAdapterOptions = array('driverOptions' => array(
    'host' => $ini['resources']['multidb']['zqueue']['host'], 
    'username' => $ini['resources']['multidb']['zqueue']['username'], 
    'password' => $ini['resources']['multidb']['zqueue']['password'], 
    'dbname' => $ini['resources']['multidb']['zqueue']['dbname'], 
    'type' => $ini['resources']['multidb']['zqueue']['adapter']), 
    'name' => $ini['resources']['multidb']['zqueue']['queueName']); 

    $this->_mailQueue = new Zend_Queue('Db', $queueAdapterOptions); 

} 

Тогда для хрон, сценарий как

<?php 
use \Wiki\Email\WikiEmailArticle; 

// Change this define to correspond to the location of the wikiapp.work/libary 
define('APPLICATION_PATH', '/home/kurt/public_html/wikiapp.work/application'); 

set_include_path(implode(PATH_SEPARATOR, array(
    APPLICATION_PATH . '/../library', 
    get_include_path(), 
))); 

// autoloader (uses closure) for loading both WikiXXX classes and Zend_ classes. 
spl_autoload_register(function ($className) { 

    // Zend classes need underscore converted to PATH_SEPARATOR 
    if (strpos($className, 'Zend_') === 0) { 

     $className = str_replace('_', '/', $className); 
    } 

    $file = str_replace('\\', '/', $className . '.php'); 

    // search include path for the file. 
    $include_dirs = explode(PATH_SEPARATOR, get_include_path()); 

    foreach($include_dirs as $dir) { 

    $full_file = $dir . '/'. $file; 

    if (file_exists($full_file)) { 

     require_once $full_file; 
     return true; 
    } 
    } 

    return false; 
}); 

// Load and parese ini file, grabing sections we need. 
$ini = new Zend_Config_Ini(APPLICATION_PATH . 
          '/configs/application.ini', 'production'); 

$queue_config = $ini->resources->multidb->zqueue; 

$smtp_config = $ini->email->smtp; 

$queueAdapterOptions = array('driverOptions' => array(
             'host'  => $queue_config->host, 
        'username' => $queue_config->username, 
        'password' => $queue_config->password, 
        'dbname' => $queue_config->dbname, 
        'type'  => $queue_config->adapter), 
       'name' => $queue_config->queuename); 

$queue = new Zend_Queue('Db', $queueAdapterOptions); 


$smtp = new Zend_Mail_Transport_Smtp($smtp_config->server, array(
       'auth'  => $smtp_config->auth, 
     'username' => $smtp_config->username, 
     'password' => $smtp_config->password, 
     'port'  => $smtp_config->port, 
     'ssl'  => $smtp_config->ssl 
     )); 

Zend_Mail::setDefaultTransport($smtp); 

$messages = $queue->receive(10); 

foreach($messages as $message) { 

     // new WikiEmailArticle.  
    $email = unserialize($message->body); 

     try { 

      $email->send(); 

     } catch(Zend_Mail_Exception $e) { 

       // Log the error? 
       $msg = $e->getMessage(); 
       $str = $e->__toString(); 
       $trace = preg_replace('/(\d\d?\.)/', '\1\r', $str); 
     } // end try 

$queue->deleteMessage($message); 

} // end foreach