概要

通知メール、パスワードリセット、帳票の送付――業務システムでメール送信が必要になる場面は今でも多く残っています。Java 標準 API にはメール送信機能が含まれていませんが、Jakarta Mail(旧 JavaMail)を使えば、SMTP の接続設定からテキスト・HTML メールの組み立てまでを比較的少ないコードで実装できます。ただし、SMTP 認証の設定、STARTTLS と SSL/TLS の違い、日本語件名の文字コード指定、HTML メールでの MimeBodyPart の組み立てなど、初見で引っかかるポイントは少なくありません。この記事では、SMTP 設定の構造化から、テキストメール・HTML メールの送信、Java バージョンごとの書き方の違いまでを一通り整理します。開発環境では Mailtrap や MailHog を使うことで、実際のメールボックスに影響を与えずにテストできます。

使いどころ

ユーザー登録完了時に確認メールを自動送信し、認証リンクを本文に含める

月次バッチ処理の結果サマリーを管理者宛にテキストメールで送信する

請求書 PDF を HTML メールに添付して取引先へ送付する

コード例

MailSender.java
import java.util.Properties;

/**
 * Jakarta Mail によるメール送信のサンプル。
 * 実行には pom.xml に jakarta.mail 依存の追加が必要です。
 *
 * <dependency>
 *   <groupId>com.sun.mail</groupId>
 *   <artifactId>jakarta.mail</artifactId>
 *   <version>2.0.1</version>
 * </dependency>
 */
public class MailSender {

    // SMTP 設定を record で構造化(Java 16+)
    record SmtpConfig(String host, int port,
                      String username, String password,
                      boolean useTls) {}

    /** SMTP 接続用の Properties を生成する */
    static Properties buildSmtpProperties(SmtpConfig config) {
        var props = new Properties();
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable",
                  String.valueOf(config.useTls()));
        props.put("mail.smtp.host", config.host());
        props.put("mail.smtp.port",
                  String.valueOf(config.port()));
        return props;
    }

    /*
     * テキストメール送信(Jakarta Mail 使用時のコード構成)
     *
     * var session = Session.getInstance(props, authenticator);
     * var message = new MimeMessage(session);
     * message.setFrom(new InternetAddress(from));
     * message.setRecipients(
     *     Message.RecipientType.TO, InternetAddress.parse(to));
     * message.setSubject(subject, "UTF-8");
     * message.setText(body, "UTF-8");
     * Transport.send(message);
     */
    static void sendTextMail(SmtpConfig config,
            String from, String to,
            String subject, String body) {
        System.out.println("=== テキストメール送信 ===");
        System.out.println("SMTP: " + config.host()
                + ":" + config.port());
        System.out.println("From: " + from);
        System.out.println("To:   " + to);
        System.out.println("件名: " + subject);
        System.out.println("本文: " + body);
    }

    /*
     * HTML メール送信(テキストブロックで HTML を記述)
     */
    static void sendHtmlMail(SmtpConfig config,
            String from, String to, String subject) {
        var htmlBody = """
                <!DOCTYPE html>
                <html>
                <body>
                  <h1 style="color: #2563eb;">お知らせ</h1>
                  <p>Jakarta Mail を使った
                     <strong>HTML メール</strong>のサンプルです。</p>
                </body>
                </html>
                """;
        System.out.println("=== HTML メール送信 ===");
        System.out.println("SMTP: " + config.host()
                + ":" + config.port());
        System.out.println("To:   " + to);
        System.out.println("件名: " + subject);
    }

    public static void main(String[] args) {
        var config = new SmtpConfig(
            "smtp.gmail.com", 587,
            "[email protected]", "your-app-password",
            true
        );

        sendTextMail(config,
            "[email protected]", "[email protected]",
            "テスト件名", "テスト本文です。");

        System.out.println();

        sendHtmlMail(config,
            "[email protected]", "[email protected]",
            "HTML メールテスト");
    }
}

Java 8 / 17 / 21 の完全なサンプルコードは GitHub リポジトリ で確認できます。

Version Coverage

jakarta.mail パッケージに移行。var による型推論で記述量が減る。テキストブロックで HTML メール本文を読みやすく記述できる。SMTP 設定を record で構造化するのも効果的。

Java 17
// Java 17: record で SMTP 設定を構造化
record SmtpConfig(String host, int port,
                  String username, String password,
                  boolean useTls) {}
var config = new SmtpConfig(
    "smtp.gmail.com", 587, user, pass, true);
// テキストブロックで HTML 本文を記述
var html = """
    <h1>お知らせ</h1>
    <p>HTML メールのサンプルです。</p>
    """;

Library Comparison

Jakarta Mail(旧 JavaMail)SMTP 接続の細かい制御が必要な場合。テキスト・HTML・添付ファイルなど多様なメール形式を扱うとき。依存追加が必要(jakarta.mail)。低レベル API のため、Session・MimeMessage の組み立てがやや冗長。
Spring Mail(JavaMailSender)Spring Boot プロジェクトで、DI と application.yml による設定管理を活用したいとき。Spring 依存が前提。非 Spring プロジェクトへの適用は過剰になる。
Apache Commons EmailJakarta Mail のラッパーとして、簡潔な API でメール送信を済ませたいとき。依存が増える割に、Jakarta Mail を直接使う場合との差分は限定的。保守状況の確認が必要。

注意点

Gmail の SMTP を使う場合、2022年以降はアプリパスワードの生成が必要(通常のパスワードでは認証できない)。二段階認証を有効にしたうえで Google アカウント設定からアプリパスワードを発行する

日本語の件名には message.setSubject(subject, "UTF-8") で文字コードを明示する必要がある。省略すると文字化けの原因になる

STARTTLS(ポート587)と SSL/TLS(ポート465)は設定が異なる。mail.smtp.starttls.enable と mail.smtp.ssl.enable を混同しないこと

開発・テスト環境では Mailtrap や MailHog などのダミー SMTP サーバーを使い、本番メールサーバーへの誤送信を防ぐこと

Jakarta Mail と旧 JavaMail(javax.mail)はパッケージ名が異なる。Jakarta EE 9 以降は jakarta.mail に移行している。依存のバージョンを確認すること

FAQ

開発環境でメール送信をテストするにはどうすればよいですか。

Mailtrap や MailHog などのダミー SMTP サーバーを使うのが一般的です。実際のメールボックスに影響を与えず、送信内容をブラウザで確認できます。

javax.mail と jakarta.mail の違いは何ですか。

Jakarta EE 9 以降でパッケージ名が javax.mail から jakarta.mail に変更されました。API の構造は同じですが、import 文とライブラリ依存の groupId/artifactId が異なります。新規プロジェクトでは jakarta.mail を選んでください。

添付ファイル付きメールを送るにはどうすればよいですか。

MimeMultipart に MimeBodyPart を複数追加し、テキスト/HTML パートと添付ファイルパートを組み合わせます。添付パートには DataHandler と FileDataSource を使ってファイルを設定します。

関連書籍

この記事のテーマをさらに深く学びたい方へ。

※ Amazon アソシエイトリンクを含みます