parsing raw email in php

Szukam dobrego / działającego / prostego w użyciu kodu php do parsowania surowych wiadomości e-mail na części.

Napisałem kilka rozwiązań brute force, ale za każdym razem pojawia się jedna mała zmiana/nagłówek/spacja/coś i cały mój parser zawodzi i projekt się rozpada.

I zanim zostanę wytykany na PEAR/PECL, potrzebuję prawdziwego kodu. Mój gospodarz ma jakąś śrubową konfigurację, czy coś, nigdy nie mogę uzyskać. Jeśli dostanę .tak wykonane, jakaś różnica w ścieżka / środowisko / php.ini nie zawsze udostępnia go (apache vs cron vs cli).

Aha, i jeszcze jedno, analizuję surowy tekst wiadomości e-mail, nie POP3, a nie IMAP. Jest on przesyłany do skryptu php poprzezqmail email redirect.

Nie spodziewam się, że SOF napisze to za mnie, Szukam kilku wskazówek/punktów wyjścia, jak to zrobić "dobrze". To jeden z tych problemów "koła", które Wiem, że już zostały rozwiązane.

 25
Author: pcurry, 2008-08-16

14 answers

Z czym chcesz skończyć na końcu? Ciało, temat, nadawca, załącznik? Powinieneś spędzić trochę czasu z RFC2822 , aby zrozumieć format poczty, ale oto najprostsze zasady dla dobrze uformowanego e-maila:

HEADERS\n
\n
BODY

Oznacza to, że pierwsza pusta linia (podwójna nowa linia) jest separatorem między nagłówkami a ciałem. Nagłówek wygląda tak:

HSTRING:HTEXT

HSTRING zawsze rozpoczyna się na początku linii i nie zawiera żadnych spacji ani dwukropki. HTEXT może zawierać szeroki zakres tekstu, w tym nowe linie, o ile znak nowej linii jest poprzedzony białymi spacjami.

"ciało"to tak naprawdę wszelkie dane, które następują po pierwszej podwójnej linii nowej. (Istnieją różne zasady, jeśli przesyłasz pocztę przez SMTP, ale przetwarzając ją przez rurę, nie musisz się o to martwić).

Więc, w bardzo prosty, około-1982 RFC822 warunki, e-mail wygląda tak:

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

THIS IS ANY
ARBITRARY DATA
(FOR THE MOST PART)

Większość nowoczesnych e-maili jest bardziej złożona niż ale to. Nagłówki mogą być kodowane dla znaków lub RFC2047 słowa mime, lub mnóstwo innych rzeczy, o których teraz nie myślę. Ciała są naprawdę trudne do roll swój własny kod na te dni, jeśli chcesz, aby były znaczące. Prawie wszystkie wiadomości e-mail generowane przez MUA będą kodowane MIME. Może to być tekst kodowany uuencoded, może to być html, może to być arkusz kalkulacyjny excel kodowany uuencoded.

Mam nadzieję, że pomoże to w zrozumieniu niektórych bardzo żywioły e-maili. Jeśli podasz więcej informacji na temat tego ,co próbujesz zrobić z danymi, ja (lub ktoś inny)może być w stanie zapewnić lepszy kierunek.

 20
Author: jj33,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-16 02:18:11

Wypróbuj Parser poczty PHP Plancake: https://github.com/plancake/official-library-php-email-parser

Używałem go do moich projektów. Działa świetnie, to tylko jedna klasa i jest open source.

 17
Author: dan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-15 21:56:52

Poskładałem to do kupy, jakiś kod nie jest mój, ale nie wiem skąd się wziął... Później przyjąłem bardziej solidny "MimeMailParser", ale to działa dobrze, przesyłam mój domyślny e-mail do niego za pomocą cPanel i działa świetnie.

#!/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(!@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());
}
?>
 4
Author: Carter Cole,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-07 14:50:48

