zend mac framework documentacion composer php email zend-framework smtp mailing-list

php - mac - zend framework 3 documentacion



¿Cuál es el mejor enfoque para enviar correos electrónicos a cientos de destinatarios desde una aplicación de Zend Framework? (8)

De la documentación PHP.net.

Nota: Vale la pena señalar que la función mail () no es adecuada para grandes volúmenes de correo electrónico en un bucle. Esta función abre y cierra un socket SMTP para cada correo electrónico, que no es muy eficiente.
Para el envío de grandes cantidades de correo electrónico, consulte los paquetes » PEAR :: Mail , y» PEAR :: Mail_Queue .

La clase Zend Mail es probablemente bastante buena (la mayoría de las cosas de Zend son buenas) Pero si quieres otras opciones. Aquí están.

Estoy tratando de implementar un sistema de listas de correo para mi aplicación. Actualmente estoy usando Zend_Mail_Transport_Smtp(''localhost'') como mi transporte, recorriendo mi lista de suscriptores y enviando un nuevo Zend_Mail a cada uno. Sin embargo, me doy cuenta de que el tiempo que lleva completar el script aumenta a medida que aumenta el número de suscriptores.

Estoy seguro de que debe haber un enfoque más profesional para hacer esto, involucrando la cola de correos electrónicos. Supongo que el enfoque ideal sería que el usuario complete el formulario, haga clic en enviar e inmediatamente reciba una respuesta que diga que se están enviando los correos electrónicos, en lugar de esperar que los cientos de correos electrónicos terminen de enviarse.

Entiendo que Zend_Mail no hace ningún tipo de cola de correo. ¿Podría alguien que tenga experiencia con esto, darme una visión general de cómo se puede hacer esto? No sé nada de cron / crontab / cronjobs, así que si eso implica, explica el proceso.


Debería estar bien usando PHP en los miles de destinatarios, aunque evite el correo () como otros han notado. He visto algunos sistemas diseñados para grandes cantidades de correo (más de 100.000 destinatarios) comenzar a pasar por alto las funciones de correo estándar e intentar trabajar más directamente con el MTA. Incluso entonces no ha sido claro para mí que se requiera.

Hacer que el correo electrónico sea profesional es más que asegurarse de que el formato sea bueno (HTML y texto sin formato siempre que sea posible), la gente puede darse de baja fácilmente, los rebotes se manejan correctamente, el servidor de correo tiene todos los registros DNS correctos y la configuración del servidor no funciona Violar las reglas de cualquier sistema importante de listas negras. El idioma en el que escribe la aplicación no es un factor importante en unos cientos o incluso miles de mensajes.


Implementé un envío masivo de correo en PHP donde cada correo electrónico se personalizó para un individuo. No fue difícil y no llevó demasiado tiempo. Usé swiftmailer y cron. Zend Mail podría estar bien también. Empecé con la cola de correo PEAR, pero poner en cola los correos electrónicos fue demasiado lento.

El proceso de poner en cola los correos electrónicos fue así:

  1. Cree la plantilla de correo electrónico y agregue marcadores de posición (o use un motor de plantilla) para las áreas donde se sustituirá el contenido único.
  2. En un bucle, sustituya los marcadores de posición en cualquier contenido único, inserte el contenido del correo electrónico resultante, el asunto, las direcciones, el ID del lote y, opcionalmente, un valor de prioridad en una tabla de base de datos.

Usé un trabajo cron para enviar lotes de correos electrónicos. El intervalo de tiempo de cron y el número de correos electrónicos enviados por lote fueron importantes ya que estaba en un host compartido con límites. La secuencia de comandos que fue llamada por el trabajo cron solo fue accesible por cron. El script lee x cantidad de correos electrónicos de la tabla ordenados por id. De lote y, opcionalmente, prioridad. Si un correo electrónico se envió con éxito, se eliminó de la cola de la base de datos. Si no se podía enviar un correo electrónico, permanecía en la cola y se incrementaba un contador para ese registro. Si un contador superaba un número establecido, el correo electrónico se eliminó de la cola.


La clase Zend Mail se ve bien y es fácil de usar, también le permite enviar un texto sin formato y una versión HTML del correo electrónico, que en marketing por correo electrónico es muy importante.

Si estás familiarizado con el marco, me quedaré con él.

Cosas importantes a tener en cuenta al enviar correos electrónicos a grandes volúmenes de personas son:

  • ¿Puede su servidor web hacer frente a las solicitudes de imágenes cuando se abren los correos electrónicos + la carga en el servidor de las personas que visitan su sitio?

Si la respuesta es no o no está seguro, el uso de un punto de referencia de apache debería ser capaz de ayudarlo a resolver si puede. Si todavía no está seguro, siempre es mejor enviar por lotes correos electrónicos (que pueden sincronizarse con crontab) para repartir la carga.

Espero que esto ayude.


NOTA: cuando leí por primera vez su pregunta, pensé que decía cientos de miles de correos electrónicos a la vez. Cuando lo comprobé dos veces, noté que en realidad decía cientos o miles. Soy demasiado perezoso para cambiar mi publicación ahora, así que he aquí algunas advertencias: según mi experiencia, probablemente pueda funcionar bien sin una herramienta comercial de aproximadamente 40K. Con aproximadamente 10K, querrá seguir la lista "mínima" para evitar dolores mayores cuando comience a alcanzar tamaños de lista más grandes. Sin embargo, recomiendo implementarlo todo de inmediato.

