Как лучше всего отправлять электронную почту сотням получателей из приложения Zend Framework? - PullRequest
16 голосов
/ 25 апреля 2009

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

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

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

Ответы [ 8 ]

19 голосов
/ 07 мая 2009

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

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

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

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

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

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

18 голосов
/ 25 апреля 2009

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

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

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

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

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

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

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

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

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

3 голосов
/ 26 мая 2011

Используйте 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);

 }

Тогда для задания cron, скрипт типа

<?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
3 голосов
/ 25 апреля 2009

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

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

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

2 голосов
/ 25 апреля 2009

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

Процесс размещения писем в очереди пошел так:

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

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

2 голосов
/ 25 апреля 2009

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

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

0 голосов
/ 26 апреля 2009

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

0 голосов
/ 25 апреля 2009

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

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...