Istnieją funkcje Mailparse, które możesz wypróbować: http://php.net/manual/en/book.mailparse.php , jednak nie w domyślnym PHP conf.

 2
Author: zuups,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-05 14:36:40

Istnieje biblioteka do parsowania nieprzetworzonej wiadomości e - mail do tablicy php - http://flourishlib.com/api/fMailbox#parseMessage .

Statyczna metoda parseMessage () może być użyta do analizy pełnego MIME wiadomość e-mail do tego samego formatu, który zwraca fetchmessage (), minus klucz uid.

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

Oto przykład przetworzonej wiadomości:

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
);
 2
Author: Yaroslav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-02 13:51:57

To https://github.com/zbateson/MailMimeParser działa dla mnie i nie potrzebuje rozszerzenia 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
 2
Author: TomaszKane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-23 12:34:43

Pear lib Mail_mimeDecode jest napisany w PHP, które możesz zobaczyć tutaj: Mail_mimeDecode source

 2
Author: postfuturist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-31 17:36:30

Prawdopodobnie nie będziesz się dobrze bawić pisząc swój własny parser MIME. Powodem, dla którego znajdujesz "zbyt rozbudowane Pakiety obsługi poczty" jest fakt, że MIME jest naprawdę złożonym zestawem reguł/formatów/kodowań. Części MIME mogą być rekurencyjne, co jest częścią zabawy. Myślę, że najlepiej będzie napisać najlepszy program obsługi MIME, przetworzyć wiadomość, wyrzucić wszystko, co nie jest text / plain lub text/html, a następnie wymusić polecenie w nadchodzącym ciągu, aby było poprzedzone komendą: lub coś podobnego tak, że można go znaleźć w błoto. Jeśli zaczniesz od takich reguł, masz przyzwoitą szansę na obsługę nowych dostawców, ale powinieneś być gotowy do zmiany, Jeśli pojawi się nowy dostawca (lub cholera, jeśli obecny dostawca zdecyduje się zmienić swoją architekturę wiadomości).

 1
Author: jj33,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-16 16:06:14

Parsowanie poczty w PHP nie jest zadaniem niemożliwym. Chodzi mi o to, że nie potrzebujesz do tego zespołu inżynierów; jest to osiągalne jako jednostka. Naprawdę najtrudniejszą częścią, którą znalazłem, było stworzenie FSM do analizy wyniku struktury ciała IMAP. Nigdzie w Internecie nie widziałem tego, więc napisałem własne. Moja procedura zasadniczo tworzy tablicę zagnieżdżonych tablic z wyjścia polecenia, a głębokość jedna jest w tablicy w przybliżeniu odpowiada numerom części potrzebnym do wykonania wyszukiwania. Więc radzi sobie z zagnieżdżonymi strukturami MIMU dość wdzięcznie.

Problem polega na tym, że domyślne funkcje PHP imap_* nie zapewniają zbyt wiele granularity...so musiałem otworzyć gniazdo do portu IMAP i napisać funkcje do wysyłania i pobierania niezbędnych informacji (IMAP FETCH 1 ciało.Na przykład PEEK[1.2]), A to wiąże się z przeglądaniem dokumentacji RFC.

Kodowanie danych (quoted-printable, base64, 7bit, 8bit, itd.), długość wiadomości, rodzaj treści itp. is all w przypadku załączników, tekstu, html itp. Być może będziesz musiał również poznać niuanse serwera pocztowego, ponieważ nie wszystkie pola są zawsze zaimplementowane w 100%.

Klejnot to FSM...jeśli masz tło w Comp Sci to może być naprawdę fajnie to zrobić (najważniejsze jest to, że nawiasy nie są zwykłą gramatyką ;)); w przeciwnym razie będzie to walka i / lub wynik w brzydkim kodzie, przy użyciu tradycyjnych metod. Potrzebujesz też trochę czasu!

Mam nadzieję, że to pomoże!

 1
Author: astateful,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-20 20:49:47

