Pregunta

Estoy buscando un código php bueno, funcional y fácil de usar para analizar el correo electrónico sin procesar en partes.

He escrito un par de soluciones de fuerza bruta, pero cada vez, aparece un pequeño cambio/encabezado/espacio/algo y todo mi analizador falla y el proyecto se desmorona.

Y antes de señalar PEAR/PECL, necesito el código real.Mi host tiene alguna configuración complicada o algo así, parece que nunca puedo lograr que los .so se construyan correctamente.Si consigo crear el .so, alguna diferencia en path/environment/php.ini no siempre lo hace disponible (apache vs cron vs cli).

Ah, y una última cosa, estoy analizando el texto sin formato del correo electrónico, NO POP3 ni IMAP.Se está canalizando al script php a través de una redirección de correo electrónico .qmail.

No espero que SOF lo escriba por mí, estoy buscando algunos consejos/puntos de partida para hacerlo "bien".Este es uno de esos problemas de "ruedas" que sé que ya se ha solucionado.

¿Fue útil?

Solución

¿Con qué esperas terminar al final?¿El cuerpo, el sujeto, el remitente, un archivo adjunto?Deberías pasar algún tiempo con RFC2822 comprender el formato del correo, pero estas son las reglas más simples para un correo electrónico bien formado:

HEADERS\n
\n
BODY

Es decir, la primera línea en blanco (doble nueva línea) es el separador entre los ENCABEZADOS y el CUERPO.UN ENCABEZADO se parece a esto:

HSTRING:HTEXT

HSTRING siempre comienza al principio de una línea y no contiene espacios en blanco ni dos puntos.HTEXT puede contener una amplia variedad de texto, incluidas nuevas líneas, siempre que el carácter de nueva línea vaya seguido de espacios en blanco.

El "CUERPO" es en realidad cualquier dato que sigue a la primera doble nueva línea.(Existen reglas diferentes si transmite correo a través de SMTP, pero al procesarlo a través de una tubería no tiene que preocuparse por eso).

Entonces, en términos muy simples, alrededor de 1982. RFC822 términos, un correo electrónico se ve así:

HEADER: HEADER TEXT
HEADER: MORE HEADER TEXT
  INCLUDING A LINE CONTINUATION
HEADER: LAST HEADER

THIS IS ANY
ARBITRARY DATA
(FOR THE MOST PART)

Sin embargo, la mayoría del correo electrónico moderno es más complejo que eso.Los encabezados se pueden codificar para conjuntos de caracteres o RFC2047 palabras mímicas o un montón de otras cosas en las que no estoy pensando en este momento.Es realmente difícil implementar su propio código en los cuerpos en estos días si desea que sean significativos.Casi todo el correo electrónico generado por un MUA será MÍMICA codificado.Podría ser texto no codificado, podría ser html, podría ser una hoja de cálculo de Excel no codificada.

Espero que esto ayude a proporcionar un marco para comprender algunos de los componentes más elementales del correo electrónico.Si proporciona más antecedentes sobre lo que está tratando de hacer con los datos, yo (u otra persona) podría brindarle una mejor dirección.

Otros consejos

Pruebe el analizador de correo electrónico PHP de Plancake:https://github.com/plancake/official-library-php-email-parser

Lo he usado para mis proyectos.Funciona muy bien, es solo una clase y es de código abierto.

Imprevisé esto, algún código no es mío pero no sé de dónde vino...Más tarde adopté el "MimeMailParser" más robusto, pero funciona bien, le envío mi correo electrónico predeterminado usando cPanel y funciona muy bien.

