Gestor de Correos (2)

PostReader

Porque me lo solicitó un desarrollador y porque en mi vida profesional no lo había programado, he hecho este ejemplo para tratar correos electrónicos, leyendo los mismos desde una cuenta de GMAIL y enviado nuevos correos a través de la misma cuenta.

El ejemplo lo he orientado a un soporte o gestor de incidentes (HelpDesk) a usuarios de un sistema donde su medio de notificar problemas y recibir contestación es el correo electrónico. Como siempre os indico, esto no es una aplicación, si no un ejemplo que deberéis personalizar para vuestros requisitos.

Objetivo

El objetivo que he marcado es facilitar código simple y eficiente para que desde PHPRunner podamos leer los mensajes que llegan a una cuenta de correo de Gmail y enviar mensajes de email a las personas que hicieron su consulta previamente.

Para aquellos que quieran recibir y enviar correos desde PHPRunner, este será un ejemplo que les facilita dichas funciones.

Funcionalidad del ejemplo

 DEMO:  https://fhumanes.com/postreader/

Las políticas de las cuentas de GMAIL han cambiado. He tenido que solicitar una password de aplicación, para que los ejemplos funcionen

Usuario: user1 y password: user1  .

La cuenta de correo que utiliza y a la que se puede enviar mensajes de prueba es: [email protected]

El ejemplo tiene una opción de «Configuración» que permite configurar el ejemplo en las características de las cuentas de correo, buzón destino de los mensajes, directorio de los archivos, etc.

La opción importante es la de «email», que es la que se muestra. He utilizado unas bolas amarillas para señalar los puntos más relevantes que paso a describir.

(1) .- Con este botón naranja, el aplicativo revisa y recupera los mensajes de [email protected]. Para el ejemplo, se ejecuta directamente desde el botón, pero para un sistema productivo se debería incluir en el CRON y ejecutarse como mucho cada 5 minutos. Los cambios necesarios son sencillos y si tenéis dudas o problemas, decídmelo y os los hago yo.

(2) .- Como ejemplo, se ha puesto que el mensaje puede estar relacionado con:

  • Contactos .- Serían los datos generales de todos los usuarios del sistema. La relación es por el email.
  • Otros mensajes .- Otros mensajes que hay en el sistema con esta misma cuenta de email.
  • Respuestas.-  Desde este enlace  creamos y consultamos las gestiones y respuesta que hemos hecho sobre este mensaje. Por cada registro de Respuesta, el ejemplo envía un email a la cuenta originaria del mensaje.

(3).-  Estado en que se encuentra el mensaje. Este estado se va actualizando con las respuestas que se van haciendo.

Solución técnica

Como siempre hago, intento buscar una librería PHP que haga la funcionalidad que requiero, en este caso he utilizado:

  • phpmailer 6.1 .- Para el envío de los mensajes. https://github.com/PHPMailer/PHPMailer
  • php-imap 4.1, de Sergey Barbushin.- Para la lectura de los mensajes y su movimiento al buzón de archivados.  https://github.com/barbushin/php-imap/

Os muestro el código más importante que tiene el ejemplo:

Leer los mensajes

read_mail.php
 
<?php
  /**
     * Example: Get and parse all unseen emails with saving their attachments one by one.
     *
     * @author Sebastian Krätzig <[email protected]>
     */
      
    global $conn;
     
    require_once __DIR__.'/../php-imap_4.1.0/autoload.php';
    use PhpImap\Exceptions\ConnectionException;
    use PhpImap\Mailbox;
    // Load variables of Config
    $serverMail       = $_SESSION['config'][array_search('GMAIL_server', array_column($_SESSION['config'], 'name'))][value];
    $login             = $_SESSION['config'][array_search('GMAIL_Username', array_column($_SESSION['config'], 'name'))][value];
    $password             = $_SESSION['config'][array_search('GMAIL_Password', array_column($_SESSION['config'], 'name'))][value];
    $buzonArchivo       = $_SESSION['config'][array_search('ARCHIVE_Mailbox', array_column($_SESSION['config'], 'name'))][value];
    $directoryAttachments = $_SESSION['config'][array_search('FOLDER_FILES', array_column($_SESSION['config'], 'name'))][value];
     
    $dateEmail = '' ;
    $from_name = '';
    $from_email = '';
    $to = '';
    $subject = '';
    $message = '';
     
    $message_id = '';
    $num_message = 0;
     
    $mailbox = new Mailbox(
        $serverMail, // IMAP server and mailbox folder
        $login, // Username for the before configured mailbox
        $password // Password for the before configured username
    );
    try {
        $mail_ids = $mailbox->searchMailbox('UNSEEN');
    } catch (ConnectionException $ex) {
        die('IMAP connection failed: '.$ex->getMessage());
    } catch (Exception $ex) {
        die('An error occured: '.$ex->getMessage());
    }
   
    foreach ($mail_ids as $mail_id) {
        $email = $mailbox->getMail(
            $mail_id, // ID of the email, you want to get
            true // Do NOT mark emails as seen (optional)
        );
        $from_name = (isset($email->fromName) ? $email->fromName : $email->fromAddress);
        $from_email = $email->fromAddress;
        $to = $email->toString;
        $subject = $email->subject; 
        $message_id = $email->messageId;
        $dateEmail = date("Y-m-d H:i:s", strtotime($email->date));
        // Save attachments one by one
        if (!$mailbox->getAttachmentsIgnore()) {
            $attachments = $email->getAttachments();
             
            $num_attachment = 0;
                                     $fileAttachment = [];
            foreach ($attachments as $attachment) {
                $usrName = $attachment->name;
                                                 $extension = $attachment->subtype;
                $name = $directoryAttachments.'/'.time().'_'.str_replace(' ', '_', $usrName); 
                $pathFile = substr(__DIR__, 0, -4).'/'.$name;
                $attachment->setFilePath($pathFile);
                if ($attachment->saveToDisk()) {
                    // echo "OK, saved!\n";
                } else {
                    // echo "ERROR, could not save!\n";
                }
                $size = filesize($pathFile);
                 
                // Mime Type
                $sql = "SELECT MimeType FROM mime_type where Extension = lower('$extension')";
                $rs = $conn->query($sql);
                if ($data = $rs->fetch_assoc()) {
                    $type = $data[MimeType];
                    } else {
                    $type = 'application/octet-stream';
                };
                 
                $fileAttachment[$num_attachment][name]= $name;
                $fileAttachment[$num_attachment][usrName]= $usrName;
                $fileAttachment[$num_attachment][size]= $size;
                $fileAttachment[$num_attachment][type]= $type;
                $fileAttachment[$num_attachment][searchStr] = $usrName.',!:sStrEnd'; 
                 
                $num_attachment = $num_attachment + 1;                               
            }
        }
        if ($email->textHtml) {
            $message = $email->textHtml;
        } else {
            $message = $email->textPlain;
        }
        if (!empty($email->autoSubmitted)) {
            // Mark email as "read" / "seen"
            $mailbox->markMailAsRead($mail_id);
        }
        if (!empty($email_content->precedence)) {
            // Mark email as "read" / "seen"
            $mailbox->markMailAsRead($mail_id);
        }       
         
        $mailbox->moveMail($mail_id,$buzonArchivo); 
         
        $sql = "insert INTO  email (FromEmail, FromName, toEmail, Date, Subject, Message, Attachment) values
        (?,?,?,?,?,?,?)";
                         $rs = $conn->prepare($sql);
                         $rs->bind_param('sssssss', $from_email, $from_name, $to, $dateEmail, $subject, $message, $attachment);
                         $attachment = my_json_encode($fileAttachment);
                         // $subject = addslashes($conn->real_escape_string($subject));
                         // $message = addslashes($conn->real_escape_string($message));
                         $rs->execute();
        $num_message = $num_message + 1;
    }
    $mailbox->disconnect();

