1. 概述
在本教程中,我们介绍从普通Spring应用程序和Spring Boot应用程序发送电子邮件所需的步骤。 对于前者,我们使用JavaMail库,后者将使用spring-boot-starter-mail依赖项。
2. Maven依赖
首先,我们需要将依赖项添加到pom.xml中。
2.1 Spring
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.3.13</version>
</dependency>
2.2 Spring Boot
对于Spring Boot:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.6.1</version>
</dependency>
3. 邮件服务器属性
Spring框架中Java mail支持的接口和类组织如下:
- MailSender接口:提供发送简单电子邮件的基本功能的顶层接口。
- JavaMailSender接口:上述MailSender的子接口,它支持MIME消息,并且主要与MimeMessageHelper类一起用于创建MimeMessage。 建议将MimeMessagePreparator机制用于此接口。
- JavaMailSenderImpl类:提供JavaMailSender接口的实现,它支持MimeMessage和SimpleEmailMessage。
- SimpleMailMessage类:用于创建包含发件人、收件人、抄送、主题和文本字段的简单邮件。
- MimeMessagePreparator接口:提供用于准备MIME消息的回调接口。
- MimeMessageHelper类:用于创建MIME消息的工具类,它支持HTML布局中的图像、经典邮件附件和文本内容。
在下面的部分中,我们演示如何使用这些接口和类。
3.1 Spring邮件服务器属性
指定SMTP服务器所需的邮件属性可以使用JavaMailSenderImpl定义。
对于Gmail,可以如下配置:
/*@formatter:off*/
@Bean
public JavaMailSender getJavaMailSender() {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost("smtp.gmail.com");
mailSender.setPort(587);
mailSender.setUsername("my.gmail@gmail.com");
mailSender.setPassword("password");
Properties props = mailSender.getJavaMailProperties();
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.debug", "true");
return mailSender;
}
/*@formatter:on*/
3.2 Spring Boot邮件服务器属性
如果我们添加了依赖,下一步就是在application.properties中通过spring.mail.*指定邮件服务器属性。
我们可以通过以下方式指定Gmail SMTP服务器的属性:
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=<login user to smtp server>
spring.mail.password=<login password to smtp server>
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
有些SMTP服务器需要TLS连接,所以我们使用spring.mail.properties.mail.smtp.starttls.enable属性以启用受TLS保护的连接。
3.2.1 Gmail SMTP属性
我们可以通过Gmail SMTP服务器发送电子邮件。
我们的application.properties文件已经定义了使用Gmail SMTP的相关属性.(如上节所述).
请注意,我们帐户密码不应该是普通密码,而是为我们的谷歌帐户生成的应用程序密码。
3.2.2 SES SMTP属性
为了使用亚马逊SES发送电子邮件,我们配置application.properties:
spring.mail.host=email-smtp.us-west-2.amazonaws.com
spring.mail.username=username
spring.mail.password=password
spring.mail.properties.mail.transport.protocol=smtp
spring.mail.properties.mail.smtp.port=25
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
3.2.3 163 SMTP属性
要使用网易邮箱发送电子邮件,我们配置application.properties:
spring.mail.host=smtp.163.com
spring.mail.username=username
spring.mail.password=password
spring.mail.default-encoding=UTF-8
4. 发送电子邮件
一旦依赖和配置到位,我们就可以使用前面提到的JavaMailSender发送电子邮件。
由于普通的Spring框架和它的Spring Boot版本都以类似的方式处理电子邮件的编写和发送,因此我们不必在下面的小节中区分这两者。
4.1 发送简单的电子邮件
让我们首先撰写并发送一封没有任何附件的简单电子邮件:
@Service("EmailService")
public class EmailServiceImpl implements EmailService {
private static final String NOREPLY_ADDRESS = "tuyucheng2000@gmail.com";
@Autowired
private JavaMailSender emailSender;
public void sendSimpleMessage(String to, String subject, String text) {
try {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(NOREPLY_ADDRESS);
message.setTo(to);
message.setSubject(subject);
message.setText(text);
emailSender.send(message);
} catch (MailException exception) {
exception.printStackTrace();
}
}
}
请注意,尽管不强制提供发件人地址,但许多SMTP服务器会拒绝此类邮件。 这就是为什么我们在EmailServiceImpl中使用tuyucheng2000@gmail.com电子邮件地址。
4.2 发送带有附件的电子邮件
有时,Spring的简单消息传递对于我们的用例来说是不够的。
例如,我们希望发送一封附有发票的订单确认电子邮件。 在这种情况下,我们应该使用来自JavaMail库的MIME Multipart Message,而不是SimpleEmailMessage。 Spring通过org.springframework.mail.javamail.MimeMessageHelper类支持JavaMail消息。
首先,我们向EmailServiceImpl添加一个方法来发送带有附件的电子邮件:
@Service("EmailService")
public class EmailServiceImpl implements EmailService {
@Override
public void sendMessageWithAttachment(String to, String subject, String text, String pathToAttachment) {
try {
MimeMessage message = emailSender.createMimeMessage();
// pass 'true' to the constructor to create a multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(NOREPLY_ADDRESS);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(text);
FileSystemResource file = new FileSystemResource(new File(pathToAttachment));
helper.addAttachment("Invoice", file);
emailSender.send(message);
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
4.3 简单电子邮件模板
SimpleEmailMessage类支持文本格式,我们可以通过在配置中定义模板bean来创建电子邮件模板:
public class EmailConfiguration {
@Bean
public SimpleMailMessage templateSimpleMessage() {
SimpleMailMessage message = new SimpleMailMessage();
message.setText("This is the test email template for your email:\n%s\n");
return message;
}
}
现在我们可以使用这个bean作为电子邮件模板,只需要为模板提供必要的参数:
/*@formatter:off*/
@Autowired
public SimpleMailMessage template;
...
String text = String.format(template.getText(), templateArgs);
sendSimpleMessage(to, subject, text);
/*@formatter:on*/
5. 处理发送错误
JavaMail提供SendFailedException来处理无法发送消息的情况。 但是,当我们向错误的地址发送电子邮件时,可能不会出现此异常。原因如下:
RFC 821中的SMTP协议规范指定了SMTP服务器在尝试将电子邮件发送到错误地址时应返回的550返回码。 但大多数公共SMTP服务器不这样做,相反,他们会发送一封”发送失败“的电子邮件,或者根本不提供反馈。
例如,Gmail SMTP服务器发送一条”delivery failed“消息,我们的程序中不会出现异常。
因此,我们有几个选择来处理这种情况:
- 捕获SendFailedException,它永远不会被抛出。
- 在一段时间内,检查我们的发件人邮箱,查看”delivery failed”消息。这并不简单,时间段也不确定。
- 如果我们的邮件服务器根本不提供反馈,我们就无能为力。
6. 总结
在这篇文章中,我们演示了如何从Spring Boot应用程序设置和发送电子邮件。
与往常一样,本教程的完整源代码可在GitHub上获得。