#!/usr/bin/php -q
<?php
// Config
$dbuser = 'emlusr';
$dbpass = 'pass';
$dbname = 'email';
$dbhost = 'localhost';
$notify= 'services@.com'; // an email address required in case of errors
function mailRead($iKlimit = "") 
    { 
        // Purpose: 
        //   Reads piped mail from STDIN 
        // 
        // Arguements: 
        //   $iKlimit (integer, optional): specifies after how many kilobytes reading of mail should stop 
        //   Defaults to 1024k if no value is specified 
        //     A value of -1 will cause reading to continue until the entire message has been read 
        // 
        // Return value: 
        //   A string containing the entire email, headers, body and all. 

        // Variable perparation         
            // Set default limit of 1024k if no limit has been specified 
            if ($iKlimit == "") { 
                $iKlimit = 1024; 
            } 

            // Error strings 
            $sErrorSTDINFail = "Error - failed to read mail from STDIN!"; 

        // Attempt to connect to STDIN 
        $fp = fopen("php://stdin", "r"); 

        // Failed to connect to STDIN? (shouldn't really happen) 
        if (!$fp) { 
            echo $sErrorSTDINFail; 
            exit(); 
        } 

        // Create empty string for storing message 
        $sEmail = ""; 

        // Read message up until limit (if any) 
        if ($iKlimit == -1) { 
            while (!feof($fp)) { 
                $sEmail .= fread($fp, 1024); 
            }                     
        } else { 
            while (!feof($fp) && $i_limit < $iKlimit) { 
                $sEmail .= fread($fp, 1024); 
                $i_limit++; 
            }         
        } 

        // Close connection to STDIN 
        fclose($fp); 

        // Return message 
        return $sEmail; 
    }  
$email = mailRead();

// handle email
$lines = explode("\n", $email);

// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;
for ($i=0; $i < count($lines); $i++) {
    if ($splittingheaders) {
        // this is a header
        $headers .= $lines[$i]."\n";

        // look out for special headers
        if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) {
            $subject = $matches[1];
        }
        if (preg_match("/^From: (.*)/", $lines[$i], $matches)) {
            $from = $matches[1];
        }
        if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
            $to = $matches[1];
        }
    } else {
        // not a header, but message
        $message .= $lines[$i]."\n";
    }

    if (trim($lines[$i])=="") {
        // empty line, header section has ended
        $splittingheaders = false;
    }
}

if ($conn = @mysql_connect($dbhost,$dbuser,$dbpass)) {
  if(!@mysql_select_db($dbname,$conn))
    mail($email,'Email Logger Error',"There was an error selecting the email logger database.\n\n".mysql_error());
  $from    = mysql_real_escape_string($from);
  $to    = mysql_real_escape_string($to);
  $subject = mysql_real_escape_string($subject);
  $headers = mysql_real_escape_string($headers);
  $message = mysql_real_escape_string($message);
  $email   = mysql_real_escape_string($email);
  $result = @mysql_query("INSERT INTO email_log (`to`,`from`,`subject`,`headers`,`message`,`source`) VALUES('$to','$from','$subject','$headers','$message','$email')");
  if (mysql_affected_rows() == 0)
    mail($notify,'Email Logger Error',"There was an error inserting into the email logger database.\n\n".mysql_error());
} else {
  mail($notify,'Email Logger Error',"There was an error connecting the email logger database.\n\n".mysql_error());
}
?>

Hay funciones de Mailparse que puedes probar: http://php.net/manual/en/book.mailparse.php, sin embargo, no en la configuración predeterminada de php.

Hay una biblioteca para analizar mensajes de correo electrónico sin procesar en una matriz php: http://flourishlib.com/api/fMailbox#parseMessage.

El método estático parsemessage () se puede usar para analizar un mensaje de correo electrónico mime completo en el mismo formato que devuelve FetchMessage (), menos la clave UID.

$ parsed_message = fmailbox :: parsemessage (file_get_contents ('/path/to/email'));

A continuación se muestra un ejemplo de un mensaje analizado:

