Challenge Java EE !

Java EEを中心に趣味や仕事における開発メモを書いています。

Simple Java Mailの主な機能について

昨日書いたSimple Java Mailライブラリの続きです。

kikutaro777.hatenablog.com
f:id:kikutaro777:20170829233253p:plain

昨日のサンプルではビルダーパターンを使いました。

Email email = new EmailBuilder()
    .from("kikutaro_from", "kikutaro_from@example.com")
    .to("kikutaro_to", "kikutaro_to@example.com")
    .subject("サブジェクトだよ")
    .text("マルチパートのテキストだよ")
    .textHTML("<b>マルチパートのHTMLだよ</b>")
    .build();
new Mailer("smtp.sendgrid.net", 587, "****id****", "****pass****").sendMail(email);

もちろん普通に書くこともできます。

Email email = new Email();
email.setFromAddress("kikutaro_from", "kikutaro_from@example.com");
email.addToRecipients("kikutaro_to", "kikutaro_to@example.com");
email.setSubject("サブジェクトだよ");
email.setText("マルチパートのテキストだよ");
email.setTextHTML("<b>マルチパートのHTMLだよ</b>");
new Mailer("smtp.sendgrid.net", 587, "****id****", "****pass****").sendMail(email);

その他、色々紹介していきます。

Recipient

上記のコード例では、宛先を表示名とメールアドレスで表現していますが、これをまとめてRecipientクラスで定義することが可能です。
RecipientTypeは(当たり前ですが)TOとCCとBCCの3つです。

Recipient maiyan = new Recipient("白石麻衣", "kikutaro526@yahoo.co.jp", Message.RecipientType.TO);
Recipient nachan = new Recipient("西野七瀬", "kikutaro526@yahoo.co.jp", Message.RecipientType.CC);
Recipient waka = new Recipient("若月佑美", "kikutaro526@yahoo.co.jp", Message.RecipientType.BCC);

引数は可変長のものがあるので、Recipientを一気に渡せます。

Email email = new Email();
email.addRecipients(maiyan,nachan,waka);

宛先をまとめて指定

宛先のメールアドレスをカンマ区切り並べた文字列をそのまま渡せます。
ccやbccでも同じように指定可能です。

String recipientNogizaka = "shiraishi_mai@example.com,nishino_nanase@example.com,wakatsuki_yumi@example.com";
Email email = new EmailBuilder()
                .from("kikutaro", "kikutaro@example.com")
                .to(recipientNogizaka)
//以下略

Message-IDの指定

メールヘッダに含まれるMessage-IDを簡単に指定できます。
Message-IDの詳細(RFC 2822)はこちら→RFC 2822(対訳)インターネットメッセージの形式 - RFCの部屋
通常ユニークな値であるべきものなので、以下の例は良くないものですが、idメソッドで指定できます。

Email email = new EmailBuilder()
        .id("thisismyownmessageid")
        .from("kikutaro_from", "kikutaro_from@example.com")
        //以下略

実際に送ったメールで確認してみました。まずはMessage-IDを指定しなかった場合は次のとおり。
f:id:kikutaro777:20170829233023p:plain

そして次にMessage-IDを上記コード例のように指定した場合です。
f:id:kikutaro777:20170829232909p:plain
ちゃんと変わってます。

非同期送信

通常のメール送信は同期なのでSMTPの応答を待ちますが、非同期に送信するもできます。
送信するメールの数が多いとき、これは結構便利そうですね。エラーのハンドリングはどうやるのか、気になる所ですが。

Mailer mailer = new Mailer("smtp.sendgrid.net", 587, "xxxxidxxxx", "xxxxpassxxxx");
mailer.sendMail(email, true); //第二引数でasyncをtrueに設定

スレッドプール

スレッドプールの値はデフォルトが10とのことですが、変更できます。

Mailer mailer = new Mailer("smtp.sendgrid.net", 587, "xxxxidxxxx", "xxxxpassxxxx");
mailer.setThreadPoolSize(3);
mailer.sendMail(email, true);

ログだけ残して送信しないモード

デバッグログだけ出して実際のメール送信はしない、みたいなことができます。
誤送信しないようにしたり、テストコードとかで使えるのかな。

Mailer mailer = new Mailer("smtp.sendgrid.net", 587, "xxxxidxxxx", "xxxxpassxxxx");
mailer.setDebug(true);
mailer.setTransportModeLoggingOnly(true);

ログについては、Simple Java MailではSLF4jを利用しているのでlog4j2やlogbackなどが利用できるようです。

Spring対応

Springから簡単に利用できるようになっています。
以下はSpring Bootで書いた例ですが@Importを指定するだけです。

