JavaMail APIを使用した電子メールの送信

概要

    目的

    このチュートリアルでは、JavaMail APIを使用してJava EEアプリケーションから電子メールを送信する方法について説明します。

    所要時間

    約45分

    はじめに

    JavaMail APIは、メール・システム・コンポーネントを表すクラスを定義します。 JavaMailはメール・サーバーを実装する代わりに、Java APIを使用して電子メール・サーバーへアクセスできるようにしています。 このチュートリアルで示したコードをテストするには、電子メール・サーバーへのアクセスが必要です。 JavaMail API仕様では特定プロトコルのサポートを義務付けていませんが、通常、JavaMailにはPOP3、IMAP、SMTPのサポートが含まれています。 このチュートリアルでは電子メール・メッセージの送信について説明しています。また、必要になるのはSMTPサーバーへのアクセスのみです。

    シナリオ

    Javaアプリケーションからの電子メールの送信には実際に役立つ多数の用途があります。 たとえば、Webアプリケーションで訪問者がアカウントを作成できるとします。 アカウント作成プロセスの途中で一意のアクティブ化コードを含む電子メールを送信することで、申込み時に指定された電子メール・アドレスが有効であるかどうかを確認できます。 また、オンライン・ショッピング・アプリケーションは一般に、電子メールを介して注文情報やステータスを購入者に通知します。

    ハードウェアとソフトウェアの要件

    ハードウェアとソフトウェアの要件リストは、以下のとおりです。

    • こちらのリンクからJava JDK 7をダウンロードし、インストールしていること。
    • こちらのリンクから、Java EEを含むNetBeans 7.1.2などのIDEおよびアプリケーション・サーバーをダウンロードし、インストールしていること。Java EEを含むNetBeans 7.1.2には、GlassFish 3.1.2(Java EEダウンロード・バンドル)が含まれています。 インストール中に、GlassFishをインストールするためのチェック・ボックスを必ず選択してください。 JUnitのインストールは省略可能であり、このチュートリアルには必要ありません。
    • SMTPサーバーへのアクセス。
    • SMTPサーバーに対して有効な資格証明(ユーザー名とパスワード)。
    • このチュートリアルで作成するプロジェクトはこちらからダウンロードできます。

    前提条件

    このチュートリアルを始める前に以下のことを確認してください。

    • SMTPサーバーへアクセスできること。 SMTPサーバーのホスト名、ポート番号、セキュリティ設定を把握している必要があります。 Webメール・プロバイダによっては、SMTPアクセスを提供し、電子メール・アカウントの設定を表示し、追加情報を確認できるようにしている場合があります。 多くの場合、ユーザー名は@記号の前にある名前だけでなく、電子メール・アドレス全体である点に注意してください。
    • Java EE IDEと、GlassFishまたはOracle WebLogic Serverなどのアプリケーション・サーバー。 JavaMailをダウンロードし、ライブラリとしてJava SEアプリケーションで使用することも可能ですが、このチュートリアルでは、あらかじめJavaMailを含んだJava EEアプリケーション・サーバーの使用を前提としています。
    • サーブレットやセッションEJBに対する基本的な知識があること(セッションEJBは便利ですが、必須ではありません)。

Java EE Webアプリケーションの作成

    Java EE Webアプリケーション(WAR)プロジェクトを作成するには、NetBeans IDEで次の手順を実行します。

    新規アプリケーションを作成します。

    NetBeansメニューから「File」→「New Project」を選択します。

    Java Web」カテゴリと「Web Application」プロジェクト・タイプを選択します。

    Next」をクリックします。

    Project NameにEmailSenderと入力します。

    Next」をクリックします。

    Serverとして「GlassFish Server 3.1.2」(またはその他のJava EE 6フル・プロファイル・サーバー)を選択します。

    Java EE Versionとして「Java EE 6 Web」を選択します。 こうすることで、Webプロジェクト内でセッションEJBを作成できるようになります。 Java EE 5の場合、EJB用の別プロジェクトが必要になります。

    Finish」をクリックします。

    以上で、index.jspファイルを含むWebアプリケーション・プロジェクトが作成されました。

