SpringでのMIMEのサポート(Spring1.2.1)

SpringはMIMEもサポートしているらしいので,試してみた.
SpringでのMIMEサポート
メール送信処理の記述
setText
サンプル実行

SpringでのMIMEサポート

Springでの,MIMEサポートは以下のような状況である.
MailSenderの実装クラスはJavaMailSender.
MIME形式のメールを構築するためのヘルパークラスがある.
このように,さほど大がかりなものではないが,文字コードの扱いに関して,APIとしてややこしい部分があるので,その点に注意. 本頁のサンプルでは,MIMEで非マルチパートメールとマルチパートメールを送信するものを作成した.

メール送信処理の記述

メール送信処理を記述する,MimeMailBLImplを以下に示す.

package org.fireproject.springsample;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMailMessage;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;

import org.apache.log4j.Logger;

public class MimeMailBLImpl implements MailBL {
    /** ログ出力用. */
    private static Logger logger = Logger.getRootLogger();

    /** メール送信処理クラス. */
    private JavaMailSender mailSender;

    /** メールメッセージプロトタイプ. */
    private SimpleMailMessage origMessage;

    /** メール出力文字コード. */
    private static String MAIL_CHAR_SET = "ISO-2022-JP";

    public void setMailSender(JavaMailSender param) {
	mailSender = param;
    }

    public JavaMailSender getMailSender() {
	return mailSender;
    }

    public void setMessage(SimpleMailMessage param) {
	origMessage = param;
    }

    public SimpleMailMessage getMessage() {
	return origMessage;
    }

    public void process() {
	process(false);
    }

    /**
     * ビジネスロジックを実行する.
     */
    public void process(boolean multiPartFlag) {
	if (multiPartFlag) {
	    processMultiPart();
	} else {
	    processUniPart();
	}
    }

    /**
     * UniPart版.
     */
    public void processUniPart() {
	MimeMessagePreparator preparator = new MimeMessagePreparator() {
            public void prepare(MimeMessage mimeMessage) throws MessagingException {
// 		mimeMessage.setSubject(origMessage.getSubject() + " UniPart版サブジェクト", MAIL_CHAR_SET);
// 		mimeMessage.setText("UniPart版メール本文.", MAIL_CHAR_SET);
		MimeMessageHelper message = new MimeMessageHelper(mimeMessage, false, MAIL_CHAR_SET);
		message.setFrom(origMessage.getFrom());
		message.setTo(origMessage.getTo());
		message.setSubject(origMessage.getSubject() + " / UniPart版サブジェクト");
	       	message.setText("UniPart版メール本文.");
            }
        };
        try{
            mailSender.send(preparator);
        } catch(MailException me) {
	    logger.error("failed to send mail", me);
        }
    }

