【コラム】

Java API、使ってますか?

3 古いAPIも進化している!? - JSR 919: JavaMail 1.4

3/60

はじめに - え、900番台のJSR?

JSRの追跡番号(JSR-XXX)は、原則としてJCP運営担当であるPMO(Program Management Office)が申請を受理した順番に付けられている。たとえば前回紹介したリアルタイムJava仕様はJSR-1なので、JCPが発足していちばん最初に申請されたJSRということになる。そして現時点ではJSR-310(Date and Time API)まで公開されているため、これが最も新しく登録されたJSRということだ。

ところで、JCPのサイトにはそれよりもさらに番号の大きい、900番台のJSRが公開されている。これら900番以降には、JCPが発足するよりも以前に策定されたAPI仕様などが多くJSRとして登録されている。たとえば以下のようなAPIがある。

  • JavaMail
  • Java Transaction API(JTA)
  • Java Media Framework(JMF)
  • Java 3D
  • Java Communication API
  • Java TV API 1.1

これらのAPIはJCPが発足した1998年以前にリリースされたものだが、900番以降のJSRとして登録することで、JCPの手順に沿ってその後のメンテナンス仕様をリリースしている。今回はそのような古いAPIの中から、Javaでメールの送受信を行うための「JSR 919: JavaMail」の使い方を紹介したい。

なお、900番台のJSRには上記APIのほかにもJavaの言語仕様やJVM仕様、J2SE 1.4仕様、Servlet仕様やJDBC仕様のエラッタシートなどが登録されている。

JavaMail 1.4

JavaMailはJavaで電子メールを送受信するための機能を提供する拡張パッケージとして1998年にVersion 1.0がリリースされた。その後2000年にそのメンテナンス版であるVersion 1.2の策定がJSR-904としてスタートし、現在はそのさらに後継バージョンとなるVersion 1.4がJSR-919として公開されている。

Version 1.4では以前のバージョンに対してたとえば次のような変更が加えられている。際立って大きな変更というものはないが、使い勝手は着実に向上しているはずだ。

  • エンコード済みのファイルを(再エンコードなしで)直接添付するためのPreencodedMimeBodyPartクラスの追加
  • IMAPにおける容量制限をIMAP APIに依存しないで実現するためのクラス/インタフェースを追加
  • バイト配列としてデータを保持するためのByteArrayDataSourceクラスを追加
  • バッキングストアからストリーム形式でデータを取得するSharedByteArrayInputStream/SharedFileInputStreamクラスの追加
  • MIMEタイプが"text"であるメッセージにテキストをセットするMimePart.setTextメソッドの追加
  • MimeMultipartクラスへのgetPreambleおよびsetPreambleメソッドの追加
  • MimeBodyPartクラスにファイルの添付や添付ファイルの保存を簡素化するためのメソッドを追加
  • 非ASCII文字のファイル名に対応するための、mail.mime.encodefilenameおよびdecodefilenameプロパティの追加
  • 適切に終了していないマルチパートデータに対応するためのmail.mime.multipart.ignoremissingendboundaryシステムプロパティの追加
  • MimePartDataSourceクラスのpartフィールドをprotectedへ変更
  • ParameterListクラスがUS-ASCII以外の文字コードもサポート

なお、JavaMailはJava SEには含まれていないが、Java EEにはコアパッケージとして含まれている。そしてその参照実装はGlassfishプロジェクトに寄贈された。Glassfish自身がSCSLのもとでオープンソースで公開されているため、JavaMailの参照実装のソースコードも同ライセンスに従って入手することができる。

JavaMailの使用方法

続いて、JavaMailの使用方法について簡単におさらいしてみよう。JavaMail 1.4の参照実装は単体ではこのサイトから入手することができる。その他、Java EEにはJavaMailの実装が含まれている。

JavaMail 1.4を使用するためには、同時にJavaBeans Activation Framework(JAF)も必要となる。JAF 1.1はJSR 926として標準仕様が決められており、Java SE 6やJava EE 5には標準APIとして同梱されている。単体の実装はこのサイトからダウンロードできる。

JavaMailを使用したプログラムを作成するには、ダウンロードしたファイルを解凍し、中に含まれているJARファイル(mail.jar)をクラスパスに含めてコンパイル→実行すればよい。

リスト1はSMTPを利用してメールを送信するプログラムの例だ。

リスト1 SMTPによるメール送信の例