JSP、サーブレット、EJB必須コンポーネントの作成

    ここでは、ユーザーが電子メールの受信者、件名、メッセージ本文を指定するためのフォームを含むJSPを作成します。 このフォームがサーブレットに送信され、サーブレットによってフォーム・パラメータが読み取られます。 サーブレットは、これから作成するセッションEJBのsendEmailメソッドに対してフォーム・パラメータを渡します。

    セッションEJB

      com.example.EmailSessionBeanクラスを作成します。 このクラスはローカル・インタフェースのステートレス・セッションEJBです。 後半の項で、EmailSessionBeanにJavaMail機能を追加します。

      EmailSender」プロジェクトを右クリックして、「New」→「Other」を選択します。

      New Fileウィンドウで、カテゴリとして「Enterprise JavaBeans」を、ファイル・タイプとして「Session Bean」を選択します。

      Next」をクリックします。

      EJB名としてEmailSessionBeanを入力します。

      EmailSessionBeanのパッケージ名としてcom.exampleと入力し、セッション・タイプとして「Stateless」を選び、Create Interfaceのチェック・ボックスは選択しません。

      Finish」をクリックします。

      sendEmailというメソッドをEmailSessionBeanに追加します。

      sendEmailメソッドに、tosubjectbodyという3つのStringパラメータを指定します。

      com.example.EmailSessionBeanクラスを保存します。

      sendEmailメソッドの実装は、すべてのアプリケーション・コンポーネントを作成した後の項で完了します。

    サーブレット

      com.example.EmailServletクラスを作成します。

      EmailSender」プロジェクトを右クリックして、「New」→「Other」を選択します。

      New Fileウィンドウで、カテゴリとして「Web」を、ファイル・タイプとして「Servlet」を選択します。

      Next」をクリックします。

      サーブレット名としてEmailServletを入力します。

      EmailServletのパッケージ名としてcom.exampleを指定します。

      Finish」をクリックします。

      emailBeanという名前のEmailSessionBeanフィールドをEmailServletに追加します。

      EmailSessionBeanへ参照を注入するため、emailBeanフィールドに対して@EJB注釈を使用します。

      @EJB
      private EmailSessionBean emailBean;
                                                      

      processRequestメソッド内で、tosubjectbodyフォーム・パラメータの値を読み取り、保存します。

      String to = request.getParameter("to");
      String subject = request.getParameter("subject");
      String body = request.getParameter("body");

      emailBean.sendEmailメソッドを呼び出し、tosubjectbodyの値を引数として渡します。

      emailBean.sendEmail(to, subject, body);

      このチュートリアルでは実施していませんが、本番品質の公開アプリケーションではすべてのフォーム・パラメータを検証する必要があります。 JavaMail APIには電子メール・アドレスの形式を検証する機能が含まれています。 ただし、電子メール・アドレスの存在を確認する唯一の方法は、このアドレスに電子メールを送信してみることです。

      javax.mail.internet.InternetAddress ia = new javax.mail.internet.InternetAddress(to);
      try {
          ia.validate();
      } catch (javax.mail.internet.AddressException ae) {
      
      }

      EmailServletを変更して、フォームが送信されたことを示すHTML出力を生成します。

    JSP

      EmailSenderプロジェクトのWeb Pages部分から既存のindex.jspファイルを開きます。

      index.jspファイルを変更して、次に示す出力を生成します。

      ページのタイトルと見出しを変更し、Emailと表示します。

      index.jspページのボディに対して、tosubjectというテキスト入力フィールドとbodyというテキスト領域を含むフォームを追加します。

      <form method="POST" action="EmailServlet">
          <label for="to">To:</label><input id="to" name="to" type="text"/><br/>
          <label for="subject">Subject:</label><input id="subject" name="subject" type="text"/><br/>
          <textarea name="body" cols="60" rows="15"></textarea><br/>
          <input type="submit" value="Send"/>
      </form>

      以上で、EmailSenderプロジェクトをデプロイし、実行する準備が整いました。 この時点では、フォームを送信しても電子メールは送信されません。 次の項で、電子メールの送信機能を追加します。

