2008-08-15 15 views
24

未処理の電子メールをパーツに解析するためのPHPコードを使いたいと思っています。PHPで未処理の電子メールを解析する

私はブルートフォースの解決策をいくつか書いていますが、たびに小さな変更/ヘッダー/スペース/何かが来て、私のパーサー全体が失敗し、プロジェクトが崩壊します。

PEAR/PECLを指す前に、実際のコードが必要です。私のホストには何らかの設定や何かがありますが、.soを正しく構築することはできません。もし私が.soを作ってしまったら、path/environment/php.iniのいくつかの違いが必ずしもそれを利用可能にするとは限りません(apache vs cron vs cli)。

ああ、もう1つ、私は生のメールテキストを解析しています。POP3ではなく、IMAPではありません。それは.qmail電子メールリダイレクトを介してPHPスクリプトにパイプされています。

SOFが私のために書いてくれるとは思っていませんが、私はいくつかのヒントを探しています。これは既に私が知っている "車輪"の問題の一つです。

答えて

19

最終的にはどうしたらいいですか?本文、件名、送信者、添付ファイルですか?あなたがメールの形式を理解するためにRFC2822でいくつかの時間を費やす必要がありますが、ここではよく形成された電子メールのための最も簡単なルールがあります:

HEADERS\n 
\n 
BODY 

、最初の空白行(ダブル改行)がヘッダ間のセパレータであることと、 BODY。ヘッダーは次のようになります。

HSTRING:HTEXT 

HSTRINGは常に行の先頭から始まり、空白またはコロンを含みません。 HTEXTには、改行文字が空白文字の後に続く限り、改行文字を含む幅広いテキストを含めることができます。

"BODY"は実際には最初の二重改行に続くデータです。 (SMTP経由でメールを送信しているのにパイプを使って処理している場合は、それについて心配する必要はありません)異なるルールがあります。

ので、本当に簡単、年頃 - 1982 RFC822用語で、電子メールは次のようになります。

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

THIS IS ANY 
ARBITRARY DATA 
(FOR THE MOST PART) 

最近のほとんどの電子メールは、しかしそれよりも複雑です。ヘッダーは、文字セットまたはRFC2047 mime単語、または私が今考えていない他のもののトンのためにコード化することができます。あなたがそれらを意味があるようにしたい場合、体は最近、あなた自身のコードを巻くのは本当に難しいです。 MUAによって生成されたほとんどすべての電子メールはMIMEにエンコードされます。それはuuencodeされたテキストかもしれません、それはhtmlかもしれません、それはuuencoded Excelスプレッドシートかもしれません。

これは、電子メールの非常に基本的なバケットの一部を理解するためのフレームワークを提供するのに役立ちます。あなたがデータで何をしようとしているのかについてより多くの背景を提供すれば、私(または他の誰か)がより良い方向を提供することができます。

0

そうですね、そのrfcと他の基本的なチュートリアルに基づいて、基本的なパーサーを書くことができました。しかし、そのマルチパートのmimeは、私を乱し続けている境界を入れ子にしています。

私の電話から送信されたMMS(SMSではない)メッセージは標準的な電子メールであることが分かりました。私は受信メールを読み、(携帯電話からのみを許可する)私のサーバー上で異なるコマンドを実行する部分。電子メールによるリモートコントロールのようなもの。

システムが画像を送信するように設計されているため、別のエンコードされた部分がたくさんあるためです。 mms.smil.txtの部分、text/plain(これは役に立たない、ちょうど 'これはhtmlメッセージです')、アプリケーション/ smil部分(携帯電話の部分)、text/html部分私のキャリアのための広告で、その後私のメッセージがすべてhtmlでラップされ、次に私のプレーンなメッセージ(私が使用している部分です)を使ってテキストファイルを添付します(メッセージの添付ファイルとして画像を押した場合、添付ファイル1、ベースコード64、添付ファイルとして添付2)

キャリアからの正確なメール形式で作業していましたが、誰かからelsesの電話を使ってメッセージを実行したときに、悲惨な方法の全体の束。

私はこのphone-> mail-> parse->コマンドシステムを拡張したいと思う他のプロジェクトがありますが、私は安定した/固体/一般的なパーサーを持つ必要がありますこれを使って。

私の最終的な目標は、生のパイプで送られたメールをフィードにして、ヘッダ:var:valのペアの連想サブアレイと、本文全体のためのもの文字列

私がこれをより多く探すと、同じことが分かります。郵便に関連する太陽の下ですべてを行う巨大な開発過剰メール処理パッケージ、または役に立たない(このプロジェクトでは)チュートリアルです。

私は弾丸を噛んで、ちょうど自分のことを丁寧に書く必要があると思います。

1

おそらくあなた自身のMIMEパーサーを書くのは面白くないでしょう。 MIMEが本当に複雑なルール/フォーマット/エンコーディングのセットであるため、あなたが「過剰に開発されたメール処理パッケージ」を見つける理由があります。 MIMEの部分は再帰的になる可能性があり、これは楽しいことの一部です。私はあなたの最善の策はあなたができる最高のMIMEハンドラを書くこと、メッセージを解析すること、テキスト/プレーンまたはテキスト/ HTMLではないものをすべて破棄してから、入力文字列のコマンドにCOMMAND:あなたが泥の中でそれを見つけることができるように。このようなルールから始めれば、新しいプロバイダーを扱う機会はまれですが、新しいプロバイダーが来た場合(または現在のプロバイダーがメッセージングアーキテクチャーを変更することを選択した場合はどうでもいい)、調整が必要です。