Ya he dicho esto antes, hay dos lados para enviar un correo electrónico:

  1. El lado técnico: básicamente todos los RFC alrededor del protocolo smtp, formatos de correo electrónico, registros DNS, etc. Esto es levemente complicado pero solucionable.
  2. El lado mágico: la administración de entrega de correo electrónico es vudú. Se sentirá frustrado, las cosas se romperán sin ninguna razón aparente y considerará irse a otro trabajo que no involucre el correo electrónico.

Recomiendo no escribir tu propio remitente masivo. Estoy seguro de que PHP puede hacer un buen trabajo, pero probablemente deberías pasar tu tiempo en otro lado. Los dos productos que he usado en el pasado y recomiendo son Strongmail y PowerMTA. Ten en cuenta que tienen un alto precio, pero casi puedo garantizarte que gastarás más en construir tu propia solución a largo plazo.

Un área que te encantará cuando escribas la tuya en PHP es la de estrangulamiento / alquitrán. Los servidores de correo comenzarán a agregarse en reposo (30) después de que haya enviado algunos mensajes para desacelerarlo y evitar que envíe spam.

Típicamente, estos remitentes masivos comerciales ejecutan el protocolo SMTP para hacer cola. Continuarías usando Zend_Mail, pero codifícalo para conectarte a tu servidor. Pondrá en cola el correo casi tan rápido como lo pueda enviar, y luego usará su propio motor para enviar el correo a sus destinos.

En una lista de 100K, tendrá que emplear las mejores prácticas de correo electrónico. Como mínimo, necesitarás:

  • SPF Records, posiblemente DKIM también
  • Múltiples direcciones IP para segmentar el tráfico - tienen 3 direcciones IP, una para la dirección de calidad en la que confía, una para las direcciones IP de riesgo medio y una para las direcciones IP de alto riesgo. Este diseño ayuda a minimizar el riesgo de recibir correo a sus mejores clientes.
  • DNS inverso correcto para enviar direcciones IP
  • Utilice los ciclos de retroalimentación de AOL, Hotmail, Yahoo y otros para procesar quejas de spam
  • Administración de cancelación de suscripción y suscripción: asegúrese de que está borrando estas direcciones
  • Tener un seguimiento de apertura / clic también es importante: si sus clientes en la lista A no abren sus correos electrónicos, debe degradarlos a la lista B, y así sucesivamente. Esto es importante porque los ISP convertirán las cuentas inactivas en un honeypot. Hotmail es famoso por esto.

Finalmente, si realmente quieres enviar un correo electrónico, querrás algunas otras herramientas como Return Path.


Desarrollé un sistema de gestión de boletines con Swiftmailer y es muy fácil de implementar. Es compatible con SMTP, cifrado, archivos adjuntos, envío por lotes, ...


Para enviar de manera confiable una gran cantidad de correos electrónicos usando PHP, debe usar un mecanismo de cola. Según lo sugerido por otros, el proceso de usar una cola se ve así:

  • Pasa el cursor por tu grupo de usuarios, creando un correo electrónico para cada uno y posiblemente personalizando el contenido
  • Pase cada objeto de correo a la cola que retrasará el envío del correo electrónico hasta más tarde
  • En algún tipo de script cron, envíe el contenido de la cola unos cientos a la vez. Nota: le conviene ajustar la cantidad de correos electrónicos que está enviando al observar los registros en busca de errores provenientes del proceso de envío real. Si intentas enviar demasiados, me doy cuenta de que llega a un punto en el que el transporte de correo ya no aceptará conexiones (estoy usando qmail)

Hay algunas bibliotecas que puede usar para hacer esto, PEAR Mail Queue (con Mail_Mime) y SwiftMailer le permiten crear y poner en cola correos electrónicos. Hasta ahora, Zend Mail solo proporciona la creación de correos electrónicos, sin cola (más sobre esto más adelante).

Tengo experiencia principalmente con PEAR Mail Queue y hay algunos inconvenientes. Si está tratando de poner en cola una gran cantidad de correos electrónicos (por ejemplo, hacer un bucle de más de 20,000 usuarios e intentar colocarlos en la cola en un tiempo razonable), la implementación de la codificación imprimible entre comillas de Mail Mime es muy lenta. Puede acelerar esto cambiando a codificación base64.

En cuanto a Zend Mail, puede escribir un objeto Zend Mail Transport que coloque sus objetos de Zend Mail en PEAR Mail Queue. Lo he hecho con cierto éxito, pero se necesita un poco de juego para hacerlo bien. Para ello, extienda Zend Mail Transport Abstract, implemente el método _sendMail (que es donde colocará su objeto Zend Mail en Mail Queue) y pase la instancia de su objeto de transporte al método send () de su objeto Zend Mail o por Zend Mail :: setDefaultTransport ().

La conclusión es que hay muchas maneras en que puede hacer esto, pero llevará algo de investigación y aprendizaje en su nombre. Sin embargo, es un problema muy solucionable.


Use Zend_Queue para colocar los correos electrónicos en la cola para un procesamiento de fondo asíncrono. Necesitará un trabajo cron para procesar la cola en segundo plano.

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); }

Luego, para el trabajo cron, un script como

<?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