array(
    'received' => '28 Apr 2010 22:00:38 -0400',
    'headers'  => array(
        'received' => array(
            0 => '(qmail 25838 invoked from network); 28 Apr 2010 22:00:38 -0400',
            1 => 'from example.com (HELO ?192.168.10.2?) (example) by example.com with (DHE-RSA-AES256-SHA encrypted) SMTP; 28 Apr 2010 22:00:38 -0400'
        ),
        'message-id' => '<4BD8E815.1050209@flourishlib.com>',
        'date' => 'Wed, 28 Apr 2010 21:59:49 -0400',
        'from' => array(
            'personal' => 'Will Bond',
            'mailbox'  => 'tests',
            'host'     => 'flourishlib.com'
        ),
        'user-agent'   => 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.9) Gecko/20100317 Thunderbird/3.0.4',
        'mime-version' => '1.0',
        'to' => array(
            0 => array(
                'mailbox' => 'tests',
                'host'    => 'flourishlib.com'
            )
        ),
        'subject' => 'This message is encrypted'
    ),
    'text'      => 'This message is encrypted',
    'decrypted' => TRUE,
    'uid'       => 15
);

Este https://github.com/zbateson/MailMimeParser funciona para mí y no necesita la extensión mailparse.

<?php
echo $message->getHeaderValue('from');          // user@example.com
echo $message
    ->getHeader('from')
    ->getPersonName();                          // Person Name
echo $message->getHeaderValue('subject');       // The email's subject

echo $message->getTextContent();                // or getHtmlContent

Pear lib Mail_mimeDecode está escrito en PHP simple que puedes ver aquí: Fuente Mail_mimeDecode

Probablemente no te divertirás mucho escribiendo tu propio analizador MIME.La razón por la que encuentra "paquetes de manejo de correo demasiado desarrollados" es porque MIME es un conjunto realmente complejo de reglas/formatos/codificaciones.Las partes MIME pueden ser recursivas, lo cual es parte de la diversión.Creo que lo mejor que puede hacer es escribir el mejor controlador MIME que pueda, analizar un mensaje, descartar todo lo que no sea texto/sin formato o texto/html y luego forzar que el comando en la cadena entrante tenga el prefijo COMMAND:o algo similar para que puedas encontrarlo en la basura.Si comienza con reglas como esa, tiene buenas posibilidades de manejar nuevos proveedores, pero debe estar preparado para modificar si aparece un nuevo proveedor (o diablos, si su proveedor actual decide cambiar su arquitectura de mensajería).

Analizar el correo electrónico en PHP no es una tarea imposible.Lo que quiero decir es que no necesitas un equipo de ingenieros para hacerlo;es alcanzable como individuo.Realmente la parte más difícil que encontré fue crear el FSM para analizar un resultado de IMAP BODYSTRUCTURE.En ningún lugar de Internet había visto esto, así que escribí el mío.Mi rutina básicamente crea una matriz de matrices anidadas a partir de la salida del comando, y la profundidad a la que se encuentra en la matriz corresponde aproximadamente a los números de pieza necesarios para realizar las búsquedas.Por lo tanto, maneja las estructuras MIME anidadas con bastante gracia.

El problema es que las funciones imap_* predeterminadas de PHP no proporcionan mucha granularidad... así que tuve que abrir un socket en el puerto IMAP y escribir las funciones para enviar y recuperar la información necesaria (IMAP FETCH 1 BODY.PEEK[1.2] por ejemplo), y eso implica mirar la documentación RFC.

La codificación de los datos (entre comillas, imprimible, base64, 7 bits, 8 bits, etc.), longitud del mensaje, tipo de contenido, etc.todo se le proporciona;para archivos adjuntos, texto, html, etc.Es posible que también tengas que descubrir los matices de tu servidor de correo, ya que no todos los campos siempre se implementan al 100%.

La joya es el FSM... si tienes experiencia en Comp Sci, puede ser muy divertido hacer esto (la clave es que los corchetes no son una gramática normal;));de lo contrario, será una lucha y/o resultará en un código feo, utilizando métodos tradicionales.¡También necesitas algo de tiempo!