JavaMail APIを使用したプレーン・テキスト・メールの送信

    ここでは、JavaMail APIを使用してプレーン・テキストの電子メールを送信します。

    Protocol列挙

      電子メールを送信するために使用できるプロトコル(SMTP、SMTPS、またはSMTP over TLS)を表す列挙を作成します。

      com.example.Protocol列挙を作成します。

      EmailSender」プロジェクトを右クリックして、「New」→「Other」を選択します。

      New Fileウィンドウで、カテゴリとして「Java」を、ファイル・タイプとして「Java Enum」を選択します。

      Next」をクリックします。

      列挙名としてProtocolを入力します。

      Protocolのパッケージ名としてcom.exampleを指定します。

      Finish」をクリックします。

      Protocol列挙を変更し、SMTPSMTPSTLSという3つのフィールドを追加します。

      public enum Protocol {
          SMTP,
          SMTPS,
          TLS
      }

    EmailSessionBeanクラス

      EmailSessionBeanクラスを開きます。

      電子メールの送信に必要なすべての情報を含むプライベート・フィールドを追加します。

      private int port = 465;
      private String host = "smtp.example.com";
      private String from = "matt@example.com";
      private boolean auth = true;
      private String username = "matt@example.com";
      private String password = "secretpw";
      private Protocol protocol = Protocol.SMTPS;
      private boolean debug = true;

      使用するSMTPサーバーに合わせてこれらのフィールド値を変更してください。

      Propertiesオブジェクトを作成し、SMTPプロトコル・プロバイダの設定を追加します。 こちらcom.sun.mail.smtpパッケージから、指定できるプロパティとその説明の一覧を参照できます。

      Properties props = new Properties();
      props.put("mail.smtp.host", host);
      props.put("mail.smtp.port", port);
      switch (protocol) {
          case SMTPS:
              props.put("mail.smtp.ssl.enable", true);
              break;
          case TLS:
              props.put("mail.smtp.starttls.enable", true);
              break;
      }

      SMTP認証が必要である場合、mail.smtp.authプロパティを設定してAuthenticatorインスタンスを構築し、ユーザー名とパスワードを含んだPasswordAuthenticationインスタンスを返す必要があります。

      Authenticator authenticator = null;
      if (auth) {
          props.put("mail.smtp.auth", true);
          authenticator = new Authenticator() {
              private PasswordAuthentication pa = new PasswordAuthentication(username, password);
              @Override
              public PasswordAuthentication getPasswordAuthentication() {
                  return pa;
              }
          };
      }

      PropertiesオブジェクトとAuthenticatorオブジェクトを使用して、Sessionインスタンスを作成します。 SMTP認証が必要でない場合は、Authenticatornullを指定します。

      Session session = Session.getInstance(props, authenticator);
      session.setDebug(debug);

      session.setDebug(boolean)メソッドを使用すると、現在のセッション・アクティビティを出力できます。

      MimeMessageインスタンスを構築し、メッセージ・ヘッダーとコンテンツを移入したら、メッセージを送信します。

      MimeMessage message = new MimeMessage(session);
      try {
          message.setFrom(new InternetAddress(from));
          InternetAddress[] address = {new InternetAddress(to)};
          message.setRecipients(Message.RecipientType.TO, address);
          message.setSubject(subject);
          message.setSentDate(new Date());
          message.setText(body);
          Transport.send(message);
      } catch (MessagingException ex) {
          ex.printStackTrace();
      }

      Fix Importウィザードを実行し([Ctrl]と[Shift]を押しながら[I]を押す)、必要なインポートを追加します。

      アプリケーションをデプロイし、実行します。

      自分宛ての電子メールを作成します。

      Send」を押すと、フォームに指定した宛先に電子メールが送信されます。

      受信ボックスをチェックし、メッセージが到着しているかどうかを確認します。

      エラーが発生した場合、NetBeansのGlassFish Server Outputタブでデバッグ出力を確認します。

JavaMail APIを使用したHTMLメールの送信

    ここでは、HTMLメールの送信方法について説明します。 EmailSessionBeanクラスを変更し、HTMLボディとその代替であるプレーン・テキストから成るメッセージを送信します。 電子メールの受信者がHTMLバージョンのコンテンツを参照できない場合、代わりにプレーン・テキストが表示されます。

    EmailSessionBean」クラスを開きます。

    message.setText(body);という行を探し、コメント・アウトします。

    サブタイプとしてalternativeを指定したMimeMultipartインスタンスを作成します。 マルチパート・メッセージは複数の要素で構成されたメッセージであり、このケースではHTMLとテキスト・メッセージになります(その他に考えられる要素は添付ファイル)。 alternativeサブタイプは、複数のメッセージ要素が同じコンテンツの代替バージョンであることを示しています。

    Multipart multipart = new MimeMultipart("alternative");

    テキスト・ボディ部分を含むMimeBodyPartインスタンスを作成します。

    MimeBodyPart textPart = new MimeBodyPart();
    String textContent = "Hi, Nice to meet you!";
    textPart.setText(textContent);

    HTMLボディ部分を含むMimeBodyPartインスタンスを作成します。 ここでは順序が重要です。代替マルチパート・メッセージのうち、優先される形式を最後に追加します。

    MimeBodyPart htmlPart = new MimeBodyPart();
    String htmlContent = "<html><h1>Hi</h1><p>Nice to meet you!</p></html>";
    htmlPart.setContent(htmlContent, "text/html");

    両方のMimeBodyPartインスタンスをMimeMultipartインスタンスに追加し、MimeMultipartインスタンスをMimeMessageとして設定します。

    multipart.addBodyPart(textPart);
    multipart.addBodyPart(htmlPart);
    message.setContent(multipart);

    Transport.send(message);を使用してメッセージを送信します(プレーン・テキストの例と同じ)。

    Fix Importウィザードを実行し([Ctrl]と[Shift]を押しながら[I]を押す)、必要なインポートを追加します。

    アプリケーションをデプロイし、実行します。 電子メール読取りアプリケーションでHTMLメールがサポートされている場合、電子メールにさまざまなフォント・サイズが表示されるはずです。

