2008-08-15 22 views
24

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

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 que me indiquen PEAR/PECL, necesito el código actual. Mi anfitrión tiene algunas configuraciones confusas o algo así, parece que nunca puedo obtener el .so's para compilar correctamente. Si obtengo el .so, alguna diferencia en path/environment/php.ini no siempre está disponible (apache vs cron vs cli).

Ah, y una última cosa, estoy analizando el texto del correo electrónico sin procesar, NO POP3, y NO IMAP. Está siendo canalizado en la secuencia de comandos php a través de un redireccionamiento de correo electrónico .qmail.

No estoy esperando SOF para escribirlo para mí, estoy buscando algunos consejos/puntos de partida para hacerlo "bien". Este es uno de esos problemas de "rueda" que sé que ya se resolvió.

Respuesta

19

¿Qué esperas terminar al final? El cuerpo, el sujeto, el remitente, un archivo adjunto? Usted debe pasar algún tiempo con RFC2822 de entender el formato del correo, pero aquí están las reglas más simples para el correo electrónico bien formada:

HEADERS\n 
\n 
BODY 

Es decir, la primera línea en blanco (doble salto de línea) es el separador entre los encabezados y el cuerpo. Un CABECERA se ve así:

HSTRING:HTEXT 

hstring siempre comienza al principio de una línea y no contiene ningún espacio en blanco o dos puntos. HTEXT puede contener una amplia variedad de texto, incluidas líneas nuevas, siempre que la nueva línea sea seguida por espacios en blanco.

El "CUERPO" es realmente cualquier dato que sigue a la primera doble línea nueva. (Hay reglas diferentes si está transmitiendo correo a través de SMTP, pero si lo procesa en una tubería, no tiene que preocuparse por eso).

Así, en muy simple, alrededor de 1982-RFC822 términos, un correo electrónico es el siguiente:

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

THIS IS ANY 
ARBITRARY DATA 
(FOR THE MOST PART) 

La mayoría de correo electrónico moderno es más complejo que eso sin embargo. Los encabezados pueden codificarse para conjuntos de caracteres o palabras de mimo RFC2047, o un montón de otras cosas en las que no estoy pensando en este momento. Los cuerpos son realmente difíciles de rodar tu propio código en estos días si quieres que sean significativos. Casi todos los correos electrónicos generados por un MUA estarán codificados en MIME. Eso podría ser un texto cifrado, podría ser html, podría ser una hoja de cálculo excel de uuencoded.

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

0

Sí, he podido escribir un analizador básico, basado en ese rfc y algunos otros tutoriales básicos. pero son los mitades anidados en múltiples partes los que continúan arruinándome.

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

porque el sistema está diseñado para enviar imágenes, tiene un montón de piezas codificadas de forma diferente. una parte mms.smil.txt, un texto/plano (que es inútil, simplemente dice 'este es un mensaje html'), una parte de la aplicación/smil (que la parte que los teléfonos verían), una parte text/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 pone en archivo adjunto 1, codificado en base64, luego mi parte de texto se adjunta como archivo adjunto 2)

lo tenía trabajando con el formato de correo exacto de mi operador, pero cuando ejecuté un mensaje de alguien más por él, falló en una todo un montón de maneras miserables.

tengo otros proyectos me gustaría extender este sistema de comando de teléfono-> correo-> parse->, pero necesito tener un analizador estable/sólido/genérico para obtener las diferentes partes del correo a usarlo

mi objetivo final sería tener una función en la que pudiera alimentar el correo sin procesar, y obtener una gran matriz con sub-arrays asociativos de encabezados var: val pairs, y uno para el texto del cuerpo como un todo cadena

Cuanto más busco en esto, más encuentro lo mismo: paquetes de manejo de correo gigante sobredesarrollado que hacen todo lo que está bajo el sol relacionado con los correos, o inservibles (para mí, en este proyecto) tutoriales.

Creo que voy a tener que morder la bala y escribir algo solo.

1

Probablemente no se va a divertir mucho escribiendo su propio analizador MIME. La razón por la que está encontrando "paquetes de manejo de correo sobredesarrollado" 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 es escribir el mejor controlador MIME posible, analizar un mensaje, descartar todo lo que no sea text/plain o text/html, y luego forzar el comando en la cadena entrante que se prefija con COMMAND: o algo similar para que pueda encontrarlo en el lodo. Si comienzas con reglas como esa, tienes una buena posibilidad de manejar nuevos proveedores, pero deberías estar listo para modificar si aparece un nuevo proveedor (o diablos, si tu proveedor actual elige cambiar su arquitectura de mensajería).

