PHP: envío de emails

10:38 manu 0 Comments




Si sois programadores de PHP y necesitáis enviar emails, no os perdáis este post que os puede ser de utilidad. Aquí os dejo la forma en la que yo programo siempre el envío de correos electrónicos. No es la única manera de hacerlo pero desde luego ésta es bastante efectiva.

Nunca envío el correo desde la página del usuario, es decir, cuando al usuario por ejemplo se le indica que pulse un botón para recibir una invitación o lo que sea, lo que hago es guardar una entrada en una tabla de bases de datos llamada emails, y al usuario le redirijo a una página donde le indico que en breve recibirá un correo. De otra manera el navegador se quedaría esperando a que la operación terminara dando una experiencia de usuario horrible.

La libreria que utilizo para enviar correos es la famosa PHPMailer. Podéis descargarosla haciendo clic aquí.

Para el envío de emails como se puede ver en la imagen superior utilizo tres clases y una pequeña tabla:
  • DBM.php (con las funciones que leer, escribir y borrar los emails de la tabla emails)
  • Utilidades.php (con la función que envía el correo)
  • Envio_correos.php (a este PHP lo llamaremos cada x minutos y será el encargado de enviar los correos mediante las dos clases anteriores, si es que los hubieras.
Vamos a ver las funciones de cada fichero:

1) DBM.php

Una sencilla inserción en la base de datos cada vez que la aplicación necesite enviar un correo.

function guardaCorreo($email,$titulo,$mensaje){
    $sql= "INSERT INTO emails (destinatario, titulo, contenido) VALUES (?,?,?)";
    $stmt = $this->conexion->prepare($sql);
    $stmt->bind_param('sss', $email, $titulo,$mensaje);
    $stmt->execute();
    $stmt->close();
}

Cogemos los emails de cinco en cinco para no saturar a la clase encargada de enviarlos. Para recoger la información podéis crearos vuestro objeto Email o usar un array como este ejemplo. Veréis que hay un campo llamado intentos. Lo incluyo porque después de cinco intentos de envío sin éxito lo elimino de la base de datos.

function getEmails(){
    $res=array();
    $i=0;
    $sql = "SELECT idemails, para, titulo, contenido, intentos FROM emails limit 5";
    if ($stmt = $this->conexion->prepare($sql)){
        $stmt->execute(); 
        $stmt->bind_result($idemails,$para,$titulo,$contenido,$intentos);
        while ($stmt->fetch()){
            $res[$i]["idemails"] = $idemails;
            $res[$i]["para"] = $para;
            $res[$i]["titulo"] = $titulo;
            $res[$i]["contenido"] = $contenido;
            $res[$i]["intentos"] = $intentos;
            $i++;
        } 
        $stmt->close(); 
    }
    return $res; 
}

Función para eliminar correos enviados o que han superado los intentos de envío. Aunque no soy muy amigo de los DELETE, esta es una de esas excepciones.

function borraEmail($idEmail){
    $sql = "DELETE FROM emails WHERE idemails=?";
    $stmt = $this->conexion->prepare($sql);
    $stmt->bind_param('i', $idEmail);
    $stmt->execute();
    $stmt->close(); 
}

2) Utilidades.php

Voy a poner el código para el envío desde Gmail y desde 1and1. Si tenéis otros servicio de correo o el vuestro propio posiblemente se ajuste a una de estas dos configuraciones.

require_once('utils/PHPMailer51/class.phpmailer.php');
require_once('utils/PHPMailer51/class.smtp.php');

function mandaCorreo($para, $titulo, $mensaje){

    // Inicializamos la clase PHPMailer
    $mail = new PHPMailer();  

    // Opciones genericas
    $mail->CharSet = 'UTF-8';
    $mail->IsHTML(true); // Si nuestro correo incluye tags HTML.

    // *********************** 
    // Configuramos para GMAIL (necesario modulo OPENSSL de PHP)
    // ***********************
    $mail->IsSMTP();     
    $mail->Host = "smtp.gmail.com";
    $mail->SMTPAuth = true; 
    $mail->SMTPSecure = "ssl";
    $mail->Port = 465;
 
    // *********************************
    // Configuracion para 1&1 (1and1) 
    // *********************************
    $mail->CharSet = 'UTF-8';
    $mail->isSendMail();
    $mail->Host = "smtp.portal.com"; // MUY IMPORTANTE SI NO QUEREMOS SER FILTRADOS POR SPAM
    $mail->Port = 465;
 
    // Datos del emisor (nosotros)
    $mail->Username = "mi_cuenta_de@gmail.com";
    $mail->Password = "mi_password_de_gmail";
 
    $mail->From     = $mail->Username;
    $mail->FromName = "Nuestro nombre"; 
 
    // Datos del receptor
    $mail->AddAddress("usuario@portal.com");
    $mail->Subject  = "Titulo del correo";
    $mail->Body     = "Contenido del correo.";
 
    // Enviamos el correo
    if ($mail->Send()){
        error_log("Enviado con éxito");
        return true;
    }else{
        error_log("Error en el envío");
        return false;
    }
    
}
Asegurate de tener activado el módulo OPENSSL si vas a usar Gmail. Edita el fichero php.ini de tu instalación de PHP y busca la línea extension=php_openssl.dll, descoméntala si estuviera comentada.

3) Envio_correos.php

Este es el PHP al que llamaremos cada x minutos para que revise y envíe los emails de la tabla Emails:

require_once('utils/dbmanager.php');
require_once('utils/utils.php');

$dbm = new DBM();
$util = new Utilidades();

$emails = $dbm->getEmails();
for ($i=0; $i<count($emails); $i++){
    $exito = $u->mandaCorreo($emails[$i]["para"], $emails[$i]["titulo"], $contenido);
    if ($exito || $emails[$i]["intentos"]==5)
        $dbm->borraEmail($emails[$i]["idemails"],$emails[$i]["para"],$exito); 
    else
        $dbm->addIntentoEmail($emails[$i]["idemails"]);
}

Pues esto es todo. Sólo faltaría inlcuir en el cron una llamada a la url de envío de correos y listo. Por ejemplo así:

wget --spider "http://tudireccion.com/Envio_correos.php" &> /dev/null

0 comentarios: