Javaでメールを解析する

Javaで80%を作成した最後のプロジェクトに、サーバーを通過するすべての文字のパーサーであるモジュールを追加する必要がありました。 モジュールの宗教的な動機は非常に奇妙ですが、詳細を共有したいと思います。

使用可能なものは次のとおりです。

CentOS上のDovecot配信サービスを備えたPostfixメールサーバー。 さて、JVM。

メッセージ構造

電子メール、そのコンポーネント、それらのおおよその構造、ヘッダー、MIMEタイプとは、 Wikipediaで人間的に説明されています。
さらに興味深いのは、サーバー上のレターのファイル名の構造です。 新しく作成された(クライアントによって要求されていない/読まれていない)手紙の名前の例:

1348142977.M852516P31269.mail.example.com,S=3309,W=3371 


名前はフラグで構成されます。 フラグは、新しい文字を作成するとき、文字とそのサイズが示される「場所」、「いつ」、コンマで区切られます。


このうち、筆記時間(最初の10桁)が役に立ちました。 ただし、多くの場合、この時間はメッセージヘッダーの時間と異なる場合があるため、名前の時間はディレクトリ内のメッセージをフィルタリングするためだけに使用しました。

追加/クライアントフラグ

クライアントメールインターフェイス(以下、クライアントと呼びます)は、独自のフラグをレター名に追加できます。 クライアントフラグの開始は、記号「:」で示されます。

クライアントサーバーから新しいレター要求するとすぐに、要求がトランスポートに送信され、要求された各レターが「読み取り」ディレクトリに移動され、次のフラグとカンマで区切られた情報フラグ(2つのうちの1つ)が名前に追加されます:

サーバー上のメッセージが既に「読み取り」フォルダーにあるという事実にもかかわらず、ユーザーにはそれが新規として表示されます。 顧客は手紙の場所ではなく、フラグを読みます。
つまり、ユーザー自身が手紙(または彼との別のアクション)を開き、フラグ "S"(表示)が名前に追加された場合にのみ、視覚的に "読み上げられます"。 手紙に対するさまざまなアクションは、予想どおり、フラグを追加し、メモを参照してください。

例:
メールボックスの新しいメッセージがサーバーに届きました。名前は次のようになります。

 1348142977.M852516P31269.mail.example.com,S=3309,W=3371 

私たちの背景では、 神は Outlookを禁止しています。Outlookは新しい文字のリストを要求し、サーバー上でそれらを「読み取り」ディレクトリに移動してフラグを追加するように言っています。

 1348142977.M852516P31269.mail.example.com,S=3309,W=3371:2, 

次に、 削除してOutlookを開き、新しい文字をクリックすると、Sフラグが追加されます。

 1348142977.M852516P31269.mail.example.com,S=3309,W=3371:2,S 

そして、それに答えて削除します:

 1348142977.M852516P31269.mail.example.com,S=3309,W=3371:2,SRT 

ご覧のとおり、フラグはセパレータなしでリストされています。

注:一部のクライアントには、レターを「読み取り」フォルダーに構成する(移動しない)機能があります。 また、クライアントは、ドキュメントに示されていない「ニーズに応じて」フラグを追加することがありますが、特に注意していません。
より有用なフラグ情報: cr.yp.to/proto/maildir.html

そして少しのJava

文字の処理には、 javax.mailを使用しました。 抽象クラスjavax.mail.Messageが提供されていますが、この場合はjavax.mail.MimeMessageに制限されています。
モジュールはサーバー上でスピンするため、ローカルでメッセージにアクセスします(コード内のチェックと例外処理は省略されます)。

 //   properties   Session session = Session.getDefaultInstance(System.getProperties()); FileInputStream fis = new FileInputStream(pathToMessage); MimeMessage mimeMessage = new MimeMessage(session, fis); 

これで、ASCIIで予期されるメッセージヘッダーを読み取ることができます。 ヘッダーが見つからない場合、nullを返します。 例:

 String messageSubject = mimeMessage.getSubject(); String messageId = mimeMessage.getMessageID(); 

受信者のリストを決定するために、引数としてMessage.RecipientTypeを取るgetRecipientsメソッドが提供されます。 このメソッドは、 Address型のオブジェクトの配列を返します。 たとえば、メッセージの受信者をリストします。

 for(Address recipient : mimeMessage.getRecipients(Message.RecipientType.TO)){ System.out.println(recipient.toString()); } 

手紙の差出人を見つけるために、getFromメソッドがあります。 また、Address型のオブジェクトの配列を返します。 このメソッドは、「From」ヘッダーを読み取り、存在しない場合は「Sender」ヘッダーを読み取り、「Sender」が存在しない場合はnullを読み取ります。

 for(Address sender : mimeMessage.getFrom()){ System.out.println(sender.toString()); } 

次に、メッセージの本文を分析します(ほとんどの場合、テキストと添付ファイルが必要です)。 複合(MIMEマルチパートメッセージ)にすることも、1ブロックのテキスト/プレーン形式のみを含めることもできます。 メッセージの本文が添付ファイル(テキストなし)のみで構成されている場合でも、マルチパートメッセージとしてマークされます。 RFC822によると、フォーマットはContent-Typeヘッダーのメッセージ本文(およびその部分)に指定されています。

  //        if(mimeMessage.isMimeType("multipart/mixed")){ // getContent()    ,   . //   - Object,    Multipart Multipart multipart = (Multipart) mimeMessage.getContent(); //       for(int i = 0; i < multipart.getCount(); i ++){ BodyPart part = multipart.getBodyPart(i); // html-   , "text/plain"  "text/html" (     html ),       : if(part.isMimeType("text/plain")){ System.out.println(part.getContent().toString()); } //    part  else if(Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition()){ //     .    ,  decode String fileName = MimeUtility.decodeText(part.getFileName()); //  InputStream InputStream is = part.getInputStream(); //    ,  -    .... } } } //          else if(mimeMessage.isMimeType("text/plain")){ System.out.println(mimeMessage.getContent().toString()); } 


実際、それがすべてです。 資料が役に立てば幸いです。
また、oracle.comには便利なjavax.mail FAQがあります。

UPD:最初のコメントで述べたように、メッセージの本文部分は一緒にネストできます。 同じ場所のコメントでは、それらを整理するために2つの方法がレイアウトされています。

Source: https://habr.com/ru/post/J153415/


All Articles