Foros del Web » Programando para Internet » PHP »

Opinion sobre mi script para enviar mails masivos

Estas en el tema de Opinion sobre mi script para enviar mails masivos en el foro de PHP en Foros del Web. Buenas amigos, posteo porque me gustaría que me den su opinion (y una mano en cuanto a este tema) sobre un script que estoy comenzando ...
  #1 (permalink)  
Antiguo 09/06/2006, 13:23
 
Fecha de Ingreso: mayo-2006
Mensajes: 34
Antigüedad: 11 años, 7 meses
Puntos: 0
Pregunta Opinion sobre mi script para enviar mails masivos

Buenas amigos, posteo porque me gustaría que me den su opinion (y una mano en cuanto a este tema) sobre un script que estoy comenzando a desarrollar, para enviar mails masivos sin saturar el servidor.

Se me ocurrió desarrollar este sistemita porque instalé phplist y es un lio hacerlo andar en mi server, y dada mail está muy bueno pero no puedo hacer q tome los mails de mi db mysql.

Por otro lado me di cuenta lo que yo necesito es algo bien bien sencillo, no un software completo para enviar boletines, sino simplemente un script que lo realize...paso a adjuntar el boceto que llevo hecho (aún no lo testeé pero creo que es bastante logico)

Script usado para el envío de los mails PHPMailer descargado de PHPClasses.org

TABLAS de mi DB
nl_new_available : valor 0 o 1. "0" indica que no hay un nuevo boletin para enviar, "1" indica lo contrario.

nl_adress_sended: una vez que se inició el proceso de envío indica cuantos mails ya fueron enviados.

nl_users: tabla con informacion de cada contacto, incluyendo el email.

Funcionamiento:

1- Seteo un cron en mi server para que todos los 1 y 15 de cada mes me ejecute cada 2 minutos sendNL.php (que contiene el codigo de más abajo).

2- El sistema comienza el envío de 10 mensajes cada 2 minutos para no saturar el servidor, cada vez que realiza esta tarea graba en "nl_adress_sended" el total enviado.

3- El cuerpo del mensaje es generado embebiendo un html. (Donde dice "Cuerpo del mensaje").

4- Cuando se envía el boletin a todas las direcciones de email se graba en "nl_new_available" el valor 0, y los resutados del proceso son enviados al administrador atachados en un email.

Código PHP:
<?   
// Enviar NL //////////////////////////////////////////////////////////////////////
   
   // Incluyo el enviador de mails
   
include("class.phpmailer.php");
   
   
// Me conecto a la base
   
include("conex.php"); 
   
$link Conectarse();
   
   
// Revizo si hay un nuevo NL disponible
   
$query1 "SELECT new FROM nl_new_available";
   
$result1 mysql_query$query1 $link ) or die( mysql_error() );
   
$row1 mysql_fetch_array($result1);
   if(
$row1['new'] == 1){
   
   
// Extraigo de la tabla de "nl_adress_sended" la ultima cantidad enviada.
             
$query2 "SELECT total FROM nl_adress_sended";
             
$result2 mysql_query($query2 $link) or die( mysql_error() );
             
$row2 mysql_fetch_array($result2);
             
   
// Selecciono los registros partiendo de la ultima cantidad enviada + 1.
                     
$piso $row3[total] + 1;
             
$techo $row3[total] + 10;
                     
$query3 "SELECT email FROM nl_users ORDER BY ID ASC Between $piso And $techo ";
                     
$result3 mysql_query$query3 $link ) or die( mysql_error() );

   
// Envio el mail
                     
while($row mysql_fetch_array($result3)){
             
$mail = new PHPMailer();
                     
$mail->From '[email protected]';
                     
$mail->FromName 'Boletin Quincenal - Dominio.com';
                     
$mail->AddAddress($row3[email]));
                     
$mail->IsHTML(true);
                     
$mail->Subject "Boletin Quincenal - Dominio.com";
                     
$mail->Body    "<font color='#000000' face='Arial, Helvetica, sans-serif'>Cuerpo del mensaje</font>";
        
                     if(!
$mail->Send()){/* Escribo el error en un archivo de texto */}
                     else{
/* Escribo el resutado exitoso en un archivo de texto */};
                     };
                     
   
