Question

Je recherche un code php efficace/fonctionnel/simple pour analyser les e-mails bruts en plusieurs parties.

J'ai écrit quelques solutions par force brute, mais à chaque fois, un petit changement/en-tête/espace/quelque chose arrive et tout mon analyseur échoue et le projet s'effondre.

Et avant de pointer vers PEAR/PECL, j'ai besoin du vrai code.Mon hôte a une configuration foireuse ou quelque chose comme ça, je n'arrive jamais à faire en sorte que les .so soient correctement construits.Si j'obtiens le .so créé, une certaine différence dans path/environment/php.ini ne le rend pas toujours disponible (apache vs cron vs cli).

Oh, et une dernière chose, j'analyse le texte brut de l'e-mail, PAS POP3, ni IMAP.Il est transmis au script php via une redirection de courrier électronique .qmail.

Je ne m'attends pas à ce que SOF l'écrive pour moi, je cherche des conseils/points de départ pour le faire « correctement ».C'est l'un de ces problèmes de "roue" dont je sais qu'il a déjà été résolu.

Était-ce utile?

La solution

Qu’espérez-vous obtenir à la fin ?Le corps, le sujet, l'expéditeur, une pièce jointe ?Tu devrais passer du temps avec RFC2822 pour comprendre le format du mail, mais voici les règles les plus simples pour un email bien formé :

HEADERS\n
\n
BODY

Autrement dit, la première ligne vide (double nouvelle ligne) est le séparateur entre les HEADERS et le BODY.Un HEADER ressemble à ceci :

HSTRING:HTEXT

HSTRING commence toujours au début d'une ligne et ne contient aucun espace blanc ni deux-points.HTEXT peut contenir une grande variété de texte, y compris des nouvelles lignes à condition que le caractère de nouvelle ligne soit suivi d'espaces.

Le "BODY" correspond en réalité à n'importe quelle donnée qui suit la première double nouvelle ligne.(Il existe différentes règles si vous transmettez du courrier via SMTP, mais en le traitant via un canal, vous n'avez pas à vous en soucier).

Donc, en très simple, vers 1982 RFC822 termes, un e-mail ressemble à ceci :

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

THIS IS ANY
ARBITRARY DATA
(FOR THE MOST PART)

La plupart des courriers électroniques modernes sont cependant plus complexes que cela.Les en-têtes peuvent être codés pour des jeux de caractères ou RFC2047 mimer des mots, ou une tonne d'autres choses auxquelles je ne pense pas en ce moment.Il est vraiment difficile de créer votre propre code pour les corps de nos jours si vous voulez qu'ils aient un sens.Presque tous les e-mails générés par un MUA seront MIME codé.Cela peut être du texte uuencodé, du HTML ou une feuille de calcul Excel uuencodée.

J'espère que cela aidera à fournir un cadre pour comprendre certains des éléments les plus élémentaires du courrier électronique.Si vous fournissez plus d'informations sur ce que vous essayez de faire avec les données, moi (ou quelqu'un d'autre) pourrai peut-être vous fournir une meilleure orientation.

Autres conseils

Essayez l'analyseur d'e-mails Plancake PHP :https://github.com/plancake/official-library-php-email-parser

Je l'ai utilisé pour mes projets.Cela fonctionne très bien, ce n'est qu'une seule classe et c'est open source.

J'ai bricolé ça, certains codes ne sont pas de moi mais je ne sais pas d'où il vient...J'ai ensuite adopté le "MimeMailParser" plus robuste, mais cela fonctionne bien, je lui transmets mon e-mail par défaut à l'aide de cPanel et cela fonctionne très 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());
}
?>

Il existe des fonctions Mailparse que vous pouvez essayer : http://php.net/manual/en/book.mailparse.php, pas dans la configuration php par défaut, cependant.

Il existe une bibliothèque pour analyser les messages électroniques bruts dans un tableau php - http://flourishlib.com/api/fMailbox#parseMessage.

La méthode statique PARSEMESSAGE () peut être utilisée pour analyser un e-mail complet de mime dans le même format que FetchMessage () revient, moins la touche UID.

$ parsed_message = fmailbox :: PARSEMESSAGE (file_get_contents ('/ path / to / e-mail'));

Voici un exemple de message analysé :

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
);

Ce https://github.com/zbateson/MailMimeParser fonctionne pour moi et n'a pas besoin d'extension 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

La bibliothèque Pear Mail_mimeDecode est écrite en PHP brut que vous pouvez voir ici : Source Mail_mimeDecode

Vous n'allez probablement pas vous amuser beaucoup à écrire votre propre analyseur MIME.La raison pour laquelle vous trouvez des « packages de gestion du courrier surdéveloppés » est que MIME est un ensemble très complexe de règles/formats/encodages.Les parties MIME peuvent être récursives, ce qui fait partie du plaisir.Je pense que votre meilleur pari est d'écrire le meilleur gestionnaire MIME possible, d'analyser un message, de jeter tout ce qui n'est pas text/plain ou text/html, puis de forcer la commande dans la chaîne entrante à être préfixée par COMMAND :ou quelque chose de similaire pour que vous puissiez le trouver dans la boue.Si vous commencez avec de telles règles, vous avez de bonnes chances de gérer de nouveaux fournisseurs, mais vous devriez être prêt à les modifier si un nouveau fournisseur arrive (ou diable, si votre fournisseur actuel choisit de modifier son architecture de messagerie).