package mailsample;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class MailSender {
    public MailSender() {
        Properties props = new Properties();
        // SMTPサーバーのURLを指定
        props.put("mail.smtp.host","example.co.jp");
        props.put("mail.host","example.co.jp");
        // セッションを確立
        Session session=Session.getDefaultInstance(props, null);
        // メッセージを作成
        MimeMessage mimeMessage = new MimeMessage(session);
        try {
            // 送信元メールアドレスと送信者名を指定
            mimeMessage.setFrom(new InternetAddress("takaaki@example.co.jp","杉山貴章", "iso-2022-jp"));
            // 送信先メールアドレスを指定
            mimeMessage.setRecipients(Message.RecipientType.TO,"sugiyama@example.jp");
            // メールのタイトルを指定
            mimeMessage.setSubject("JavaMailによるテストメール","iso-2022-jp");
            // メールの内容を指定
            mimeMessage.setText("これはテストメールです。","iso-2022-jp");
            // 送信日付を指定
            mimeMessage.setSentDate(new Date());
            // メールを送信
            Transport.send(mimeMessage);
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
        } catch (MessagingException ex) {
            ex.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        MailSender sample = new MailSender();
    }
}

JavaMailで提供されるクラス類はjavax.mail以下のパッケージに含まれている。メールを送信する最も一般的な手順は、まずSessionクラスを使用してSMTPサーバとのセッションを確立し、メールの本体をMessageクラスのインスタンスとして作成する。ここではMIME形式のメールを作成するためMimeMessageクラスを使用している。最後にTransportクラスのsendメソッドを利用してメールを送信する。

続いて、POPを利用してメールを受信するプログラムの例をリスト2に示す。ここではPOPサーバに接続してフォルダに溜まっているすべてのメールをダウンロードし、その内容を表示する。

リスト2 POPによるメール受信の例

package mailsample;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import javax.mail.Address;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeUtility;

public class MailPopper {
    public MailPopper() {
        // POPサーバに接続
        Session session = Session.getDefaultInstance(System.getProperties(), null);
        try {
            Store store = session.getStore("pop3");
            store.connect("example.jp", -1, "userid", "password");
            // フォルダを開く
            Folder folder = store.getFolder("INBOX");
            folder.open(Folder.READ_ONLY);
            // メッセージを取得
            Message[] messages = folder.getMessages();
            // メッセージを表示
            for (int i = 0; i < messages.length; i++) {
                Address[] addresses;
                // 差出人を表示
                if ((addresses = messages[i].getFrom()) != null) {
                    for (int j = 0; j < addresses.length; j++) {
                        System.out.println("差出人: " + MimeUtility.decodeText(addresses[j].toString()));
                    }
                }
                // 宛先を表示
                if ((addresses = messages[i].getRecipients(Message.RecipientType.TO)) != null) {
                    for (int j = 0; j < addresses.length; j++) {
                        System.out.println("宛先: " + MimeUtility.decodeText(addresses[j].toString()));
                    }
                }
                // 日付を表示
                Date date = messages[i].getSentDate();
                System.out.println("日付: " + (date != null ? date.toString() : "不明"));
                // タイトルを表示
                System.out.println("題名: " + messages[i].getSubject());
                // 内容を表示
                System.out.println("内容:\n" + messages[i].getContent());
            }
            // フォルダを閉じる
            folder.close(false);
            store.close();
        } catch (NoSuchProviderException ex) {
            ex.printStackTrace();
        } catch (MessagingException ex) {
            ex.printStackTrace();
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        MailPopper sample = new MailPopper();
    }
}

まずSessionクラスのインスタンスを生成し、getStoreメソッドにプロトコル(今回はpop3)を指定することでStoreインスタンスを取得する。そしてconnectメソッドを使用して任意のPOPサーバに接続した上で、getFolderメソッドで任意のフォルダのFolderオブジェクトを取得する。フォルダはopenメソッドで開くことができ、すべてのメールを取得するにはgetMessagesメソッドを使用する。メールはMessageオブジェクトとして返されるので、あとは各Messageから差出人やタイトル、本文などの情報を取得すればよい。

なお、MessageオブジェクトはisMimeTypeメソッドによってMIMEタイプを調べることができる。これによってHTMLメールやマルチパートメールなどを処理することも可能だ。また、添付ファイルがあるかどうかを調べるにはgetDispositionメソッドの返り値とPart.ATTACHMENTの値を比較すればよい。添付ファイルのファイル名はgetFileNameメソッドで取得できるため、そこからFileオブジェクトを生成してファイルを復元できる。

まとめ - 故きを温めて新しきを知る!?

JavaMailというと古くからのJavaユーザには「何を今さら」と思われてしまうかもしれない。しかしこのようなJSRの900番台に位置するAPIには、Javaアプリケーションを開発する上で必要不可欠なものも多く、現在も保守フェーズに入って改良が重ねられている。中にはオープンソース化されたりサードパーティによる実装が公開されているものもある。成熟した古いAPIだからこそ最新の情報をチェックしてみる価値があるだろう。

提供:毎日就職ナビ

会員登録はこちら

学生のための就職情報サイト「毎日就職ナビ」。6,000社以上の新卒採用情報が常時掲載され、社内の雰囲気が伝わる情報画面、さまざまな項目での会社検索、エントリーや説明会検索など、機能も充実。無料適職診断、就活Q & A、エントリーシート添削講座など、就職活動に役立つ記事も満載です。研究者、エンジニアを目指す学生の方々も是非エントリーしてください。お待ちしています!

毎日コミュニケーションズはプライバシーマークを取得しています。

3/60

インデックス

連載目次
第60回 どうなる? 今後のJavaプラットフォーム(Java SE編)
第59回 どうなる? 今後のJavaプラットフォーム(Java EE編)
第58回 Java SE 7の要注目機能"クロージャ"はどうなるのか その6
第57回 Java SE 7の要注目機能"クロージャ"はどうなるのか その5
第56回 Java SE 7の要注目機能"クロージャ"はどうなるのか その4
第55回 Java SE 7の要注目機能"クロージャ"はどうなるのか その3
第54回 Java SE 7の要注目機能"クロージャ"はどうなるのか その2
第53回 Java SE 7の要注目機能"クロージャ"はどうなるのか
第52回 Early Draftが公開されたJSF 2.0
第51回 EJBから独立したJava Persistence 2.0
第50回 モバイルJavaの新しい潮流となるか - MSA 2.0のドラフト公開
第49回 やっぱり基本はServlet - Servlet 3.0のEarly Draftを読む
第48回 JOGLで3Dプログラミング その4
第47回 JOGLで3Dプログラミング その3
第46回 JOGLで3Dプログラミング その2
第45回 JOGLで3Dプログラミング
第44回 JARファイルを効率的にネットワーク転送するためのPack200形式
第43回 Early Draftで把握するEJB 3.1の新機能
第42回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その2
第41回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その1
第40回 リソースアダプタによる接続の仕組み
第39回 JCAを利用したシステム間接続
第38回 Java EEと外部システムの接続性を支えるJCAがバージョンアップ
第37回 Javaのモジュラリティ強化を担う"スーパーパッケージ"とは
第36回 JSR 308対応のコンパイラを試す
第35回 公開されたJSR 308のEarly Draftを検証する
第34回 スクリプト言語とJavaを結びつけるJSR 223
第33回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その2
第32回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その1
第31回 Javaの文法がそのまま使えるスクリプト言語"BeanShell"
第30回 Javaアプリケーションにオブジェクトのキャッシュ機構を提供するJCache API
第29回 Javaアプリケーションからのリソース管理を可能にするJSR 284
第28回 XMLデータソースへの問い合わせはJSR 225で
第27回 Portlet Specification 2.0をもっと手軽に利用する
第26回 次期Javaポートレット仕様となるJSR 286
第25回 JSFとポートレットをつなげるJSR 301
第24回 Webサービス向けのポートレット仕様「WSRP」
第23回 高い相互運用性を実現するポートレットAPI - JSR 168
第22回 Java EE環境でタスクのスケジューリングを可能にするJSR 236
第21回 Java EE環境でのスレッドプログラミングを可能にするJSR 237
第20回 音声認識/合成のためのAPI - Java Speech APIとJSR 113
第19回 JSR 291でJavaプラットフォームにダイナミックコンポーネントモデルを導入
第18回 JAX-RSで簡単RESTful - JSR 311
第17回 待望のServlet 3.0がJSRに登場 - JSR 315
第16回 アノテーションを使ってバグ退治 - JSR 305
第15回 アノテーションをさらに広い範囲で利用可能にするJSR 308
第14回 Webアプリケーション開発の要となるか - JSF 2.0がJSRに登場
第13回 Webサービス経由でのJMX Agentへの接続を可能にするJSR 262
第12回 Javaアプリケーションのモジュール化をサポートするJava Module System
第11回 "NIO.2"がやってきた - JSR 203: More New I/O APIs for the Java Platform
第10回 JSR 295: Beans Bindingの参照実装を試す
第9回 けっこう便利! 単位を扱うAPI -- JSR 275: Units Specification
第8回 アノテーションでバリデーション - JSR 303: Bean Validator
第7回 Swing開発の救世主となるか - Swing Application Framework
第6回 JavaBeansのプロパティを同期させるバインディングAPI
第5回 誰よりも早く"Java SE 7"を睨む
第4回 日時情報の取り扱いを改善する JSR 310: Date and Time API
第3回 古いAPIも進化している!? - JSR 919: JavaMail 1.4
第2回 JSR 1 リアルタイムJava仕様
第1回 JCPによって進められるJava関連技術の標準化

もっと見る



人気記事

一覧

イチオシ記事

新着記事