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