¡Espero que esto ayude!

No estoy seguro de si esto le será de ayuda (espero que sí), pero seguramente ayudará a otros interesados ​​en saber más sobre el correo electrónico. Marcos Bointon Hizo una de las mejores presentaciones titulada "Mail() y la vida después de Mail()" en la conferencia PHP de Londres en marzo de este año y la diapositivas y MP3 están en línea.Habla con cierta autoridad, ya que ha trabajado extensamente con correo electrónico y PHP a un nivel profundo.

Mi percepción es que te espera un mundo de dolor al intentar escribir un analizador verdaderamente genérico.

EDITAR: los archivos parecen haber sido eliminados en el sitio PHP de Londres;Encontré las diapositivas de Marcus. propio sitio: Parte 1 Parte 2 Aunque no pude ver el MP3 por ninguna parte.

Sí, pude escribir un analizador básico, basado en ese rfc y algunos otros tutoriales básicos.pero son los límites anidados del mimo de varias partes los que siguen confundiéndome.

Descubrí que los mensajes MMS (no SMS) enviados desde mi teléfono son solo correos electrónicos estándar, por lo que tengo un sistema que lee el correo electrónico entrante, verifica el origen (para permitir solo desde mi teléfono) y usa la parte del cuerpo para ejecutar diferentes comandos en mi servidor.Es algo así como un control remoto por correo electrónico.

Debido a que el sistema está diseñado para enviar imágenes, tiene un montón de partes codificadas de manera diferente.una parte mms.smil.txt, una parte de texto/sin formato (que es inútil, solo dice "este es un mensaje html"), una parte de aplicación/smil (que es la parte que los teléfonos captarían), una parte de texto/html con un anuncio de mi operador, luego mi mensaje, pero todo envuelto en html, y finalmente un archivo de texto adjunto con mi mensaje simple (que es la parte que uso) (si inserto una imagen como archivo adjunto en el mensaje, se coloca en archivo adjunto 1, codificado en base64, luego mi parte de texto se adjunta como archivo adjunto 2)

Lo tenía funcionando con el formato de correo exacto de mi proveedor, pero cuando envié un mensaje desde el teléfono de otra persona, falló de muchas maneras miserables.

Tengo otros proyectos a los que me gustaría ampliar este teléfono->correo->análisis->sistema de comando, pero necesito tener un analizador estable/sólido/genérico para sacar las diferentes partes del correo para usarlo.

Mi objetivo final sería tener una función en la que pudiera alimentar el correo canalizado sin procesar y obtener una gran matriz con submatrices asociativas de pares de encabezados var:val, y una para el texto del cuerpo como una cadena completa.

Cuanto más busco sobre esto, más encuentro lo mismo:Paquetes gigantes de manejo de correo sobredesarrollados que hacen todo lo relacionado con el correo electrónico, o tutoriales inútiles (para mí, en este proyecto).

Creo que tendré que hacer de tripas corazón y escribir algo con cuidado yo mismo.

Me encontré con el mismo problema, así que escribí la siguiente clase:Correo electrónico_Parser.Toma un correo electrónico sin procesar y lo convierte en un bonito objeto.

Requiere PEAR Mail_mimeDecode, pero debería ser fácil de instalar a través de WHM o directamente desde la línea de comandos.

Consiguelo aqui : https://github.com/optimumweb/php-email-reader-parser

PhpMimeParser simple https://github.com/breakermind/PhpMimeParser Yuo puede cortar mensajes mimo de archivos y cadenas.Obtenga archivos, html e imágenes en línea.

$str = file_get_contents('mime-mixed-related-alternative.eml');

// MimeParser
$m = new PhpMimeParser($str);

// Emails
print_r($m->mTo);
print_r($m->mFrom);

// Message
echo $m->mSubject;
echo $m->mHtml;
echo $m->mText;

// Attachments and inline images
print_r($m->mFiles);
print_r($m->mInlineList);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top