JavaアプリケーションからEメールを送信するサンプルコード

  • 56
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

概要

Eメールを送信するJavaアプリケーションのサンプルコードです。JavaMail、Commons Email、Spring Boot Starter mailの3つのライブラリを試しました。

環境

  • Windows7 (64bit)
  • Java 1.8.0_65
  • JavaMail 1.5.4
  • Spring Boot 1.3.0
    • spring-boot-starter-mail 1.3.0
  • Commons Email 1.4

参考

JavaMail

準備

pom.xml
<dependency>
  <groupId>com.sun.mail</groupId>
  <artifactId>javax.mail</artifactId>
  <version>1.5.4</version>
</dependency>

properties

Package javax.mail

mail.user=
mail.host=
mail.from=
mail.mime.address.strict=true
mail.store.protocol=imap
mail.transport.protocol=smtp
mail.debug=false                # debug出力

Package com.sun.mail.smtp

An SMTP protocol provider for the JavaMail API that provides access to an SMTP server.

mail.smtp.user=
mail.smtp.host=
mail.smtp.port=
mail.smtp.from=
mail.smtp.connectiontimeout=0    # コネクション確立までのタイムアウト時間(ミリ秒)
mail.smtp.timeout=0              # SMTPサーバとの通信(read)のタイムアウト時間(ミリ秒)
mail.smtp.writetimeout=0         # ソケットの書き込みのタイムアウト時間(ミリ秒)
mail.smtp.auth=false             # authコマンドでのユーザー認証を行うか
mail.smtp.ssl.enable=false       #
mail.smtp.starttls.enable=false  #
mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory   # ssl
mail.smtp.socketFactory.fallback=false                         # ssl
mail.smtp.socketFactory.port=                                  # ssl

サンプルコード

import java.io.UnsupportedEncodingException;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class JavaMailSample {
  private static final Logger log = LoggerFactory.getLogger(JavaMailSample.class);

  public static void main(String[] args) {
    JavaMailSample mailSend = new JavaMailSample();
    mailSend.send("JavaMail テストメール", "テストメールの本文");
  }

  public void send(String subject, String content) {

    final String to = "xxx.yyy.zzz@example.com";
    final String from = "*****.*****.*****@gmail.com";

    // Google account mail address
    final String username = "*****.*****.*****@gmail.com";
    // Google App password
    final String password = "***************";

    //final String charset = "ISO-2022-JP";
    final String charset = "UTF-8";

    final String encoding = "base64";

    // for gmail
    String host = "smtp.gmail.com";
    String port = "587";
    String starttls = "true";

    // for local
    //String host = "localhost";
    //String port = "2525";
    //String starttls = "false";

    Properties props = new Properties();
    props.put("mail.smtp.host", host);
    props.put("mail.smtp.port", port);
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.starttls.enable", starttls);

    props.put("mail.smtp.connectiontimeout", "10000");
    props.put("mail.smtp.timeout", "10000");

    props.put("mail.debug", "true");

    Session session = Session.getInstance(props,
    new javax.mail.Authenticator() {
       protected PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication(username, password);
       }
    });

    try {
      MimeMessage message = new MimeMessage(session);

      // Set From:
      message.setFrom(new InternetAddress(from, "Watanabe Shin"));
      // Set ReplyTo:
      message.setReplyTo(new Address[]{new InternetAddress(from)});
      // Set To:
      message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));

      message.setSubject(subject, charset);
      message.setText(content, charset);

      message.setHeader("Content-Transfer-Encoding", encoding);

      Transport.send(message);

    } catch (MessagingException e) {
      throw new RuntimeException(e);
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }

  }

}

Commons Email

準備

pom.xml
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-email</artifactId>
  <version>1.4</version>
</dependency>

サンプルコード

package com.example.sbmail.mail;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.mail.DefaultAuthenticator;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;
import org.springframework.stereotype.Component;

@Component
public class CommonsMailSample {

  private String to = "xxx.yyy.zzz@example.com";
  private String from = "*****.*****.*****@gmail.com";

  // Google account mail address
  private String username = "*****.*****.*****@gmail.com";
  // Google app password
  private String password = "**********";

  //private String charset = "ISO-2022-JP";
  private String charset = "UTF-8";

  private String encoding = "base64";

  // for gmail
  private String host = "smtp.gmail.com";
  private int port = 587;
  private boolean starttls = true;

  // for local
  //private String host = "localhost";
  //private int port = 2525;
  //private boolean starttls = false;