1

これがあなたに役立つかどうかはわかりませんが、それは確かに電子メールの詳細を知りたいと考えている他の人たちに役立つでしょう。 Marcus Bointonは、今年3月のPHPロンドン会議で「メール()とメールの後の生活」(slidesMP3)と呼ばれる最高のプレゼンテーションの1つをオンラインにしました。彼はいくつかの権威を持って話し、電子メールとPHPを深く使って広範囲に活動してきました。

私が知覚しているのは、本当に汎用的なパーサーを作成しようとすると苦痛の世界にあるということです。

EDIT - ファイルがPHPのロンドンサイトで削除されたようです。 Marcusのown site上のスライドを見つけました:http://php.net/manual/en/book.mailparse.php、ないデフォルトのPHPのconfの中しかし、:Part 1Part 2はMP3を見ることができませんでしたどこにでも

2

かかわらず、あなたが試みることができるMailparseの機能があります。

1

PHPで電子メールを解析することは不可能ではありません。つまり、エンジニアのチームは必要ありません。それは個人として達成可能です。私が見つけた最も難しい部分は、IMAP BODYSTRUCTUREの結果を解析するためのFSMを作成することでした。インターネット上のどこにも私はこれを見たので、私は自分自身を書いた。私のルーチンは基本的に、コマンド出力からネストされた配列の配列を作成し、配列内の深さ1はルックアップを実行するのに必要な部品番号にほぼ対応します。したがって、ネストされたMIME構造は非常に上手く処理されます。

PHPのデフォルトのimap_ *関数はあまり細かくないので、IMAPポートへのソケットを開いて、必要な情報を送信して取得する関数を作成しなければなりませんでした(IMAP FETCH 1 BODY。 PEEK [1.2]など)、それはRFCの文書を見ることになります。

データ(quoted-printable、base64、7bit、8bitなど)のエンコーディング、メッセージの長さ、コンテンツタイプなどはすべてあなたに提供されます。添付ファイル、テキスト、htmlなどのためにあなたのメールサーバーのニュアンスを把握しなければならないかもしれません。すべてのフィールドが常に100%実装されているわけではないからです。

宝石はFSMです...あなたがComp Sciに背景を持っていれば、これを作るのは本当に面白いかもしれません(それらの括弧は普通の文法ではありません;));それ以外の場合は、伝統的な方法を使用して醜いコードになってしまいます。また、時間が必要です!

希望すると便利です。

4

私はこれを一緒に洞窟に入れましたが、いくつかのコードは私のものではありませんが、どこから来たのか分かりません...後でもっと強力な "MimeMailParser"を採用しました。 cPanelとそれは素晴らしい動作します。

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

私はこのアプローチが好きで、ほとんどの場合非常にうまく動作します。しかし、私は、ヘッダ行の折り返しを処理しないことをトラブルシューティングで気付いています。たとえば、to:アドレスが複数の行を使用する場合です。 –

17

はPlancake PHPメールパーサーを試してみてください。 https://github.com/plancake/official-library-php-email-parser

私は私のプロジェクトのためにそれを使用しています。それは素晴らしい、それはただのクラスであり、それはオープンソースです。梨のlib Mail_mimeDecodeはあなたがここで見ることができますプレーンなPHPで書かれている

+0

すばらしい図書館dan!どのように= 23と= 40の文字を取り除きますか? – cwd

+0

@cwdそれは引用符で囲まれたテキストエンコーディングだと思います。 –

+2

私はこのlibを使用していますが、90%の時間で動作しますが、100%ではありません。 – behz4d

2

:非常によくMail_mimeDecode source

+0

リンクはhttp://svn.php.net/viewvc/pear/packages/Mail_mimeDecode/trunk/Mail/mimeDecode.php?revision=337165&view=markup – chiliNUT

+0

btwこのライブラリはすばらしいです – chiliNUT

0
+0

-1あなたが登録する必要がありますそのサイトを入手するには、ドキュメントが明確ではありません。あなたは少なくともそれを使用する方法の例を挙げることができますか?プランケーキの答えはこれよりもよく見えます。 – cwd

2

PHPに生の電子メールメッセージを解析するためのライブラリがあります配列 - http://flourishlib.com/api/fMailbox#parseMessage

静的メソッドparseMessage()はそのfetchMessage()戻り、マイナス UIDキー同じフォーマットに完全なMIME 電子メールメッセージを解析するために使用することができます。

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

が解析されたメッセージの例です:Email_Parser:

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

魅力的な作品! 8-) –

0

私はので、私は次のクラスを書いて、同じ問題に会いました。それは未処理の電子メールを取り込み、素敵なオブジェクトに変換します。

PEAR Mail_mimeDecodeが必要ですが、WHMまたはコマンドラインから簡単にインストールできます。

ここでそれを取得します。私のために https://github.com/optimumweb/php-email-reader-parser

2

このhttps://github.com/zbateson/MailMimeParser作品、および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

シンプルPhpMimeParser https://github.com/breakermind/PhpMimeParser Yuoは、ファイルから文字列をMIMEメッセージをカットすることができます。ファイル、HTML、インライン画像を取得します。

$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); 
関連する問題