1

No estoy seguro de si esto será útil para usted, eso espero, pero seguramente ayudará a otros interesados ​​en obtener más información sobre el correo electrónico. Marcus Bointon hizo una de las mejores presentaciones tituladas "Mail() y life after Mail()" en la conferencia PHP London en marzo de este año y slides y MP3 están en línea. Habla con cierta autoridad, ya que trabajó extensamente con correo electrónico y PHP a un nivel profundo.

Mi percepción es que estás en un mundo de dolor tratando de escribir un analizador verdaderamente genérico.

EDITAR - Parece que los archivos se han eliminado en el sitio de PHP London; Encontramos las diapositivas sobre Marcus own site: Part 1Part 2 no podía ver el MP3 en cualquier lugar, aunque

1

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

El problema es que las funciones predeterminadas de imap_ * de PHP no proporcionan mucha granularidad ... así que tuve que abrir un socket al 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 de RFC.

Se le proporciona la codificación de los datos (quoted-printable, base64, 7bit, 8bit, etc.), la longitud del mensaje, el tipo de contenido, etc. para archivos adjuntos, texto, html, etc. Puede que tenga que descubrir los matices de su servidor de correo también, ya que no todos los campos están siempre implementados al 100%.

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

Espero que esto ayude!

4

He improvisado esto, un código no es mío, pero no sé de dónde vino ... Más tarde adopté el más robusto "MimeMailParser", pero esto funciona bien, canalizo mi correo electrónico predeterminado al mismo usando cPanel y funciona genial

#!/usr/bin/php -q 
<?php 
// Config 
$dbuser = 'emlusr'; 
$dbpass = 'pass'; 
$dbname = 'email'; 
$dbhost = 'localhost'; 
$notify= '[email protected]'; // 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([email protected]_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()); 
} 
?> 
+0

Me gusta este enfoque, y funciona bastante bien en su mayor parte. Sin embargo, he notado en la solución de problemas que no manejará las líneas de encabezado de envoltura, por ejemplo, si las direcciones a: usan más de una línea. –

17

Prueba el Plancake PHP Email analizador: https://github.com/plancake/official-library-php-email-parser

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

+0

gran biblioteca dan! ¿cómo te deshaces de los caracteres tipo = 23 y = 40? – cwd

+0

@cwd es una codificación de texto entre comillas, supongo. –

+2

Estoy usando esta lib y funciona el 90% de las veces, pero no el 100% ... – behz4d

2

El lib Mail_mimeDecode pera está escrito en PHP claro que se puede ver aquí: Mail_mimeDecode source

+0

el enlace debe ser http://svn.php.net/viewvc/pear/packages/Mail_mimeDecode/trunk/Mail/mimeDecode.php?revision=337165&view=markup – chiliNUT

+0

por cierto esta biblioteca es excelente – chiliNUT

2

hay una biblioteca para analizar el mensaje de correo electrónico en bruto en php array - http://flourishlib.com/api/fMailbox#parseMessage.

El parseMessage método estático() puede utilizarse para analizar un mensaje de correo electrónico completa MIME en el mismo formato que los rendimientos fetchMessage(), menos la tecla UID.

$ parsed_message = fMailbox :: parseMessage (file_get_contents ('/ path/to/email'));

Aquí es 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' => '<[email protected]>', 
     '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 
); 
+0

¡Funciona como un encanto! 8-) –

0

me encontré con el mismo problema así que escribí la siguiente clase: Email_Parser. Toma un correo electrónico sin formato y lo convierte en un objeto agradable.

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

Consíguelo aquí: https://github.com/optimumweb/php-email-reader-parser

2

Este https://github.com/zbateson/MailMimeParser funciona para mí, y no es necesario mailparse extensión.

<?php 
echo $message->getHeaderValue('from');   // [email protected] 
echo $message 
    ->getHeader('from') 
    ->getPersonName();       // Person Name 
echo $message->getHeaderValue('subject');  // The email's subject 

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

PhpMimeParser simple https://github.com/breakermind/PhpMimeParser Yuo puede cortar los mensajes MIME de los archivos, cadena. 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); 
Cuestiones relacionadas