  private Map<String, String> headers = new HashMap<String, String>(){
    private static final long serialVersionUID = 1L;
    {
      put("Content-Transfer-Encoding", encoding);
    }
  };

  public static void main(String[] args) throws IOException {
    CommonsMailSample sendMail = new CommonsMailSample();
    sendMail.send("Commons Email テストメール", "テストメールの本文");
  }

  public void send(String subject, String content) {

    Email email = new SimpleEmail();

    try {
      email.setHostName(host);
      email.setSmtpPort(port);
      email.setCharset(charset);
      email.setHeaders(headers);
      email.setAuthenticator(new DefaultAuthenticator(username, password));
      email.setStartTLSEnabled(starttls);
      email.setFrom(from);
      email.addTo(to);
      email.setSubject(subject);
      email.setMsg(content);
      email.setDebug(true);

      email.send();

    } catch (EmailException e) {
      e.printStackTrace();
    }
  }

}

spring-boot-starter-mail

準備

pom.xml
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-mail</artifactId>
  <version>1.3.0.RELEASE</version>
</dependency>

<dependency>
  <groupId>com.sun.mail</groupId>
  <artifactId>javax.mail</artifactId>
</dependency>

properties

MailProperties.java

application.yml
spring:
# Email (MailProperties)
  mail:
    default-encoding: UTF-8
    protocol: smtp
    #host: localhost
    #port: 2525
    host: smtp.gmail.com
    port: 587
    jndi-name: mail/Session
    password: ********** # Google App password
    username: *****.*****.*****@gmail.com # Google account mail address
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            #enable: false
            enable: true
          socketFactory:
            #port: 2525
            port: 587
            class: javax.net.ssl.SSLSocketFactory
            fallback: false
        debug: true
    test-connection: false

MailSenderAutoConfiguration.java

サンプルコード

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;

@Component
public class SpringBootMailSample {
  private static final Logger log = LoggerFactory.getLogger(SpringBootMailSample.class);

  private final JavaMailSender javaMailSender;

  @Autowired
  SpringBootMailSample(JavaMailSender javaMailSender) {
    this.javaMailSender = javaMailSender;
  }

  public SimpleMailMessage send(String subject, String content) {

    SimpleMailMessage mailMessage = new SimpleMailMessage();

    mailMessage.setTo("xxx.yyy.zzz@example.com");
    mailMessage.setReplyTo("*****.*****.*****@gmail.com");
    mailMessage.setFrom("*****.*****.*****@gmail.com");
    mailMessage.setSubject(subject);
    mailMessage.setText(content);

    javaMailSender.send(mailMessage);

    return mailMessage;
  }

}
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;

@Component
public class SpringBootMailSample2 {
  private static final Logger log = LoggerFactory.getLogger(SpringBootMailSample2.class);

  private final JavaMailSender javaMailSender;

  @Autowired
  public SpringBootMailSample2(JavaMailSender javaMailSender) {
    this.javaMailSender = javaMailSender;
  }

  public void send(String subject, String content) {

    try {

      MimeMessage mail = javaMailSender.createMimeMessage();

      mail.setHeader("Content-Transfer-Encoding", "base64");

      MimeMessageHelper helper = new MimeMessageHelper(mail, false);

      helper.setTo("xxx.yyy.zzz@example.com");
      helper.setReplyTo("*****.*****.*****@gmail.com");
      helper.setFrom("*****.*****.*****@gmail.com");
      helper.setSubject(subject);
      helper.setText(content);

      javaMailSender.send(mail);

    } catch (MessagingException e) {
      e.printStackTrace();
    }

  }

}

開発用SMTPサーバー

ローカル環境でメールの送信テストを行いたい場合に使用する開発用SMTPサーバーを幾つか試用しました。

FakeSMTP

Dummy SMTP server with GUI for testing emails in applications easily.

Javaで開発されているので実行環境を選びません。受信したメールをeml形式のファイルとして保存することができます。
日本語(ISO-2020-JP,UTF-8)で書かれたメールにも対応しています。

ビルド

ソースコードからビルドしてjarファイルを生成します。(ビルド済みのjarを取得して使用することもできます)

$ git clone https://github.com/Nilhcem/FakeSMTP.git
> cd FaceSMTP
> mvn package -Dmaven.test.skip

実行

-oで指定したディレクトリに受信したメールがemlファイルとして保存されます。

> java -jar fakeSMTP-2.1-SNAPSHOT.jar -p 2525 -a 127.0.0.1 -o d:\mail\message

