メール

このセクションでは、Spring Framework を使用してメールを送信する方法について説明します。

ライブラリの依存関係

Spring Framework のメールサポートを使用するには、次の JAR をアプリケーションのクラスパスに配置する必要があります。

このライブラリは、Web 上でフリーで入手できます。たとえば、Maven Central では com.sun.mail:jakarta.mail として利用できます。Jakarta Mail 1.6.x (javax.mail パッケージ名前空間を使用) ではなく、最新の 2.x バージョン (jakarta.mail パッケージ名前空間を使用) を使用してください。

Spring Framework は、メールを送信するための有用なユーティリティライブラリを提供します。このライブラリは、基礎となるメールシステムの詳細からユーザーを保護し、クライアントに代わって低レベルのリソース処理を行います。

org.springframework.mail パッケージは、Spring Framework のメールサポートのルートレベルパッケージです。メールを送信するための中心的なインターフェースは、MailSender インターフェースです。from や to (その他多数)などの単純なメールのプロパティをカプセル化する単純な値オブジェクトは、SimpleMailMessage クラスです。このパッケージには、チェック例外の階層も含まれており、下位レベルのメールシステム例外よりも高いレベルの抽象化を提供します。ルート例外は MailException です。リッチメールの例外階層の詳細については、javadoc を参照してください。

org.springframework.mail.javamail.JavaMailSender インターフェースは、MIME メッセージのサポートなどの特殊な JavaMail 機能を(継承元の) MailSender インターフェースに追加します。JavaMailSender は、MimeMessage を準備するための org.springframework.mail.javamail.MimeMessagePreparator と呼ばれるコールバックインターフェースも提供します。

使用方法

次の例に示すように、OrderManager というビジネスインターフェースがあると仮定します。

  • Java

  • Kotlin

public interface OrderManager {

	void placeOrder(Order order);
}
interface OrderManager {

	fun placeOrder(order: Order)
}

さらに、オーダー番号付きのメールメッセージを生成し、関連するオーダーを行った顧客に送信する必要があるという要件があると仮定します。

MailSender および SimpleMailMessage の基本的な使用箇所

次の例は、MailSender および SimpleMailMessage を使用して、誰かがオーダーしたときにメールを送信する方法を示しています。

  • Java

  • Kotlin

public class SimpleOrderManager implements OrderManager {

	private MailSender mailSender;
	private SimpleMailMessage templateMessage;

	public void setMailSender(MailSender mailSender) {
		this.mailSender = mailSender;
	}

	public void setTemplateMessage(SimpleMailMessage templateMessage) {
		this.templateMessage = templateMessage;
	}

	@Override
	public void placeOrder(Order order) {

		// Do the business calculations...

		// Call the collaborators to persist the order...

		// Create a thread-safe "copy" of the template message and customize it
		SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
		msg.setTo(order.getCustomer().getEmailAddress());
		msg.setText(
				"Dear " + order.getCustomer().getFirstName()
						+ order.getCustomer().getLastName()
						+ ", thank you for placing order. Your order number is "
						+ order.getOrderNumber());
		try {
			this.mailSender.send(msg);
		}
		catch (MailException ex) {
			// simply log it and go on...
			System.err.println(ex.getMessage());
		}
	}

}
class SimpleOrderManager : OrderManager {

	lateinit var mailSender: MailSender
	lateinit var templateMessage: SimpleMailMessage

	override fun placeOrder(order: Order) {
		// Do the business calculations...

		// Call the collaborators to persist the order...

		// Create a thread-safe "copy" of the template message and customize it

		val msg = SimpleMailMessage(this.templateMessage)
		msg.setTo(order.customer.emailAddress)
		msg.text = ("Dear " + order.customer.firstName
				+ order.customer.lastName
				+ ", thank you for placing order. Your order number is "
				+ order.orderNumber)
		try {
			mailSender.send(msg)
		} catch (ex: MailException) {
			// simply log it and go on...
			System.err.println(ex.message)
		}
	}
}

次の例は、前述のコードの Bean 定義を示しています。

  • Java

  • Kotlin

  • XML

@Bean
JavaMailSender mailSender() {
	JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
	mailSender.setHost("mail.mycompany.example");
	return mailSender;
}

@Bean // this is a template message that we can pre-load with default state
SimpleMailMessage templateMessage() {
	SimpleMailMessage message = new SimpleMailMessage();
	message.setFrom("[email protected] (英語)  ");
	message.setSubject("Your order");
	return message;
}

@Bean
SimpleOrderManager orderManager(JavaMailSender mailSender, SimpleMailMessage templateMessage) {
	SimpleOrderManager orderManager = new SimpleOrderManager();
	orderManager.setMailSender(mailSender);
	orderManager.setTemplateMessage(templateMessage);
	return orderManager;
}
@Bean
fun mailSender(): JavaMailSender {
	return JavaMailSenderImpl().apply {
		host = "mail.mycompany.example"
	}
}

@Bean // this is a template message that we can pre-load with default state
fun templateMessage() = SimpleMailMessage().apply {
	from = "[email protected] (英語)  "
	subject = "Your order"
}


@Bean
fun orderManager(javaMailSender: JavaMailSender, simpleTemplateMessage: SimpleMailMessage) = SimpleOrderManager().apply {
	mailSender = javaMailSender
	templateMessage = simpleTemplateMessage
}
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
	<property name="host" value="mail.mycompany.example"/>
</bean>