    /**
     * MultiPart版.
     */
    private void processMultiPart() {
	MimeMessagePreparator preparator = new MimeMessagePreparator() {
            public void prepare(MimeMessage mimeMessage) throws MessagingException {
		MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, MAIL_CHAR_SET);
		message.setFrom(origMessage.getFrom());
		message.setTo(origMessage.getTo());
		message.setSubject(origMessage.getSubject() + " / MultiPart版サブジェクト");
		message.setText("MultiPart版メール本文");
		message.addInline("log4j.xml", new FileSystemResource("conf/log4j.xml.eucjp"));
		message.addAttachment("build.xml", new FileSystemResource("conf/build.xml.eucjp"));
            }
        };
        try{
            mailSender.send(preparator);
        } catch(MailException me) {
	    logger.error("failed to send mail", me);
        }
    }

}
BeanFactoryにより,mailSenderにはJavaMailSenderImplが設定されている. 二つのメソッドprocessUniPart,processMultiPartが本頁の本題である. 前者が非マルチパートメール,後者がマルチパートメールを送信する. Springでは,MIMEメッセージを作成するには,MimeMessagePreparatorを使用してJavaMailSenderImpl#send(MimeMessagePreparator)から呼び出すコールバックメソッドを実装する.
MimeMessagePreparator preparator = new MimeMessagePreparator() {
MimeMessagePreparatorはインタフェースで,サンプルのようにコールバックprepare(MimeMessage)メソッドを実装する. このメソッド内で,具体的にどういったメールを生成するかといった処理を記述する. SpringではMIMEメール生成のためのヘルパークラスとして,MimeMessageHelperがある. いくつかのコンストラクタがあり,以下がもっとも設定の多いものである.
MimeMessageHelper(MimeMessage mimeMessage, boolean multipart, String encoding)
引数について以下に記述する.
mimeMessage.
MimeMessageHeloperは内部でこれを編集するのだが,prepareメソッドの引数を渡すことで,JavaMailSenderImplに編集結果を渡す. したがって,決めでprepareメソッドの引数を渡す.
multipart
作成するメールがマルチパートか否かのフラグを設定する. したがってサンプルでは,メソッドprocessUniPartではfalse,processMultiPartではtrueを設定している.
encoding
文字コードを記述する. サンプルでは日本語を記述するので,ISO-2022-JP(定数MAIL_CHAR_SET)を設定している.
あとは,いつものようにsetToやらsetSubjectやらすればよい. MimeMessageHelperはコンストラクタでencodeが指定されていると,setSubjectやsetTextの際にそのエンコードを適用するので,毎回文字コードを指定する必要がない点に注意. したがって,
message.setSubject(origMessage.getSubject() + " / UniPart版サブジェクト");
message.setText("UniPart版メール本文.");
は,サンプルでコメントアウトされている
mimeMessage.setSubject(origMessage.getSubject() + " UniPart版サブジェクト", MAIL_CHAR_SET);
mimeMessage.setText("UniPart版メール本文.", MAIL_CHAR_SET);
と等価となる. processMultiPartにあるように,MimeMessageHelperでは,
addInline
addAttachment
などが提供されており,マルチパートメールの作成を補助してくれる. なお,setTextは,addInlineやaddAttachmentより先に呼び出さなければならない.

setText

MimeMessageHelperを使用すると,いちいちsetTextなどをする際に文字コードを指定する必要がない. コンストラクタのものが設定される. MimeMessageHelper#setTextには,その設定が楽になった分,HTMLメールか否かの引数がある.
setText(String text)
通常のテキストを設定する.
setText(String text, boolean html)
第二引数で,HTMLメールか否かを指定する. 第二引数に応じて,Content-Typeがtext/htmlに変化する.
setText(String plainText, String htmlText)
プレーンテキストと,HTMLテキストの両方を設定する. これは両方メールに記述し,メールクライアントにて表示を選択するようなメールである.

サンプル実行

本頁のサンプルドライバを以下に示す.

package org.fireproject.springsample;

import java.net.URL;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.util.Locale;

import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import org.apache.log4j.Logger;

public class HelloSpringMailSender {
    /** ログ出力用. */
    private static Logger logger = Logger.getRootLogger();

    public static void main (String args[]) throws IOException {
	boolean multiPartFlag = false;
	if (args.length == 1) {
	    multiPartFlag = "true".equals(args[0]);
	}

	ApplicationContext context = null;

	context = getApplicationContext();

	// メール送信ビジネスロジックの取得.
	MailBL mailBL = (MailBL)context.getBean("mailBL");
	mailBL.process(multiPartFlag);
    }

    /**
     * ApplicationContextを生成して返す.
     * 要素importによるbeans.xmlの分割.
     *
     * @return ApplicationContextオブジェクト
     */
    private static ApplicationContext getApplicationContext() {
	logger.info("getApplicationContext start");
        // ClassLoaderがうまくbeans.xmlを見付けられない場合や,
        // jarファイル内にbeans.xmlがある場合は,以下のようにする.
 	URL url = HelloSpringMailSender.class.getResource("beans.xml");
 	Resource res = new UrlResource(url);
  	XmlBeanFactory factory = new XmlBeanFactory(res);

	GenericApplicationContext ctx = new GenericApplicationContext(factory);
	ctx.refresh();
	return ctx;
    }

}

サンプルを実行する前に,
conf/mail.conf
に,メールの設定を記述する. サンプルを実行すると実際にメールを送信するので,送信先などに注意する. 実行には,引数でマルチパートメールか否かを指定する.
$> java -jar springsample.jar false
あとは,宛先でメールを受信して内容を確認する.

This article was written by Fujiko