电子邮件

本节介绍如何使用 Spring Framework 发送电子邮件。 .库依赖 为了使用 Spring Framework 的电子邮件支持,以下 JAR 需要在应用程序的类路径中:

该库可在网上免费获取——例如,在 Maven Central 中以 com.sun.mail:jakarta.mail 的形式。请确保使用最新的 2.x 版本(它使用 jakarta.mail 包命名空间),而不是 Jakarta Mail 1.6.x(它使用 javax.mail 包命名空间)。 Spring Framework 提供了一个有用的实用程序库来发送电子邮件,它使您免受底层邮件系统的具体细节的影响,并负责代表客户端处理低级资源。 org.springframework.mail 包是 Spring Framework 电子邮件支持的根级别包。发送电子邮件的核心接口是 MailSender 接口。一个简单的值对象,封装了简单邮件的属性,如 fromto(以及许多其他属性),是 SimpleMailMessage 类。此包还包含一个受检异常层次结构,它提供了比低级邮件系统异常更高一级的抽象,根异常是 MailException。有关丰富的邮件异常层次结构的更多信息,请参阅 javadocorg.springframework.mail.javamail.JavaMailSender 接口向 MailSender 接口(它继承自该接口)添加了专门的 JavaMail 功能,例如 MIME 消息支持。JavaMailSender 还提供了一个名为 org.springframework.mail.javamail.MimeMessagePreparator 的回调接口,用于准备 MimeMessage

用法

假设我们有一个名为 OrderManager 的业务接口,如以下示例所示:

进一步假设我们有一个要求,即需要生成并发送一封包含订单号的电子邮件消息给下达相关订单的客户。

MailSenderSimpleMailMessage 的基本用法

以下示例展示了如何在有人下订单时使用 MailSenderSimpleMailMessage 发送电子邮件:

以下示例显示了前面代码的 bean 定义:

使用 JavaMailSenderMimeMessagePreparator

本节描述 OrderManager 的另一个实现,它使用 MimeMessagePreparator 回调接口。在以下示例中,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("mail@mycompany.example"));
				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("test@host.com");
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("test@host.com");

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("test@host.com");

// 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 的支持类,这变得相当容易实现。