Enviar nuevos mensajes

send_mail.php
<?php
// For send of email response
// field of Config
$GMAIL_Username = $_SESSION['config'][array_search('GMAIL_Username', array_column($_SESSION['config'], 'name'))][value];
$GMAIL_Password = $_SESSION['config'][array_search('GMAIL_Password', array_column($_SESSION['config'], 'name'))][value];
$GMAIL_setFrom_email = $_SESSION['config'][array_search('GMAIL_setFrom_email', array_column($_SESSION['config'], 'name'))][value];$GMAIL_Username = $_SESSION['config'][array_search('GMAIL_Username', array_column($_SESSION['config'], 'name'))][value];
$GMAIL_setFrom_name = $_SESSION['config'][array_search('GMAIL_setFrom_name', array_column($_SESSION['config'], 'name'))][value];
//Import PHPMailer classes into the global namespace
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
require __DIR__.'/../phpmailer_6.1/autoload.php';
//Create a new PHPMailer instance
$mail = new PHPMailer;
// Activo condificacción utf-8
$mail->CharSet = 'UTF-8';
//Tell PHPMailer to use SMTP
$mail->isSMTP();
//Enable SMTP debugging
// SMTP::DEBUG_OFF = off (for production use)
// SMTP::DEBUG_CLIENT = client messages
// SMTP::DEBUG_SERVER = client and server messages
$mail->SMTPDebug = SMTP::DEBUG_OFF;
//Set the hostname of the mail server
$mail->Host = 'smtp.gmail.com';
// use
// $mail->Host = gethostbyname('smtp.gmail.com');
// if your network does not support SMTP over IPv6
//Set the SMTP port number - 587 for authenticated TLS, a.k.a. RFC4409 SMTP submission
$mail->Port = 587;
//Set the encryption mechanism to use - STARTTLS or SMTPS
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
//Whether to use SMTP authentication
$mail->SMTPAuth = true;
//Username to use for SMTP authentication - use full email address for gmail
$mail->Username = $GMAIL_Username;
//Password to use for SMTP authentication
$mail->Password = $GMAIL_Password;
//Set who the message is to be sent from
$mail->setFrom($GMAIL_setFrom_email,$GMAIL_setFrom_name);
//Set an alternative reply-to address
// $mail->addReplyTo('[email protected]', 'First Last');
//Set the subject line
$mail->Subject = $values['Subject'];
//Read an HTML message body from an external file, convert referenced images to embedded,
//convert HTML into a basic plain-text alternative body
$message = $values['Message'];
// $mail->msgHTML($message);
/*
// Attachments
$filesArray = my_json_decode($masterData['attachments']);
foreach ($filesArray as $File) {
      $mail->addAttachment(__DIR__."/../".$File["name"],$File["usrName"],'base64', $File["type"]);
}
*/
$mail->msgHTML($message);
//  $mail->AltBody = $mail->html2text($message0); // Text plain alternative
$mail->addAddress($values['toEmail'], $values['toName']);
$status = $mail->send();
$a='';
?>

Como siempre, para cualquier duda o consulta, escribidme a mi email [email protected]

Os dejo el proyecto, para que podáis ejecutar en vuestros equipos.

Adjuntos

Archivo Tamaño de archivo Descargas
zip backup de la base de datos 28 KB 868
zip PHPRunner 10.4 960 KB 918
zip PHPRunner 10.7 - Actualizado: 25/08/2022 1.012 KB 341

Blog personal para facilitar soporte gratuito a usuarios de React y PHPRunner