ファイルに書き出す必要がない場合は代わりに-mオプションを付けます。

> java -jar fakeSMTP-2.1-SNAPSHOT.jar -p 2525 -a 127.0.0.1 -m

上記のオプションで実行するとGUIが起動します。

FaceSMTPServer.png

メールをクリックするとメールクライアントが立ち上がりメール本文を確認することが出来ます。

FaceSMTPServer1.png

バックグラウンドモードで実行したい場合は-b-sオプションを付けます。

> java -jar fakeSMTP-2.1-SNAPSHOT.jar -p 2525 -a 127.0.0.1 -b -s -o d:\mail\message

smtp4dev

Windows 7/Vista/XP/2003/2010 compatible dummy SMTP server. Sits in the system tray and does not deliver the received messages. The received messages can be quickly viewed, saved and the source/structure inspected. Useful for testing/debugging software that generates email.

Windowsのネイティブアプリケーションです。smtp4dev.exeという実行ファイルのみでインストール不要です。最終リリースが2011年となっているのが気になりますが今のところ問題なく利用できました。
日本語にも対応しています。(ISO-2022-JPの場合、GUI上では件名が文字化けしましたがメールクライアントでは正常に表示されます。)

smtp4dev0.png

Viewボタンをクリックするとメールクライアントでメールを表示することができます。図はありませんがInspectボタンをクリックするとメールヘッダーやソースを確認することができます。

mailtest0.png

option画面

smtp4dev1.png

MailDev

MailDev is a simple way to test your projects' emails during development with an easy to use web interface that runs on your machine.

インストールと実行にはNodejs,npmが必要です。ISO-2022-JPの場合は文字化けを起こしますが、UTF-8は問題ありませんでした。

インストール

> npm install -g maildev

実行

> maildev -s 2525 -w 8080 --ip 127.0.0.1

ブラウザベースのGUIが付属しています。

maildev0.png

SubEtha

SubEtha SMTP is a Java library for receiving SMTP mail

上記のsmtpサーバーとは用途が違い、Unit Testで使用する組み込み型smtpサーバーです。こちらは未だ試用していませんが便利そうだったので記載だけしておきます。

メモ

テンプレートエンジン

mustache.java

pom.xml
<dependency>
  <groupId>com.github.spullara.mustache.java</groupId>
  <artifactId>compiler</artifactId>
  <version>0.9.1</version>
</dependency>

Handlebars.java

pom.xml
<dependency>
  <groupId>com.github.jknack</groupId>
  <artifactId>handlebars</artifactId>
  <version>4.0.2</version>
</dependency>

Gmail

Googleアカウントの2段階認証

smtpサーバーにsmtp.gmail.comを使用してメール送信を行う場合、指定するGoogleアカウントが2段階認証プロセスを適用していると下記のエラーメッセージを出力してメール送信に失敗します。
この場合はそのGoogleアカウントでアプリパスワードを取得し、そのパスワードを使用することでメール送信ができるようになります。

javax.mail.AuthenticationFailedException: 534-5.7.9 Application-specific password required. Learn more at
534 5.7.9  https://support.google.com/accounts/answer/185833 63sm19755563pfq.92 - gsmtp

アプリパスワードを取得する

Googleアカウント情報ページの"Googleへのログイン"メニューを選択し"アプリ パスワード"をクリックします。

g01.png

アプリパスワードの用途をメニューから選ぶか、任意の名前を付けてパスワードを作成します。

g02.png

図の通り(モザイクをかけています)パスワードが作成されるので、このパスワードをgoogleアカウントのパスワードとして使用します。

g03.png

作成したパスワードはいつでも取り消すことができます。

g04.png

メール送信に使用するポート

25

SMTP

465

SMTPS (Simple Mail Transfer Protocol Secure)

ポート465はSMTPSに割り当てられていたが、STARTTLSの制定により割り当ては無効となった。

587

MSA (Mail Submission Agent)

MUA-MSA間の投稿(Submission)ではポート587が使われることが多い。

STARTTLS

STARTTLS(スタート・ティーエルエス)は、平文の通信プロトコルを暗号化通信に拡張する方法のひとつ。
STARTTLSは、IMAPやPOP3に対してはRFC 2595、SMTPに対してはRFC 3207、FTPに対してはRFC 4217、XMPPに対してはRFC 6120の5節、LDAPに対してはRFC 4511の4.14節、NNTPに対してはRFC 4642で規定する。

STARTTLS - Wikipedia

参考になったstackoverflow

spring.mail.properties.mail.smtp.ssl.enable = true