@Component
@Import(SimpleJavaMailSpringSupport.class)
public class MyMailService {
    @Autowired
    private Mailer mailer;

    public void sendmail() {
        Email email = new EmailBuilder()
            .from("kikutaro_from", "kikutaro_from@example.com")
            .to("kikutaro_to", "kikutaro_to@example.com")
            .subject("Spring bootから")
            .text("マルチパートのテキストだよ")
            .textHTML("<b>マルチパートのHTMLだよ</b>")
            .build();
        mailer.sendMail(email);
    }
}

application.propetiesでSMTPの設定を定義できます。

simplejavamail.smtp.host = smtp.sendgrid.net
simplejavamail.smtp.port = 587
simplejavamail.smtp.username = ********
simplejavamail.smtp.password = ********

その他

設定(Configure)はファイルでもConfigクラスでも可能です。プロキシなんかへの対応もあるようです。
カスタムヘッダ、添付ファイル、DKIM対応、Return-Receipt-To/Disposition-Notification-To、メールアドレスのバリデーション、MimeやEML,Outlook.msgなどなどあるので、別途書きたい。

Simple Java Mailの紹介

JavaでメールといえばJavaMail一択だと思っていたのですが、Simple Java Mailという中々良さげなライブラリがありました。

Simple Java Mail
f:id:kikutaro777:20170828231049p:plain

2007年ぐらいから開発されていて、2017年現在でもメンテや改造が進んでいるようです。中身が気になる方はGitHubへ。

GitHub - bbottema/simple-java-mail: Simple API, Complex Emails (JavaMail smtp wrapper)

「Simple API, Complex Emails」ってちょっとカッコイイですね。ちなみに中ではJavaMailを利用しているので、ラッパーライブラリという位置づけです。

細かい記述方法とかは別途解説していくとして(結構色んなことができそう)、シンプルなコードでJavaMailと簡単に比べてみます。

SendGridのSMTPサーバに接続して、テキストとHTML両方含めたマルチパートメールを送るというもの。JavaMailだとこんな感じですね。

JavaMailで書いた場合
package jp.co.kke.simplejavamailsample;

import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

/**
 * JavaMailを利用したメール送信
 *
 * @author kikuta
 */
public class Main {

    public static void main(String[] args) throws MessagingException {
        sendByJavaMail();
    }

    private static void sendByJavaMail() throws NoSuchProviderException, MessagingException {
        //接続先の設定
        Properties props = new Properties();
        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.host", "smtp.sendgrid.net");
        props.put("mail.smtp.port", 587);
        props.put("mail.smtp.auth", "true");
        
        //Authenticatorを継承したクラスを作って(ここではSMTPAuthenticator)
        //getPasswordAuthentication()をオーバーライドして認証情報をセット
        Authenticator auth = new SMTPAuthenticator();
        
        //セッション
        Session mailSession = Session.getDefaultInstance(props, auth);
        
        //メール送信のため
        Transport transport = mailSession.getTransport();
 
        //メールの情報を設定
        MimeMessage message = new MimeMessage(mailSession);
 
        //マルチパート・メディアタイプはalternativeを指定
        Multipart multipart = new MimeMultipart("alternative");
 
        BodyPart part1 = new MimeBodyPart();
        part1.setText("マルチパートのテキストだよ");
 
        BodyPart part2 = new MimeBodyPart();
        part2.setContent("<b>マルチパートのHTMLだよ</b>", "text/html;charset=UTF-8");
        
        multipart.addBodyPart(part1);
        multipart.addBodyPart(part2);
        message.setContent(multipart);
        
        //送信元
        message.setFrom(new InternetAddress("kikutaro_from@example.com"));
        
        //メールタイトル
        message.setSubject("サブジェクトだよ");
        
        //送信先
        message.addRecipient(Message.RecipientType.TO, new InternetAddress("kikutaro_to@example.com"));
        
        //メール送信
        transport.connect();
        transport.sendMessage(message, message.getRecipients(Message.RecipientType.TO));
        transport.close();
    }

    private static class SMTPAuthenticator extends Authenticator {
        @Override
        public PasswordAuthentication getPasswordAuthentication() {
           String username = "****id****"; //SendGridのログインID
           String password = "****pass****"; //SendGridのログインパスワード
           return new PasswordAuthentication(username, password);
        }
    }
}
Simle Java Mailで書いた場合

Simple Java Mailを利用したコードはこちらです。

package jp.co.kke.simplejavamailsample;

import org.simplejavamail.email.Email;
import org.simplejavamail.email.EmailBuilder;
import org.simplejavamail.mailer.Mailer;

