POP3クライアントをSocketとJavaMailで作る その1
はじめに
表題の通り,POP3クライアントをSocketとJavaMailを使って作り比べてみよう.
まず,動作環境は以下の通り.
- Microsoft Windows XP Professional SP1a
- Java 2 SDK Standard Edition 1.4.2_04
- JavaMail 1.3.1
- JAF(JavaBeans Activation Framework) 1.0.2
こんな要件としよう.プログラムを単純にするために,GUIは使わずコマンドラインだ.
- プログラムを起動すると,コマンドラインにread:を表示してコマンドの入力を待つ
- 入力可能なコマンドはlist/read/quitの3種類
- listでメールサーバにあるメールの件数を表示
- read NでN番目のメールの内容を表示.例えば,2通目のメールを表示する場合はread 2と入力
- quitでプログラムを終了
- 受信したメールはそのままサーバに残す
Socket版
まずはSocket版のプログラムである.いきなりだが,こんなソースになった.ポート番号110でメールサーバとのSocketを作成し,BufferedReader/BufferedWriterでコマンドと結果をやり取りしている.
import java.net.Socket; import java.io.*; public class Pop3{ private Socket mailserver; private BufferedReader reader; private BufferedWriter writer; public Pop3() throws Exception{ final String servername="mailserver"; //適当なメールサーバに書換える final String username="username"; //適当なユーザに書換える final String password="password"; //適当なパスワードに書換える mailserver=new Socket(servername,110); reader=new BufferedReader(new InputStreamReader(mailserver.getInputStream())); writer=new BufferedWriter(new OutputStreamWriter(mailserver.getOutputStream())); if(isReady()&&isReady("user "+username)&&isReady("pass "+password)){ //メールサーバにログインできれば何もしない } else{ mailserver.close(); } } private boolean isReady() throws IOException{ final boolean OK=true; final boolean NG=!OK; return reader.readLine().matches("^\\+OK.*$")? OK: NG; } private boolean isReady(String message) throws IOException{ final String end="\r\n"; writer.write(message+end); writer.flush(); //コマンドをメールサーバに送って return isReady(); //結果を判定 } public void transaction() throws Exception{ BufferedReader reader=new BufferedReader(new InputStreamReader(System.in)); while(!mailserver.isClosed()){ System.out.print("ready: "); String command=reader.readLine(); if(command.equalsIgnoreCase("quit")){ if(isReady(command)){ mailserver.close(); } } else if(command.equalsIgnoreCase("list")){ if(isReady(command)){ System.out.println(getMessage().split(" ")[0]); //件数とバイト数を受取る.件数のみ表示 } } else if(command.matches("(?i)^read \\d+$")){ if(isReady(command.replaceFirst("read","retr"))){ System.out.println(getMessage()); } } else{ System.out.println("ignore: "+command); } } } private String getMessage() throws IOException{ StringBuffer message=new StringBuffer(); while(true){ String s=reader.readLine(); if(s.equals(".")){ if(message.length()>0){ message.deleteCharAt(message.length()-1); //つけすぎた改行を削除 } break; } else{ message.append(s+"\n"); } } return message.toString(); } public static void main(String[] args){ try{ Pop3 pop3=new Pop3(); pop3.transaction(); } catch(Exception e){ e.printStackTrace(); } } }
プログラムとメールサーバとのやり取りを図にするとこのようになる.
JavaMailをダウンロード&インストール
Socket版の次はJavaMail版を作成する.その前に,JavaMailのダウンロードとインストールを行う.
JavaMail APIからJavaMailを,JavaBeans Activation FrameworkからJAFダウンロードする.ダウンロードしたアーカイブからそれぞれmail.jarとactivation.jarを取り出し,CLASSPATHに設定したディレクトリに置く.今回は${JAVA_HOME}\jre\lib\extに配置した.${JAVA_HOME}はJDKをインストールしたディレクトリを表す.
JavaMail版
Socketを使用した場合は,メールサーバとサーバとコマンドや結果をやり取りするストリームが必要だった.JavaMailを使用すると,Session/Store/Folderを使用してメールの受信ができる.以下のような手順である.
- メールサーバとの間にSessionを作成
- SessionからStoreを取得
- StoreからFolderを取得
- Folderのメソッドを使ってメールを受信
import java.io.*; import java.util.Properties; import javax.mail.*; import javax.mail.internet.*; public class Pop3{ private Store store; private Folder folder; public Pop3() throws Exception{ Properties prop=new Properties(); prop.put("mail.host","mailserver"); //適当なメールサーバに書換える prop.put("mail.store.protocol","pop3"); //"pop3"固定 Session session=Session.getDefaultInstance(prop,new Authenticator(){ //メールサーバとの間にSessionを作成 protected PasswordAuthentication getPasswordAuthentication(){ return new PasswordAuthentication("username","password"); //適当なユーザ名とパスワードに書換える } }); store=session.getStore(); //SessionからStoreを取得 store.connect(); folder = store.getFolder("INBOX"); //SessionからFolderを取得.名称は"INBOX"固定 folder.open(Folder.READ_ONLY); } private void transaction() throws Exception{ BufferedReader reader=new BufferedReader(new InputStreamReader(System.in)); while(store.isConnected()){ System.out.print("ready: "); String command=reader.readLine(); if(command.equalsIgnoreCase("quit")){ folder.close(false); store.close(); } else if(command.equalsIgnoreCase("list")){ System.out.println(folder.getMessageCount()); } else if(command.matches("(?i)^read \\d+$")){ folder.getMessage(Integer.parseInt(command.replaceAll("read\\s",""))).writeTo(System.out); } else{ System.out.println("ignore: "+command); } } } public static void main(String[] args){ try{ Pop3 pop3=new Pop3(); pop3.transaction(); } catch(Exception e){ e.printStackTrace(); } } }
プログラムとSession/Store/Folderとのやり取りを図にするとこのようになる.
参考文献・サイト
- 北山洋幸著,Javaによるはじめてのインターネットプログラミング,技術評論社
- JavaでHello Workd JavaMail(POP)編
- JavaMail API
- JavaBeans Activation Framework
- Jude...Java and UML Developers' Environment