詳細情報

    JavaMailアプリケーションの開発に役立つ関連情報を次に示します。

    デバッグを使用したJavaMail問題のトラブルシューティング

    session.setDebug(boolean)メソッドを使用するとデバッグ出力が有効化され、通信や認可の問題が発生しているかどうかを特定するために役立ちます。

    稼働中の本番環境ではデバッグを無効にする必要があります。

    SMTP認証を使用したユーザー名とパスワードの検証(電子メールの送信にはログインが必要)

    通常、パスワードでは大文字と小文字を区別する必要があります。

    多くの場合、ユーザー名には名前だけでなく完全な電子メール・アドレス(matt@example.com)を指定します。

    住宅用のインターネット・サービス・プロバイダ(ISP)では、SMTP関連ポートがブロックされがちです(もっとも多くブロックされるのは25)。

    Thunderbirdなどのローカルの電子メールクライアントを構成および使用して、接続と設定を検証してください。

    SMTPサーバーでは送信メッセージ数が制限される場合があります。

    機能中の送信が突然停止した場合、送信メッセージの制限を超えている可能性があります。 しばらく(おそらくは数時間)待つと、メッセージの送信機能が回復する場合もあります。

    大量のメッセージを送信するには、場合によって、ビジネス・クラスの有料SMTPアカウントを契約するか、独自のSMTPサーバーをセットアップする必要があります。

    SPAM送信の助長回避

    このチュートリアルの例を使用すると、誰でも、アプリケーション内に記述されたアドレスから任意の宛先に電子メールを送信することができます。 この例をそのまま一般のWebサイトで公開することは、お勧めできません。

    Webメール・アカウントによっては、SMTPアクセスを提供していない場合があります。

    すべてのWebメール・プロバイダがSMTPアクセスを提供している訳ではなく、 SMTPアクセスに料金が課されるケースもあれば、ユーザー側での有効化が必要になるケースもあります。

    Webメール・アカウントにSMTPの有効化オプションが見当たらない場合、IMAPまたはPOP3アクセスを有効化してください。

    JavaMailでは、自己署名付き証明書を特別な方法で処理する必要があります。

    独自のSMTPサーバーに自己署名付き証明書を構成している場合、特別な処理が必要になります。 次のWebサイトを参照してください。 http://www.oracle.com/technetwork/java/javamail145sslnotes-1562622.html

    セキュアなSMTP(SMTPSまたはSMTP over TLS)

    SMTPSを使用した場合、ネットワーク接続は最初から暗号化されます。

    SMTP over TLSは暗号化されていないSMTP接続として開始された後で、TLSを使用してセキュア接続に格上げされます。

    SMTPSとTLSは同じものではありません。 SMTPSは通常ポート465を使用しますが、TLSはポート25を使用し、場合によっては587などの代替ポートを使用します。

    それぞれのSMTPサーバーに規定されたメカニズムを使用してください。 一部のSMTPプロバイダは、両方のメカニズムをサポートしています。

    ユーザー名とパスワード(SMTP認証)を必要とするSMTPサーバーの場合、ユーザー名とパスワードが暗号化されないままインターネット上に送信されることを防ぐため、通常はセキュア接続も必要になります。

    非同期での電子メールの送信

    EJB 3.1(Java EE 6)のSession Beanメソッドには、@Asynchronousという注釈を付加できます。 非同期メソッドを呼び出すと、すぐに制御が戻されます。

まとめ

    このチュートリアルで学習した内容は、以下のとおりです。

    • JavaMailを使用したプレーン・テキスト・メールの送信
    • JavaMailを使用したHTMLメールの送信

    参考資料

    著者

    • Lead Curriculum Developer: Matt Heimer

このOracle by Exampleをナビゲートする際、次の機能を使用できます。

ヘッダー・ボタンの非表示:
ヘッダー内のボタンを非表示にするには、タイトルをクリックします。 ボタンを再表示するには、もう一度タイトルをクリックします。
トピック一覧ボタン:
すべてのトピックの一覧です。 いずれかのトピックをクリックすると、その項に移動します。
すべてのトピックを開く/閉じる:
すべての項に対する詳細を表示または非表示にします。 デフォルトでは、すべてのトピックが閉じられています。
すべてのイメージを表示/非表示:
すべてのスクリーンショットを表示または非表示にします。 デフォルトでは、すべてのイメージが表示されています。
印刷:
コンテンツを印刷します。 現在表示または非表示にされているコンテンツが印刷されます。

このチュートリアルの特定の項に移動するには、一覧からトピックを選択してください。