<!-- this is a template message that we can pre-load with default state -->
<bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage">
	<property name="from" value="[email protected] (英語)  "/>
	<property name="subject" value="Your order"/>
</bean>

<bean id="orderManager" class="com.mycompany.businessapp.support.SimpleOrderManager">
	<property name="mailSender" ref="mailSender"/>
	<property name="templateMessage" ref="templateMessage"/>
</bean>

JavaMailSender および MimeMessagePreparator の使用

このセクションでは、MimeMessagePreparator コールバックインターフェースを使用する OrderManager の別の実装について説明します。次の例では、mailSender プロパティの型は JavaMailSender であるため、JavaMail MimeMessage クラスを使用できます。

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

import jakarta.mail.internet.MimeMessage;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessagePreparator;

public class SimpleOrderManager implements OrderManager {

	private JavaMailSender mailSender;

	public void setMailSender(JavaMailSender mailSender) {
		this.mailSender = mailSender;
	}

	public void placeOrder(final Order order) {
		// Do the business calculations...
		// Call the collaborators to persist the order...

		MimeMessagePreparator preparator = new MimeMessagePreparator() {
			public void prepare(MimeMessage mimeMessage) throws Exception {
				mimeMessage.setRecipient(Message.RecipientType.TO,
						new InternetAddress(order.getCustomer().getEmailAddress()));
				mimeMessage.setFrom(new InternetAddress("[email protected] (英語)  "));
				mimeMessage.setText("Dear " + order.getCustomer().getFirstName() + " " +
						order.getCustomer().getLastName() + ", thanks for your order. " +
						"Your order number is " + order.getOrderNumber() + ".");
			}
		};

		try {
			this.mailSender.send(preparator);
		}
		catch (MailException ex) {
			// simply log it and go on...
			System.err.println(ex.getMessage());
		}
	}

}
メールコードは横断的な問題であり、カスタム Spring AOP アスペクトへのリファクタリングの候補となる可能性があり、その後、OrderManager ターゲット上の適切なジョインポイントで実行できます。

Spring Framework のメールサポートは、標準の JavaMail 実装に付属しています。詳細については、関連する javadoc を参照してください。

JavaMail MimeMessageHelper の使用

JavaMail メッセージを処理するときに非常に便利なクラスは org.springframework.mail.javamail.MimeMessageHelper です。これにより、冗長な JavaMail API を使用する必要がなくなります。MimeMessageHelper を使用すると、次の例に示すように、MimeMessage を簡単に作成できます。

// of course you would use DI in any real-world cases
JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");

MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
helper.setTo("[email protected] (英語)  ");
helper.setText("Thank you for ordering!");

sender.send(message);

添付ファイルとインラインリソースの送信

マルチパートメールメッセージでは、添付ファイルとインラインリソースの両方を使用できます。インラインリソースの例には、メッセージで使用したいが添付ファイルとして表示したくないイメージまたはスタイルシートが含まれます。

添付

次の例は、MimeMessageHelper を使用して、単一の JPEG イメージが添付されたメールを送信する方法を示しています。

JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");

MimeMessage message = sender.createMimeMessage();

// use the true flag to indicate you need a multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("[email protected] (英語)  ");

helper.setText("Check out this image!");

// let's attach the infamous windows Sample file (this time copied to c:/)
FileSystemResource file = new FileSystemResource(new File("c:/Sample.jpg"));
helper.addAttachment("CoolImage.jpg", file);

sender.send(message);

インラインリソース

次の例は、MimeMessageHelper を使用して、インラインイメージを含むメールを送信する方法を示しています。

JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");

MimeMessage message = sender.createMimeMessage();

// use the true flag to indicate you need a multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("[email protected] (英語)  ");

// use the true flag to indicate the text included is HTML
helper.setText("<html><body><img src='cid:identifier1234'></body></html>", true);

// let's include the infamous windows Sample file (this time copied to c:/)
FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg"));
helper.addInline("identifier1234", res);

sender.send(message);
インラインリソースは、指定された Content-ID (上記の例では identifier1234)を使用して MimeMessage に追加されます。テキストとリソースを追加する順序は非常に重要です。最初にテキストを追加してから、リソースを追加してください。逆にそれをやっていると、うまくいきません。

テンプレートライブラリを使用してメールコンテンツを作成する

前のセクションで示した例のコードは、message.setText(..) などのメソッド呼び出しを使用して、メールメッセージのコンテンツを明示的に作成しました。これは単純なケースでは問題ありませんが、前述の例のコンテキストでは問題ありません。この例では、API の基本を説明することを目的としています。

ただし、一般的なエンタープライズアプリケーションでは、多くの場合、開発者は前述のアプローチを使用してメールメッセージのコンテンツを作成しません。

  • Java コードで HTML ベースのメールコンテンツを作成するのは面倒でエラーが発生しやすくなります。

  • 表示ロジックとビジネスロジックの間には明確な分離はありません。

  • メールコンテンツの表示構造を変更するには、Java コードの記述、再コンパイル、再デプロイなどが必要です。

通常、これらの課題に対処するために取られるアプローチは、テンプレートライブラリ(FreeMarker など)を使用してメールコンテンツの表示構造を定義することです。これにより、コードは、メールテンプレートでレンダリングされるデータの作成とメールの送信のみに任されます。メールメッセージの内容がやや複雑になる場合は間違いなくベストプラクティスであり、Spring Framework の FreeMarker のサポートクラスを使用すると、非常に簡単になります。