Nie jestem pewien , czy to będzie pomocne dla ciebie - mam nadzieję-ale na pewno pomoże innym zainteresowanym dowiedzieć się więcej o e-mail. Marcus Bointon wykonał jedną z najlepszych prezentacji zatytułowanych "Mail() i life after Mail()" na konferencji PHP w Londynie w marcu tego roku, a slajdy i MP3 są online. Mówi z pewnym autorytetem, pracując intensywnie z e-mailem i PHP na głębokim poziomie.

Moim zdaniem jesteś w świecie bólu próbuję napisać naprawdę ogólny parser.

EDIT-pliki zostały usunięte na stronie PHP; znaleziono slajdy na własnej stronie : Część 1 Część 2 nie widziałem nigdzie MP3

 1
Author: Polsonby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-15 12:46:08

Tak, udało mi się napisać podstawowy parser, oparty na rfc i kilku innych podstawowych samouczkach. ale to wieloczęściowe mime zagnieżdżone granice, które ciągle mnie wkurzają.

Dowiedziałem się, że wiadomości MMS (NIE SMS) wysyłane z mojego telefonu to tylko standardowe wiadomości e-mail, więc mam system, który odczytuje przychodzącą wiadomość e-mail, sprawdza od (Aby zezwolić tylko z mojego telefonu) i używa części ciała do uruchamiania różnych poleceń na moim serwerze. to coś w rodzaju pilota przez e-mail.

Ponieważ system jest przeznaczony do wysyłania zdjęć, ma kilka różnych zakodowanych części. mms.smil.część txt, tekst / plain (który jest bezużyteczny, po prostu mówi "to jest wiadomość html"), część application / smil (którą część, na której telefony pic up), część tekst / html z reklamą dla mojego przewoźnika, a następnie moja wiadomość, ale wszystko zawinięte w html, a następnie załącznik do pliku tekstowego z moją zwykłą wiadomością (która jest częścią, której używam) (jeśli wsadzę obraz jako załącznik do wiadomości, jego umieścić w załączniku 1, base64 zakodowany, wtedy moja część tekstowa jest załączona jako załącznik 2)

Miałem to działa z dokładnym formacie poczty z mojego operatora, ale kiedy przepuściłem wiadomość od kogoś elses telefon przez niego, to nie w całej masy żałosne sposoby.

Mam inne projekty, do których chciałbym rozszerzyć ten system phone - > mail->parse - > command, ale muszę mieć stabilny/solidny/generic parser, aby uzyskać różne części z poczty, aby go użyć.

Moim celem końcowym będzie funkcja że mogę wprowadzić surową przesyłaną pocztę i odzyskać dużą tablicę z asocjacyjnymi pod-tablicami nagłówków par var: val i jedną dla tekstu głównego jako całego ciągu

Im więcej i bardziej tego Szukam, tym bardziej znajduję to samo: gigantyczne, rozbudowane Pakiety obsługi poczty, które robią wszystko pod słońcem, co jest związane z pocztą, lub bezużyteczne (jak dla mnie w tym projekcie) tutoriale.

Myślę, że będę musiał ugryźć kulę i po prostu ostrożnie napisać coś sam.

 0
Author: Uberfuzzy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-16 05:09:11
 0
Author: Petah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-08 21:27:33

Spotkałem się z tym samym problemem, więc napisałem następującą klasę: Email_Parser. Przyjmuje surową wiadomość e-mail i zamienia ją w ładny obiekt.

Wymaga kodu Pear Mail_mimeDecode, ale powinien być łatwy do zainstalowania przez WHM lub bezpośrednio z linii poleceń.

Pobierz tutaj: https://github.com/optimumweb/php-email-reader-parser

 0
Author: Jonathan Roy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-23 21:47:40

Simple PhpMimeParser https://github.com/breakermind/PhpMimeParser Yuo może wycinać wiadomości mime z plików, string. Pobierz pliki, html i obrazy wbudowane.

$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);
 0
Author: Kazik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-04 12:48:57