#author("2022-03-01T06:13:21+00:00","","")
#author("2022-05-19T12:02:14+00:00","","")
// 下階層用テンプレート
#topicpath
----
//ここにコンテンツを記述します。
#contents

**JavaMailをメールの解析に使う、って? [#ra5e3f16]
JavaMailは通常メールを送信したりメールを受信するためのAPI群ですが、メールデータをストリームから受け取って解析する、などの用途にも利用することができます。たとえば受信したメールデータの宛先アドレスを抜き出すとか、本文の中身をサニタイズするとか、そんな場合ですね。ストリームから受け取れるってことは標準入力からのデータも解析できるわけで、たとえば、.forwardでメールをプログラムに転送してそこでなんか処理するときなど、標準入力よりプログラムにメールデータが渡されることになりますが、そこでJavaMailのAPIを利用することができます。



**サンプル [#l8ed694f]
サンプルとして以下のようなメールを扱ってみたいと思います。
 From fromaddress@hogehoge.com  Sun May 18 01:13:17 2008
 Return-Path: <fromaddress@hogehoge.com>
 X-Original-To: toaddress@hogehoge.jp
 Delivered-To: toaddress@hogehoge.jp
 Received: from fuga.so-net.ne.jp (fuga.so-net.ne.jp [202.238.82.9])
 	by mail.hogehoge.jp (Postfix) with ESMTP id A75B1408BE
 	for <toaddress@hogehoge.jp>; Sun, 18 May 2008 01:13:12 +0900 (JST)
 Received: from [127.0.0.1] 
 	by fuga.so-net.ne.jp  with ESMTP id m4HGD9n9027300;
 	Sun, 18 May 2008 01:13:09 +0900 (JST)
 Date: Sun, 18 May 2008 01:13:10 +0900
 From: Hogehoge Com <fromaddress@hogehoge.com>
 To: toaddress@hogehoge.jp
 Subject: =?ISO-2022-JP?B?GyRCJUYlOSVIJWEhPCVrISobKEI=?=
 Message-Id: <20080518011206.8EB1.fromaddress@hogehoge.com>
 MIME-Version: 1.0
 Content-Type: text/plain; charset="ISO-2022-JP"
 Content-Transfer-Encoding: 7bit
 X-Mailer: Becky! ver. 2.31 [ja]
 
 メールのテストです。
 end。
 
このメールをストリームから受信して、JavaMailで内容を解析してみたいと思います。だいたいの内容は以下の通りですね。

-差出人: Hogehoge Com <fromaddress@hogehoge.com>
-送信先: toaddress@hogehoge.jp
-(厳密な)送信元: fromaddress@hogehoge.com ((SMTPをコマンドラインでたたくときの、mail from: xxx のこと。Envelope Fromってやつ))
-127.0.0.1 -> fuga.so-net.ne.jp -> mail.hogehoge.jp と配送された
-Return-Path はfromaddress@hogehoge.com (って最後に受信したサーバ mail.hogehoge.jp がつけた)

ちなみに
 Subject: =?ISO-2022-JP?B?GyRCJUYlOSVIJWEhPCVrISobKEI=?=
ですが "GyRCJUYlOSVIJWEhPCVrISobKEI=" をBase64でデコードしてそのバイナリを上記 ISO-2022-JP でデコードすると「テストメール!」となります。

[[MIMEでエンコードされたMailのSubjectのデコード、エンコード - 教えて!goo>http://oshiete1.goo.ne.jp/qa519669.html]]



***まずはテキストファイルからメールを読み取る [#xe822e41]
まずは標準入力からでなくファイルからストリームを作成して、メールを解析してみます。上記ファイルをテキストでJISで保存しておきます。

サンプルは以下の通り。
 public class FileMain {
   public static void main(String[] args) throws IOException {
     try {
       InputStream in = new FileInputStream(new File("mail.dummy.txt"));
       Session session = Session.getDefaultInstance(
           new java.util.Properties(), null);
       MimeMessage message = new MimeMessage(session, in);
       print(message);
     } catch (MessagingException e) {
       e.printStackTrace();
     } catch (FileNotFoundException e) {
       e.printStackTrace();
     }
   }
 
   private static void print(MimeMessage message) throws MessagingException,
       IOException {
     System.out.println("---- 全ヘッダをリストします ----");
     Enumeration<Header> allHeaders = message.getAllHeaders();
     while (allHeaders.hasMoreElements()) {
       Header header = allHeaders.nextElement();
       System.out
           .println(header.getName() + " : " + header.getValue());
     }
     System.out.println("---- 全ヘッダ 以上 ----");
 
     System.out.println("---- ヘッダ名指定で取ってみる(Received) ----");
     String[] headers = message.getHeader("Received");
     for (String header : headers) {
       System.out.println(header);
     }
 
     System.out.println("---- ヘッダ名指定で取ってみる(Return-Path) ----");
     headers = message.getHeader("Return-Path");
     for (String header : headers) {
       System.out.println(header);
     }
 
     System.out.println("---- ヘッダ名指定で取ってみる(Subject) ----");
     headers = message.getHeader("Subject");
     for (String header : headers) {
       System.out.println(header);
     }
     System.out.println("デコード↑してくれない");
 
     System.out.println("---- 専用のメソッドで取ってみる(Subject) ----");
     System.out.println(message.getSubject());
     System.out.println("デコード↑してくれた");
 
     System.out.println("---- 専用のメソッドで取ってみる(To) ----");
     Address[] allRecipients = message.getAllRecipients();
     for (Address address : allRecipients) {
       System.out.println(address);
     }
 
     System.out.println("---- メール本体の取得 ----");
     System.out.println(message.getContent());
     System.out.println("--------");
   }
 }

結果は以下の通りです

 ---- 全ヘッダをリストします ----
 From fromaddress@hogehoge.com  Sun May 18 01 : 13:17 2008
 Return-Path : <fromaddress@hogehoge.com>
 X-Original-To : toaddress@hogehoge.jp
 Delivered-To : toaddress@hogehoge.jp
 Received : from fuga.so-net.ne.jp (fuga.so-net.ne.jp [202.238.82.9])
 	by mail.hogehoge.jp (Postfix) with ESMTP id A75B1408BE
 	for <toaddress@hogehoge.jp>; Sun, 18 May 2008 01:13:12 +0900 (JST)
 Received : from [127.0.0.1] 
 	by fuga.so-net.ne.jp  with ESMTP id m4HGD9n9027300;
 	Sun, 18 May 2008 01:13:09 +0900 (JST)
 Date : Sun, 18 May 2008 01:13:10 +0900
 From : Hogehoge Com <fromaddress@hogehoge.com>
 To : toaddress@hogehoge.jp
 Subject : =?ISO-2022-JP?B?GyRCJUYlOSVIJWEhPCVrISobKEI=?=
 Message-Id : <20080518011206.8EB1.fromaddress@hogehoge.com>
 MIME-Version : 1.0
 Content-Type : text/plain; charset="ISO-2022-JP"
 Content-Transfer-Encoding : 7bit
 X-Mailer : Becky! ver. 2.31 [ja]
 ---- 全ヘッダ 以上 ----
 
 ---- ヘッダ名指定で取ってみる(Received) ----
 from fuga.so-net.ne.jp (fuga.so-net.ne.jp [202.238.82.9])
 	by mail.hogehoge.jp (Postfix) with ESMTP id A75B1408BE
 	for <toaddress@hogehoge.jp>; Sun, 18 May 2008 01:13:12 +0900 (JST)
 from [127.0.0.1] 
 	by fuga.so-net.ne.jp  with ESMTP id m4HGD9n9027300;
 	Sun, 18 May 2008 01:13:09 +0900 (JST)
 
 ---- ヘッダ名指定で取ってみる(Return-Path) ----
 <fromaddress@hogehoge.com>
 
 ---- ヘッダ名指定で取ってみる(Subject) ----
 =?ISO-2022-JP?B?GyRCJUYlOSVIJWEhPCVrISobKEI=?=
 デコード↑してくれない
 
 ---- 専用のメソッドで取ってみる(Subject) ----
 テストメール!
 デコード↑してくれた
 
 ---- 専用のメソッドで取ってみる(To) ----
 toaddress@hogehoge.jp
 
 ---- メール本体の取得 ----
 メールのテストです。
 end。
 --------


<>とかの微妙な装飾まで細かな解析はしてくれないみたいですが、まあ、自前で解析するよりは良さそうです。

***パイプされた標準入力からメールを読み取る [#fd81b0d5]
次に実際に標準入力からやってみます。

 public static void main(String[] args) {
   try {
     InputStream in = System.in;
     Session session = Session.getDefaultInstance(
         new java.util.Properties(), null);
     MimeMessage message = new MimeMessage(session, in);
     print(message);
   } catch (MessagingException e) {
     e.printStackTrace();
   } catch (IOException e) {
     e.printStackTrace();
   }
 }
ストリームとして標準入力を渡しています。では実際にUnix上でパイプで標準入力を渡してみましょう。

 [hoge@www Test]$ export CLASSPATH=lib/mail.jar:lib/sample.jar:lib/activation.jar
 [hoge@www Test]$ cat mail.dummy.txt | java nu.mine.kino.sample.Main

書きませんが先と同じ結果が得られました。

ちなみにパイプしない場合は入力待ちになります。色々入力後Ctrl+ z で入力終了を指示すれば、プログラムが実行されます(([[Platform-Specific Details: The End-of-Input Character>http://www.ei.fukui-nct.ac.jp/~yfa/java/jtutorial/java/nutsandbolts/_endofinput.html]]))。



**関連リンク [#w3fb37e8]
[[メーリングリストの構築と運用(前編)(4/4)>http://www.atmarkit.co.jp/flinux/rensai/qmail04/qmail04d.html]]


----
この記事は
#vote(おもしろかった[52],そうでもない[16])
#vote(おもしろかった[53],そうでもない[16])

#comment
#topicpath


SIZE(10){現在のアクセス:&counter;}

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS