|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
电子邮件
本节介绍如何使用 Spring Framework 发送电子邮件。
Spring 框架提供了一个用于发送电子邮件的实用工具库,该库屏蔽了底层邮件系统的具体细节,并代表客户端负责底层资源的处理。
org.springframework.mail 包是 Spring 框架电子邮件支持的根级包。发送电子邮件的核心接口是 MailSender 接口。from 类是一个简单的值对象,用于封装简单邮件的属性,例如 to 和 SimpleMailMessage(以及其他许多属性)。该包还包含一个受检异常的层次结构,对底层邮件系统异常提供了更高层次的抽象,其根异常为 MailException。有关丰富的邮件异常层次结构的更多信息,请参阅 javadoc。
org.springframework.mail.javamail.JavaMailSender 接口在 MailSender 接口(它继承自该接口)的基础上增加了专门的 JavaMail 功能,例如对 MIME 消息的支持。JavaMailSender 还提供了一个名为 org.springframework.mail.javamail.MimeMessagePreparator 的回调接口,用于准备 MimeMessage。
用法
假设我们有一个名为 OrderManager 的业务接口,如下例所示:
public interface OrderManager {
void placeOrder(Order order);
}
进一步假设我们有一个需求,即需要生成一封包含订单号的电子邮件,并将其发送给下相关订单的客户。
基本MailSender和SimpleMailMessage用法
以下示例展示了如何在用户下单时使用 MailSender 和 SimpleMailMessage 发送电子邮件:
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
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;
}
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());
}
}
}
以下示例展示了上述代码的 bean 定义:
<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
本节描述了另一个使用 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("[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 框架的邮件支持附带了标准的 JavaMail 实现。 有关更多信息,请参阅相关的 Javadoc。
使用 JavaMailMimeMessageHelper
在处理 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);
内联资源通过指定的 MimeMessage(如上例中的 Content-ID)添加到 identifier1234 中。添加文本和资源的顺序非常重要。请务必先添加文本,然后再添加资源。如果顺序颠倒,则无法正常工作。 |
使用模板库创建电子邮件内容
前面几节示例中所示的代码通过调用诸如 message.setText(..) 等方法显式地创建了电子邮件消息的内容。
对于简单场景而言,这种方式是合适的;在前述示例的上下文中也是可以接受的,因为这些示例的目的是向您展示该 API 最基本的用法。
然而,在典型的企业应用程序中,开发人员通常不会使用前面所示的方法来创建电子邮件内容,原因有很多:
-
在 Java 代码中创建基于 HTML 的电子邮件内容既繁琐又容易出错。
-
显示逻辑与业务逻辑之间没有清晰的分离。
-
更改电子邮件内容的显示结构需要编写 Java 代码、重新编译、重新部署等操作。
通常,解决这些问题的方法是使用模板库(例如 FreeMarker)来定义邮件内容的显示结构。这样,您的代码只需负责创建要在邮件模板中渲染的数据并发送邮件即可。当您的邮件内容变得哪怕只是稍微复杂一些时,这种做法无疑是一种最佳实践;而借助 Spring 框架对 FreeMarker 提供的支持类,实现起来也变得非常简单。