2008-08-15 10 views
24

Sto cercando un codice php valido/funzionante/semplice da utilizzare per analizzare le e-mail non elaborate in parti.analizzando l'email non elaborata in php

Ho scritto un paio di soluzioni di forza bruta, ma ogni volta, una piccola modifica/intestazione/spazio/qualcosa arriva e il mio intero parser fallisce e il progetto va in pezzi.

E prima che venga indicato PEAR/PECL, ho bisogno del codice attuale. Il mio ospite ha qualche confusa configurazione o qualcosa del genere, non riesco mai a ottenere il .so per costruire correttamente. Se ottengo il .so, alcune differenze in path/environment/php.ini non rendono sempre disponibile (apache vs cron vs cli).

Oh, e un'ultima cosa, sto analizzando il testo e-mail non elaborato, NON POP3 e NON IMAP. Viene convogliato nello script php tramite un reindirizzamento email .qmail.

Non mi aspetto che SOF lo scriva per me, sto cercando alcuni suggerimenti/punti di partenza per farlo "giusto". Questo è uno di quei problemi della "ruota" che so essere già stato risolto.

risposta

19

Che cosa speri di concludere alla fine? Il corpo, il soggetto, il mittente, un attaccamento? Si dovrebbe passare un po 'di tempo con RFC2822 per capire il formato della posta, ma ecco le regole più semplici per email ben formato:

HEADERS\n 
\n 
BODY 

Cioè, la prima riga vuota (doppio ritorno a capo) è il separatore tra le intestazioni ei il corpo. Un colpo di testa simile a questa:

HSTRING:HTEXT 

hstring inizia sempre all'inizio di una riga e non contiene alcun spazio bianco o due punti. HTEXT può contenere un'ampia varietà di testo, incluse le newline purché il carattere di nuova riga sia seguito da spazi bianchi.

Il "BODY" è in realtà solo tutti i dati che seguono il primo double newline. (Ci sono regole diverse se si sta trasmettendo la posta via SMTP, ma elaborandola su una pipe non ci si deve preoccupare di ciò).

Quindi, in realtà semplice, circa-1982 RFC822 termini, una e-mail simile a questa:

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

THIS IS ANY 
ARBITRARY DATA 
(FOR THE MOST PART) 

La maggior parte di posta elettronica moderna è più complesso di quello però. Le intestazioni possono essere codificate per charset o RFC2047 parole mime o una tonnellata di altre cose a cui non sto pensando in questo momento. I corpi sono davvero difficili da caricare il tuo codice per questi giorni se vuoi che siano significativi. Quasi tutte le e-mail generate da un MUA saranno codificate MIME. Potrebbe essere un testo uuencoded, potrebbe essere html, potrebbe essere un foglio di calcolo excel uuencoded.

Spero che questo aiuti a fornire un quadro per la comprensione di alcuni dei bucket molto elementari dell'e-mail. Se fornisci maggiori informazioni su ciò che stai cercando di fare con i dati che I (o qualcun altro) potrebbe essere in grado di fornire una direzione migliore.

0

sì, sono stato in grado di scrivere un parser di base, basato su quello rfc e alcuni altri tutorial di base. ma sono i confini mime multiparte che continuano a rovinarmi.

ho scoperto che i messaggi MMS (non SMS) inviati dal mio telefono sono solo e-mail standard, quindi ho un sistema che legge l'email in arrivo, controlla il da (per consentire solo dal mio telefono), e usa il corpo parte per eseguire diversi comandi sul mio server. è come un telecomando per email.