// Grabo en la tabla "enviados" los mails que fueron enviados.
                     
$query4 "UPDATE nl_adress_sended SET `total` = '$techo'";
                     
$result4 mysql_query$query4 $link ) or die( mysql_error() );

   
// Si se envió el total de mails grabo en la tabla "nuevo NL disponible" el valor cero
                     
$query5 "SELECT total FROM nl_adress_sended";
                     
$result5 mysql_query$query5 $link ) or die( mysql_error() );
                     
$row5 mysql_fetch_array($result5);
                     
                     
$query6 "SELECT * FROM nl_users";
                     
$result6 mysql_query$query6 $link ) or die( mysql_error() );
                     
$total_users mysql_num_rows($result6);
                     
                     if(
$row5[total] == $total_users){
                                
$query7 "UPDATE nl_new_available SET `new` = '0'";
                               
$result7 mysql_query$query7 $link ) or die( mysql_error() );

   
// Envio mail informando al administrador
                     
$mail = new PHPMailer();
                     
$mail->From '[email protected]';
                     
$mail->FromName 'Enviador de boletín - Dominio.com';
                     
$mail->AddAddress($row[email]));
                     
$mail->IsHTML(true);
                     
$mail->Subject "Dominio.com - Resultados de envio de boletin (Fecha)";
                     
$mail->Body    "<font color='#000000' face='Arial, Helvetica, sans-serif'>Resultados del envio de boletín</font>";
                     
$mail->AddAttachment("send_mail_results.txt");
                     if(!
$mail->Send())/* Muestro error en pantalla */
   
    
};

   };

 
// Fin ////////////////////////////////////////////////////////////////////////////

?>

Espero sus criticas, opinines y consejos!
Saludos y gracias!
  #2 (permalink)  
Antiguo 09/06/2006, 13:50
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 15 años, 11 meses
Puntos: 126
Pues en general se ve bien .. sobre todo por qué te basastes en PHP Mailer (una excelente classe para trabajar con e-mail desde PHP).

Ahora .. como recomendación .. Estaría bueno validar las direcciones de e-mail va a enviarse y registrar si hay algún mensaje de error que PHP Mailer enviando el e-mail por SMTP lo recoje con el método:

$mail->ErrorInfo;

Y ese error como comento .. registrarlo en un Log .. ya sea un simple archivo de texto plano donde tiras el mensaje de error si existe junto con la entrada del e-mail de tu BBDD que envias que lo origina para posibles analisis .. o a una BBDD .. como gustes.

Un saludo,
__________________
Por motivos personales ya no puedo estar con Uds. Fue grato haber compartido todos estos años. Igualmente los seguiré leyendo.
  #3 (permalink)  
Antiguo 11/06/2006, 13:17
 
Fecha de Ingreso: mayo-2006
Mensajes: 34
Antigüedad: 11 años, 7 meses
Puntos: 0
Pregunta

Cluster muchas gracias por tu respuesta.

Bien agregué en mi código la parte de error_log (o mas bien de grabar resultados sea error o no).

Te quería hacer dos preguntas una respecto de la validadción de email, como sería este tema? porque yo valido el mail cuando entra en la base desde el formulario de login... a eso te referías?

Bueno, la otra pregunta que quiero hacerte es sobre el tema de enviar vía SMTP, PHPMailer envía aprentemente de una forma (como lo estoy usando yo), y también vía SMTP... mi pregunta es que me conviene hacer con tal de no saturar mi server y de que mi server no aparesca en ninguna "lista negra"...

Bueno adjunto el código con el agregado... espero criticas foristaas.
Muchas graciias!
Código PHP:
   // Enviar NL ////////////////////////////////////////////////////////////////////////////////////////
   // Incluyo el enviador de mails
   
include("class.phpmailer.php");
   
   
// Me conecto a la base
   
include("conex.php"); 
   
$link Conectarse();
   
   
// Revizo si hay un nuevo NL disponible
   
$query1 "SELECT new FROM nl_new_available";
   
