20220507 6. Integration - Email
前言
相关依赖:
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mail</artifactId>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-bom</artifactId>
<version>${spring-integration.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
本节介绍如何使用 Spring 框架发送电子邮件。
Spring Framework 为发送电子邮件提供了一个有用的实用程序库,使您无需了解基础邮件系统的细节,并代表客户负责低级别的资源处理。
org.springframework.mail
包是 Spring 框架电子邮件支持的根级别包。发送电子邮件的核心接口是 MailSender
接口。SimpleMailMessage
类是一个简单的值对象,它封装了简单邮件的属性,例如 from
和 to
。这个包还包含一个检查异常的层次结构,它提供了比低级别邮件系统异常更高层次的抽象,根异常是 MailException
。有关富邮件异常层次结构的更多信息,请参见 javadoc 。
org.springframework.mail.javamail.JavaMailSender
接口添加了专门的 JavaMail 特性,例如对 MailSender 接口的 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="customerservice@mycompany.example"/>
<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>
参考
使用 QQ 邮箱的配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.qq.com"/>
<property name="username" value="qq账号@qq.com"/>
<property name="password" value="邮箱的授权码"/>
</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="qq账号@qq.com"/>
<property name="subject" value="邮件主题"/>
</bean>
<bean id="orderManager" class="study.hwj.spring.mail.SimpleOrderManager">
<property name="mailSender" ref="mailSender"/>
<property name="templateMessage" ref="templateMessage"/>
</bean>
</beans>
使用 JavaMailSender
和 MimeMessagePreparator
本节描述了 OrderManager
的另一个实现,该实现使用 MimeMessagePreparator
回调接口。
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.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 框架的邮件支持标准 JavaMail 实现。
使用 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 框架对 FreeMarker 的支持类,这将变得非常容易。