perché il sistema è progettato per inviare immagini, ha un sacco di parti codificate in modo diverso. una parte mms.smil.txt, un text/plain (che è inutile, dice semplicemente 'questo è un messaggio html'), una parte application/smil (che la parte su cui i telefoni dovrebbero apparire), una parte text/html con una pubblicità per il mio operatore, poi il mio messaggio, ma tutto racchiuso in html, quindi finalmente un file di testo allegato con il mio messaggio semplice (che è la parte che uso) (se spingo un'immagine come allegato nel messaggio, viene messa in allegato 1, codificato Base64, quindi la mia porzione di testo è allegata come allegato 2)

l'ho fatto funzionare con il formato di posta esatto dal mio operatore, ma quando ho eseguito un messaggio da un altro telefono attraverso di esso, non è riuscito in un un sacco di modi miserabili.

ho altri progetti che mi piacerebbe estendere questo telefono-> mail-> parse-> il sistema di comando a, ma ho bisogno di avere un parser stabile/solido/generico per ottenere le diverse parti fuori dalla posta per usalo

il mio obiettivo finale sarebbe quello di avere una funzione che potrei alimentare la posta in pipe grezza e recuperare un grande array con sottoarray associativi di intestazioni var: val pair e uno per il corpo del testo nel suo complesso stringa

più lo cerco sempre, più trovo la stessa cosa: giganteschi pacchetti di gestione della posta eccessivamente sviluppati che fanno tutto sotto il sole che riguarda le e-mail, o tutorial inutili (per me, in questo progetto).

Penso che dovrò mordere il proiettile e scrivere con cura qualcosa di mio.

1

Probabilmente non ti divertirai molto a scrivere il tuo parser MIME. Il motivo per cui stai trovando "pacchetti di gestione della posta eccessivamente sviluppati" è perché MIME è un insieme di regole/formati/codifiche davvero complesso. Le parti MIME possono essere ricorsive, che è parte del divertimento. Penso che la cosa migliore da fare sia scrivere il miglior gestore MIME possibile, analizzare un messaggio, buttare via tutto ciò che non è text/plain o text/html, e quindi forzare il comando nella stringa in entrata a essere preceduto da COMANDO: o qualcosa di simile in modo che tu possa trovarlo nella melma. Se inizi con regole del genere hai una discreta possibilità di gestire nuovi provider, ma dovresti essere pronto a modificare se un nuovo provider arriva (o diamine, se il tuo attuale fornitore sceglie di cambiare la loro architettura di messaggistica).

1

Non sono sicuro che questo possa esserti d'aiuto, spero di sì, ma sicuramente aiuterà gli altri interessati a saperne di più sulla posta elettronica. Marcus Bointon ha fatto una delle migliori presentazioni dal titolo "Mail() e vita dopo la posta()" alla conferenza di PHP di PHP a marzo di quest'anno e gli slides e MP3 sono online. Parla con una certa autorità, avendo lavorato a lungo con email e PHP a un livello profondo.

La mia percezione è che ci si trova in un mondo di dolore cercando di scrivere un parser veramente generico.

MODIFICA - I file sembrano essere stati rimossi sul sito PHP di Londra; trovato le diapositive su Marcus' own site: Part 1Part 2 non poteva vedere il MP3 ovunque anche se

1

L'analisi dell'email in PHP non è un'impresa impossibile. Quello che voglio dire è che non hai bisogno di un team di ingegneri per farlo; è raggiungibile come individuo. La parte più difficile che ho trovato è stata la creazione dell'FSM per l'analisi di un risultato IMAP BODYSTRUCTURE. Da nessuna parte su Internet avevo visto questo così ho scritto il mio.La mia routine fondamentalmente crea una matrice di matrici annidate dall'output del comando e la profondità nella matrice corrisponde approssimativamente al numero di parti necessario per eseguire le ricerche. Quindi gestisce le strutture MIME nidificate con molta grazia.

Il problema è che le funzioni di imap_ * di default di PHP non forniscono molta granularità ... quindi ho dovuto aprire un socket per la porta IMAP e scrivere le funzioni per inviare e recuperare le informazioni necessarie (IMAP FETCH 1 BODY. PEEK [1.2] per esempio), e ciò riguarda la documentazione RFC.

La codifica dei dati (quotato-stampabile, base64, 7 bit, 8 bit, ecc.), Lunghezza del messaggio, tipo di contenuto, ecc. È tutto fornito all'utente; per allegati, testo, html, ecc. Potresti dover capire anche le sfumature del tuo server di posta dato che non tutti i campi sono sempre implementati al 100%.

La gemma è l'FSM ... se hai uno sfondo in Comp Sci può essere davvero molto divertente farlo (la chiave è che le parentesi non sono una grammatica regolare;)); altrimenti sarà una lotta e/o risulterebbe in un brutto codice, usando metodi tradizionali. Inoltre hai bisogno di tempo!

Spero che questo aiuti!

4

L'ho messo insieme, un codice non è mio ma non so da dove viene ... In seguito ho adottato il più robusto "MimeMailParser" ma funziona bene, lo reindirizzo al mio indirizzo email predefinito usando cPanel e funziona benissimo.

#!/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

Mi piace questo approccio, e funziona abbastanza bene per la maggior parte. Tuttavia, ho notato nella risoluzione dei problemi che non gestirà il wrapping delle righe di intestazione, ad esempio se gli indirizzi to: utilizzano più di una riga. –

17

provare il Plancake PHP-mail parser: https://github.com/plancake/official-library-php-email-parser

L'ho usato per i miei progetti. Funziona alla grande, è solo una classe ed è open source.

+0

ottima biblioteca dan! come ti sbarazzi dei caratteri di tipo = 23 e = 40? – cwd

+0

@ cwd che cita la codifica del testo credo. –

+2

Sto usando questa libreria e funziona il 90% delle volte, ma non al 100% ... – behz4d

2

Il lib Mail_mimeDecode Pera è scritto in PHP chiaro che potete vedere qui: Mail_mimeDecode source

+0

il link dovrebbe essere http://svn.php.net/viewvc/pear/packages/Mail_mimeDecode/trunk/Mail/mimeDecode.php?revision=337165&view=markup – chiliNUT

+0

btw questa libreria è eccellente – chiliNUT

2

C'è una biblioteca per l'analisi di un messaggio di posta elettronica prima in php array - http://flourishlib.com/api/fMailbox#parseMessage.

Il metodo parseMessage statico() può essere utilizzato per analizzare un MIME messaggio completo e-mail nella stesso formato rendimenti che fetchMessage(), meno la chiave UID.

$ parsed_message = fMailbox :: parseMessage (file_get_contents ('/ percorso/a/email'));

Ecco un esempio di un messaggio analizzato:

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

Funziona come un fascino! 8-) –

0

Ho incontrato lo stesso problema così ho scritto la seguente classe: Email_Parser. Ricopre un'e-mail non elaborata e la trasforma in un oggetto piacevole.

Richiede PEAR Mail_mimeDecode ma che dovrebbe essere facile da installare tramite WHM o direttamente dalla riga di comando.

Scarica qui: https://github.com/optimumweb/php-email-reader-parser

2

Questo https://github.com/zbateson/MailMimeParser funziona per me, e non hanno bisogno di estensione mailparse.

<?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

semplice PhpMimeParser https://github.com/breakermind/PhpMimeParser Yuo può tagliare i messaggi MIME da file, stringa. Ottieni file, html e immagini in linea.

$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); 
Problemi correlati