Analyser les e-mails en PHP n'est pas une tâche impossible.Ce que je veux dire, c'est que vous n'avez pas besoin d'une équipe d'ingénieurs pour le faire ;c’est réalisable en tant qu’individu.La partie la plus difficile que j'ai trouvée a été de créer le FSM pour analyser un résultat IMAP BODYSTRUCTURE.Je n'avais vu cela nulle part sur Internet, alors j'ai écrit le mien.Ma routine crée essentiellement un tableau de tableaux imbriqués à partir de la sortie de la commande, et la profondeur à laquelle on se trouve dans le tableau correspond à peu près au(x) numéro(s) de pièce nécessaire(s) pour effectuer les recherches.Il gère donc les structures MIME imbriquées avec beaucoup de grâce.

Le problème est que les fonctions imap_* par défaut de PHP n'offrent pas beaucoup de granularité... j'ai donc dû ouvrir un socket sur le port IMAP et écrire les fonctions pour envoyer et récupérer les informations nécessaires (IMAP FETCH 1 BODY.PEEK[1.2] par exemple), et cela implique de consulter la documentation RFC.

L'encodage des données (quoted-printable, base64, 7bit, 8bit, etc.), la longueur du message, le type de contenu, etc.tout vous est fourni ;pour les pièces jointes, le texte, le HTML, etc.Vous devrez peut-être également comprendre les nuances de votre serveur de messagerie, car tous les champs ne sont pas toujours implémentés à 100 %.

Le joyau est le FSM... si vous avez une formation en Comp Sci, cela peut être vraiment très amusant de faire cela (la clé est que les parenthèses ne sont pas une grammaire normale ;) );sinon, ce sera une lutte et/ou aboutira à un code laid, en utilisant des méthodes traditionnelles.Il faut aussi du temps !

J'espère que cela t'aides!

Je ne suis pas sûr que cela vous soit utile - je l'espère - mais cela aidera sûrement les autres personnes intéressées à en savoir plus sur le courrier électronique. Marcus Bointon a fait l'une des meilleures présentations intitulée "Mail() and life after Mail()" à la conférence PHP de Londres en mars de cette année et le diapositives et MP3 sont en ligne.Il parle avec une certaine autorité, ayant beaucoup travaillé avec le courrier électronique et PHP à un niveau approfondi.

Ma perception est que vous vous retrouverez dans un monde de souffrance en essayant d'écrire un analyseur véritablement générique.

EDIT - Les fichiers semblent avoir été supprimés sur le site PHP Londres ;J'ai trouvé les diapositives sur Marcus propre site: Partie 1 Partie 2 Cependant, je n'ai pu voir le MP3 nulle part

ouais, j'ai pu écrire un analyseur de base, basé sur cette RFC et quelques autres didacticiels de base.mais ce sont les limites imbriquées du mime en plusieurs parties qui continuent de me gâcher.

J'ai découvert que les messages MMS (et non SMS) envoyés depuis mon téléphone ne sont que des e-mails standard. J'ai donc un système qui lit l'e-mail entrant, vérifie l'expéditeur (pour autoriser uniquement depuis mon téléphone) et utilise la partie du corps pour exécuter différents commandes sur mon serveur.c'est un peu comme une télécommande par email.

parce que le système est conçu pour envoyer des images, il contient un tas de parties codées différemment.une partie mms.smil.txt, une partie text/plain (qui est inutile, dit simplement 'ceci est un message html'), une partie application/smil (que la partie sur laquelle les téléphones capteraient), une partie texte/html avec une publicité pour mon opérateur, puis mon message, mais le tout enveloppé en HTML, puis enfin une pièce jointe de fichier texte avec mon message brut (qui est la partie que j'utilise) (si je mets une image en pièce jointe dans le message, elle est mise à pièce jointe 1, codée en base64, puis ma partie de texte est jointe en pièce jointe 2)

Je l'ai fait fonctionner avec le format de courrier exact de mon opérateur, mais lorsque j'ai transmis un message provenant du téléphone de quelqu'un d'autre via celui-ci, il a échoué de toutes sortes de manières misérables.

J'ai d'autres projets auxquels j'aimerais étendre ce système de commande téléphone->mail->analyse->, mais j'ai besoin d'un analyseur stable/solide/générique pour extraire les différentes parties du courrier afin de l'utiliser.

mon objectif final serait d'avoir une fonction dans laquelle je pourrais alimenter le courrier brut et récupérer un grand tableau avec des sous-tableaux associatifs d'en-têtes var:val paires, et un pour le corps du texte dans sa totalité.

plus je cherche là-dessus, plus je trouve la même chose :des packages géants de gestion du courrier surdéveloppés qui font tout ce qui est lié aux courriers sous le soleil, ou des tutoriels inutiles (pour moi, dans ce projet).

je pense que je vais devoir mordre la balle et écrire soigneusement quelque chose moi-même.

J'ai rencontré le même problème, j'ai donc écrit le cours suivant :Email_Parser.Il récupère un e-mail brut et le transforme en un bel objet.

Cela nécessite PEAR Mail_mimeDecode mais cela devrait être facile à installer via WHM ou directement depuis la ligne de commande.

Obtenez-le ici : https://github.com/optimumweb/php-email-reader-parser

PhpMimeParser simple https://github.com/breakermind/PhpMimeParser Yuo peut couper des messages mime à partir de fichiers, de chaînes.Obtenez des fichiers, des images HTML et en ligne.

$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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top