$result1 mysql_query$query1 $link ) or die( mysql_error() );
   
$row1 mysql_fetch_array($result1);
   if(
$row1['new'] == 1){
   
   
// Creo un file para guardar los resultados
   
$file "http://www.dominio.com/logs/result_log_" date("Y-m-d") . ".txt";
   if(!
file_exists($file))$gestor fopen($file,"a+");
   
   
// Extraigo de la tabla de "enviados" la ultima cantidad enviada.
             
$query2 "SELECT total FROM nl_adress_sended";
             
$result2 mysql_query($query2 $link) or die( mysql_error() );
             
$row2 mysql_fetch_array($result2);
             
   
// Selecciono los registros LIMIT 10 partiendo de la ultima cantidad enviada + 1.
                     
$piso $row3[total] + 1;
                     
$techo $row3[total] + 10;
                     
$query3 "SELECT email FROM nl_users ORDER BY ID ASC Between $piso And $techo ";
                     
$result3 mysql_query$query3 $link ) or die( mysql_error() );

   
// Envio el mail
                     
while($row mysql_fetch_array($result3)){
                     
$mail = new PHPMailer();
                     
$mail->From '[email protected]';
                     
$mail->FromName 'Boletin Quincenal - Dominio.com';
                     
$mail->AddAddress($row3[email]));
                     
$mail->IsHTML(true);
                     
$mail->Subject "Boletin Quincenal - Dominio.com";
                     
$mail->Body    "<font color='#000000' face='Arial, Helvetica, sans-serif'>Cuerpo del mensaje</font>";
        
                     if(!
$mail->Send())fwrite($gestor"ERROR al enviar mail a $row3[email] - " date("r") . " - ErrorInfo: " $mail->ErrorInfo " \r\n");//Escribo error en log
                     
else fwrite($gestor"Correcto: mail a $row3[email] - " date("r") . "\r\n");//Escribo confirmacion en log
                     
};
                     
   
// Grabo en la tabla "enviados" los mails que fueron enviados.
                     
$query4 "UPDATE nl_adress_sended SET `total` = '$techo'";
                     
$result4 mysql_query$query4 $link ) or die( mysql_error() );

   
// Si se envió el total de mails grabo en la tabla "nuevo NL disponible" el valor cero
                     
$query5 "SELECT total FROM nl_adress_sended";
                     
$result5 mysql_query$query5 $link ) or die( mysql_error() );
                     
$row5 mysql_fetch_array($result5);
                     
                     
$query6 "SELECT * FROM nl_users";
                     
$result6 mysql_query$query6 $link ) or die( mysql_error() );
                     
$total_users mysql_num_rows($result6);
                     
                     if(
$row5[total] == $total_users){
                                
$query7 "UPDATE nl_new_available SET `new` = '0'";
                               
$result7 mysql_query$query7 $link ) or die( mysql_error() );

   
// Envio mail informando al adminitrador
                     
$mail = new PHPMailer();
                     
$mail->From '[email protected]';
                     
$mail->FromName 'Enviador de boletín - Dominio.com';
                     
$mail->AddAddress($row[email]));
                     
$mail->IsHTML(true);
                     
$mail->Subject "Dominio.com - Resultados de envio de boletin (Fecha)";
                     
$mail->Body    "<font color='#000000' face='Arial, Helvetica, sans-serif'>Resultados del envio de boletín</font>";
                     
$mail->AddAttachment($file);
                     if(!
$mail->Send())fwrite($gestor"ERROR al enviar mail a Administración - " date("r") . " - ErrorInfo: " $mail->ErrorInfo " \r\n");/* Si no pude enviar el mail a administracion, grabo el error en el log */
                     
};
                     
                     
fclose($gestor);
   
   };
   
// Fin /////////////////////////////////////////////////////////////////////////////////////////////
?> 
  #4 (permalink)  
Antiguo 13/06/2006, 09:03
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 15 años, 11 meses
Puntos: 126
Cita:
Te quería hacer dos preguntas una respecto de la validadción de email, como sería este tema? porque yo valido el mail cuando entra en la base desde el formulario de login... a eso te referías?
Si lo haces así .. no tendría mucho sentido repetir la operación cuando envias el e-mail .. Pero a veces se introducen datos por otros médios a tus BBDD, ya sean por procesos de importación "masivos" de datos que no pudistes o no sabes si están correctos o por otras causas.