/**
 * Simple Java Mailを利用したメール送信
 *
 * @author kikuta
 */
public class Main {

    public static void main(String[] args) throws MessagingException {
        sendBySimpleJavaMail();
    }

    private static void sendBySimpleJavaMail() {
        Email email = new EmailBuilder()
                .from("kikutaro_from", "kikutaro_from@example.com")
                .to("kikutaro_to", "kikutaro_to@example.com")
                .subject("サブジェクトだよ")
                .text("マルチパートのテキストだよ")
                .textHTML("<b>マルチパートのHTMLだよ</b>")
                .build();
        new Mailer("smtp.sendgrid.net", 587, "****id****", "****pass****").sendMail(email);
    }    
}

Builderでスッキリ!もちろんHeaderの設定とか色々なことができます。

Mavenのdependencyは以下です。

<dependency>
    <groupId>org.simplejavamail</groupId>
    <artifactId>simple-java-mail</artifactId>
    <version>4.4.4</version>
</dependency>

JavaMailのissueにあったUTF-7に関する質問

JavaMailのissueを眺めていたら「UTF-7ってまだ必要なの?」という質問が挙がってました。

github.com

質問内容は「数年前に作ったアプリにおいて、メールを読み込むとjava.io.UnsupportedEncodingExceptionが出たのでjutf7.jarを配置していたが、今もこの対処は必要か?」というもの。

「UTF-7ってなんだっけ?なんでそんなのが出てくるんだろう…」と、ふと気になったので調べてました。

jutf7.jarは以下sourceforgeで手に入るライブラリのようです。
Java UTF-7 Charset support download | SourceForge.net

issueに貼ってあるリンクは以下2つ。

java.io.UnsupportedEncodingException: unicode-1-1-utf-7?
Parsing UTF-7 email messages

前者はJDKではUTF-7はサポートしてないよ、という話。後者はJiraからメール送ってエラーとなった現象の話。JIRAのはこの辺でJIRA Mail Plugin関連?な気も。これは最終的にはJavaMail使ってるものなのか…?よくわからないけど、多分以下ブログにあるような話なのだろうなぁと。

www.tdtsh.com

JavaMailのPOPってほとんど触ったことないので今度ちょっと試してみたい。

なお、JavaMailのコード内には自前でUTF-7を処理してるような部分があるとのことで、それに対してSpecリードのBill Shannonさんは「IMAP uses a modified version of UTF-7.」と回答してました。JavaMailのコード調べたのですが、以下の部分と思われます。

BASE64MailboxEncoder

IMAP(Internet Message Access Protocol)のRFC 2060にある5.1.3. Mailbox International Naming Conventionの実装部分のようです。

メールで文字コードと聞くと「ASCII」「iso-2022-jp」、最近だと「UTF-8」も。というイメージですが、「UTF-7」なんていうのもあるんですね。知らなかった。

UTF-7のRFCみると「A Mail-Safe Transformation Format of Unicode」ってあるし、生まれた背景自体メール関連なのか。

そもそも文字コードのこと、あまり理解できていないなぁと思って、ネットの情報で色々調べてましたが、どうしても情報が分散してる感じです(RFCとかまとめて読めという感じなんでしょうが…)。で、体系的にまとまった知識を得たいなぁと思って探していたら以下の書籍がみつかりました。早速買って読んだのですが、とても良かったです。文字コード関連の話が丸々一冊にまとまっていて、350ページくらいあります。歴史的な背景からプログラム(JavaやRubyなど)、さらにWebやメールと文字コードの関係まで深く広く書かれているので、知りたい情報を知れた感じ。

そもそも自分はUnicodeとUTFの関係とか認識できていなかったのだなぁと。本では符号化文字集合(coded character set)、文字符号化方式(character encoding scheme)という言葉で説明されていました。Unicodeは文字にどんな番号を割り当てるか(符号位置)の話でUTFはそれをどういうバイト列で表すか、というもの。その表現の違いによってUTF-8やUTF-16、そしてUTF-7があるのですね。

メール関連で良く出てくるMIME、そしてBASE64、quoted-printableの話も本に載ってて、ちょうど知りたかったので買ってよかったなーと。

調べたときにみたサイトは以下。

equj65.net

tyru.hatenablog.com

メール一般

404 Blog Not Found:Unicodeは文字集合か符号化方式か

www.atmarkit.co.jp

エンコード・コレクション (メール、テキスト関連)

http://wa3.i-3-i.info/word15293.html

http://www.shoai.ne.jp/hirakata-s/it/mail/mail_code.html

にほんブログ村 IT技術ブログへ
にほんブログ村 にほんブログ村 IT技術ブログ Javaへ
にほんブログ村