Cita:
PHPMailer envía aprentemente de una forma (como lo estoy usando yo), y también vía SMTP... mi pregunta es que me conviene hacer con tal de no saturar mi server y de que mi server no aparesca en ninguna "lista negra"...
En principio PHPMailer puede enviar el e-mail usando la función mail() de PHP nativa de este, usando el MTA: sendmail() y usando conexión directa SMTP. No sé ahora como "por defecto" PHPMailer lo hace .. (siempre uso el método SMTP directo y así lo especifico en:
Código PHP:
 $mail->Mailer   "smtp";
// junto con otros datos sobre el Host y demás para el envio por SMTP directo ... 
El tema de evitar caer en "listas negras" o no .. no depende de que si usastes mail() o un servidor SMTP tuyo própio directo. Depende de las condiciones que rodean al envio del e-mail en sí .. no tanto de PHP. PHP con PHPMailer ajusta en la medida de lo posible las cabeceras del e-mail .. rigiendose en los RFC's que las definen, pero .. es al final de todo tu servidor de correo el que envia el e-mail, el cual "corre" bajo cierto domino/IP registrado (con sus registros MX en regla .. su dominio registrado o no asociado .. ). Todo eso es parte del envio del e-mail y lo que los filtros de "SPAM" validan entre otras cosas. A las "listas negras" se añaden IP's/dominos que se ha comprobado que hacen SPAM y así son consultados por los filtros de anti-SPAM para validar si quien envia el e-mail está en esas listas o no (insisto: entre otras cosas que validan).

Por cierto .. se me olvidó algo bien importante .. que ahora me dí cuenta:

Haces en tu código:

Cita:
while($row = mysql_fetch_array($result3)){ <--- inicias un bucle
$mail = new PHPMailer(); <-- instancias el objeto PHPMailer constantemente a cada pasada del bucle ..
También más abajo .. vuelves a instanciar el objeto nuevamente:
Cita:
// Envio mail informando al adminitrador
$mail = new PHPMailer();
El objeto .. su "instancia" ($mail=new PHPMailer();) sólo debes hacerlo -una vez- .. al principio del script .. envies los e-mails que envies. Para eso .. PHPMailer tiene sus métodos para "resetear" las direcciones de e-mail que puedas haber acomulado con un:

Código PHP:
$mail->AddAddress($row3[email])); 
Ates de cerrar tu bucle:
Código PHP:
while(....) { 
..... 
aqu&#237;}; 
Debes usar:
Código PHP:
$mail->ClearAddresses(); 
Tienes otra función similar para "resetear" archivos adjuntos si lo usases de la misma forma ...


Un saludo,
__________________
Por motivos personales ya no puedo estar con Uds. Fue grato haber compartido todos estos años. Igualmente los seguiré leyendo.
  #5 (permalink)  
Antiguo 13/06/2006, 11:23
 
Fecha de Ingreso: mayo-2006
Mensajes: 34
Antigüedad: 11 años, 7 meses
Puntos: 0
Buenisimo Cluster!

Cluster genial, muchas gracias por las explicaciones me dejaron mas claro el tema.

Optimicé un montón el script, si lo revizás te vas a dar cuenta, solo me quedan dos dudas:
1: Estoy tratando de dispararlo con una tarea CRON pero por alguna razon no me lo dispara!!, la tarea que uso (test) es:
0,15,30,45 * * * * http://www.midominio.com/admin/sendNL.php
Se te ocurre por que puede ser? Esta tarea la armo desde un admin que me proveen los de mi servidor..
2: Hay peligro real de que se trabe todo y termine no enviando nada con este script? como lo ves vos con tu ojo profesional? Digamos hay posibilidad de esta manera de enviar por ejemplo 200, 300 mails?

Bueno gracias de nuevo y adjunto el codigo nuevo:

Código PHP:
<?
   
###################################################################################################################################
   ##                                   RUTINA PARA ENVÍO DE BOLETINES INFORMATIVOS                                                 ##
   ###################################################################################################################################
   
   /* Script usado para el envío de los mails
   ------------------------------------------
   PHPMailer descargado de PHPClasses.org
   
   TABLAS
   ------
   nl_new_available : valor 0 o 1. "0" indica que no hay un nuevo boletin para enviar, "1" indica lo contrario.
   
   nl_users: tabla con informacion de cada contacto, incluyendo el email.
   
   Funcionamiento:
   ---------------
   1- Seteo un cron en mi server para que todos los 1 y 15 de cada mes me ejecute sendNL.php (que contiene el codigo de más abajo).
   
   2- El cuerpo del mensaje es generado embebiendo un archivo.
   
   3- Cuando se envía el boletin a todas las direcciones de email se graba en "nl_new_available" el valor 0,
      y los resutados del proceso son enviados al administrador vía email.   
   */
   ###################################################################################################################################
   
   // CONFIGURACION GENERAL //////////////////////////////////////////////////////////////////////////////////////////////////////////
   // Includes
   
include("class.phpmailer.php");
   include(
"conex.php");
   
$link Conectarse();
   
   
// VARIABLES
   // Dominio
   
$dominio $_SERVER['HTTP_HOST'];
   
// Email del administrador
   
$administrador "[email protected]$_SERVER['HTTP_HOST'];
   
// Nombre y ubicacion del archivo LOG (debe comenzar con "../")
   
$file "../Backup/logs/result_log_" date("Y-m-d") . ".txt";
   
// Gestor de archivo LOG
   
$gestor fopen($file,"a+");
   
// Nombre y ubicacion del TEMPLATE
   
$template "http://$dominio/NL.php"
   
// Subject del boletin
   
$subject "Boletin Quincenal - $dominio"
   
   
// Configuracion PHPMailer 
   
$mail = new PHPMailer();
   
$mail->Mailer   "smtp";
   
$mail->IsHTML(true);
   
$mail->From "[email protected]$dominio";
   
$mail->FromName $dominio;
   
   
   
// Enviar NL /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   
   // 1. Revizo si hay un nuevo NL disponible
   
$query1 "SELECT new FROM nl_new_available";
   
$result1 mysql_query$query1 $link ) or die( mysql_error() );
   
$row1 mysql_fetch_array($result1);
   if(
$row1['new'] == 1){
                
                     
// Selecciono todos los registros
                     
$query2 "SELECT email FROM nl_users ORDER BY ID";
                     
$result2 mysql_query($query2,$link) or die(mysql_error());
                     
$total mysql_num_rows($result2);
                     
                     
// Envio el mail
                     
$i 1;
                     while(
$row2 mysql_fetch_array($result2)){

                     
$mail->AddAddress($row3[email]);
                     
$mail->Subject $subject;
                     
$mail->Body    file_get_contents($template);
                     
                     
//Escribo error en log
                     
if(!$mail->Send())fwrite($gestor"$i / ERROR al enviar mail a $row2[email] - " date("r") . " - ErrorInfo: " $mail->ErrorInfo " \r\n");
                     
//Escribo confirmacion en log
                     
else fwrite($gestor"$i / Correcto: mail a $row2[email] - " date("r") . "\r\n");
                     
                     
//echo"Enviado: $row2[email] <strong>$i</strong> de $total<br>";//TEST: Muestro enviados en pantalla
                     
                     // Duermo el script para no saturar al servidor
                     
sleep(2);
                     
                     
$mail->ClearAddresses();
                     
$i++;                     
                     };
                     
                               
// Al terminar la rutina de envío grabo en la base que no hay nuevos boletines                     
                                
$query3 "UPDATE nl_new_available SET `new` = '0'";

                               
$result3 mysql_query($query3,$link) or die(mysql_error());
                               
                               
// Envio mail informando al administrador
                               
$mail->AddAddress($administrador);
                               
$mail->Subject "$dominio - Resultados de envío de boletin " date("r");
                               
$mail->Body    "<font color='#000000' face='Arial, Helvetica, sans-serif'>Resultados del envío de boletín</font>";
                               
$mail->AddAttachment($file);
                               if(!
$mail->Send())fwrite($gestor"ERROR al enviar mail a Administración - " date("r") . " - ErrorInfo: " $mail->ErrorInfo " \r\n");

                     
                               
fclose($gestor);
                               
mysql_close($link);

   
   };
   
// Fin /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
?>
  #6 (permalink)  
Antiguo 13/06/2006, 12:48
 
Fecha de Ingreso: junio-2004
Mensajes: 60
Antigüedad: 13 años, 6 meses
Puntos: 1
Creo que deberias hacer la llamada a la página desde algun navegador, por ejemplo utilizar Lynx en modo consola:

0,15,30,45 * * * * lynx http://www.midominio.com/admin/sendNL.php


Espero te sirva.

Al3jo
  #7 (permalink)  
Antiguo 14/06/2006, 13:33
 
Fecha de Ingreso: mayo-2006
Mensajes: 34
Antigüedad: 11 años, 7 meses
Puntos: 0
Cita:
Iniciado por al3jo
Creo que deberias hacer la llamada a la página desde algun navegador, por ejemplo utilizar Lynx en modo consola:

0,15,30,45 * * * * lynx http://www.midominio.com/admin/sendNL.php


Espero te sirva.

Al3jo
al3jo muchas gracias por responder, intenté con lo que vos me decís pero sigue sin resultarme... habrá alguna otra manera de realizar esto??

gracias!
  #8 (permalink)  
Antiguo 14/06/2006, 13:55
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 15 años, 11 meses
Puntos: 126
Tu script SendNL.php es el correspondiente al código que hemos visto en este mensaje?

Si tu en un Cron Job llamas a un script PHP .. tendrías que llamarlo bajo el interprete de PHP (recuera que PHP es "interpretado") o bien simulas una llamada desde algún navegador texto (como lynx) o algún metodo como por ejemplo GET:

Cita:
(uso GET .. llamo a mi script como si lo hiciera a mano por un navegador común y toda salida que genere la descarto (la envio al "null") pues ya haces registros de otra forma en tu código )

En cualquier caso .. para solventar ese tipo de problemas contacta con tu proveedor para que te indique que comando es el más idoneo según tu configuración asignada en ese servidor .. tal vez la "shell" que tienes no te permita ejeuctar esos comandos propuestos .. consultado mejor.

Cita:
: Hay peligro real de que se trabe todo y termine no enviando nada con este script? como lo ves vos con tu ojo profesional? Digamos hay posibilidad de esta manera de enviar por ejemplo 200, 300 mails?
Se observa un problema a primera vista, .. usas "sleep()" para demorar la ejecución de tu script por cierto tiempo para que "descanse" tu servidor SMTP a cada tanda de N e-mails enviados. Esto te va a plantear un problema a primeras: necesitas dar tiempo de ejecución a tu script ilimitado .. tarde lo que tarde en ejecutarse. PHP impone límite (30 Segundos por defecto) a la ejecución de un script .. así que si multiplicas tu tanda de envios de e-mail .. lo que tarde uno por uno en procesarse y ese "sleep()" que haces ahí veras que sobrepasaras dicho tiempo muchas veces.

Para esto tienes la función:
set_time_limit()

Pero si dices usar un servicio de hosting lo "normal" es que no te permitan cambiar dicho tiempo de ejecución o te llamen la atención los Srs. administradores de ese servidor por exceso de recursos.

Por otro lado .. el consumo de "memoria" podría ser elevado en cantidades grandes de envios .. ojo con eso .. ese dato no se puede cambiar por código sino por configuración de PHP (php.ini).

Por cierto .. tu proveedor no te exige autentificación para usar su servidor SMTP? .. Ya que dices:

$mail->Mailer = "smtp";

tendrás que configurar tu servidor SMTP a usar y si corresponde su autentificación (eso en más variables de PHPMailer).

Un saludo,
__________________
Por motivos personales ya no puedo estar con Uds. Fue grato haber compartido todos estos años. Igualmente los seguiré leyendo.
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Tema Cerrado




La zona horaria es GMT -6. Ahora son las 12:10.