使用 Java 注释使用 Spring 发送电子邮件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22483407/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Send emails with Spring by using Java annotations
提问by vdenotaris
How could I send an email with Spring 4(and Spring Boot) by using a pure annotation-based approach (according to the Java Configurationsrules)?
如何使用纯基于注释的方法(根据Java 配置规则)发送带有Spring 4(和Spring Boot)的电子邮件?
回答by geoand
A simple solution (where you will be using an SMTP server with no authentication) for configuring the email service would by
一个用于配置电子邮件服务的简单解决方案(您将使用没有身份验证的 SMTP 服务器)
@Configuration
public class MailConfig {
@Value("${email.host}")
private String host;
@Value("${email.port}")
private Integer port;
@Bean
public JavaMailSender javaMailService() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setHost(host);
javaMailSender.setPort(port);
javaMailSender.setJavaMailProperties(getMailProperties());
return javaMailSender;
}
private Properties getMailProperties() {
Properties properties = new Properties();
properties.setProperty("mail.transport.protocol", "smtp");
properties.setProperty("mail.smtp.auth", "false");
properties.setProperty("mail.smtp.starttls.enable", "false");
properties.setProperty("mail.debug", "false");
return properties;
}
}
Spring must be able to resolve the properties email.host
and email.port
in of the usual ways (in case of Spring Boot the simplest is to put then in application.properties)
春天必须能够解决性能email.host
和email.port
通常的方式(在春季启动的情况下,最简单的就是把那么application.properties)
In any class that needs the services of JavaMailSender, just inject with one of the usual ways (such as @Autowired private JavaMailSender javaMailSender
)
在任何需要 JavaMailSender 服务的类中,只需注入一种常用方式(例如@Autowired private JavaMailSender javaMailSender
)
UPDATE
更新
Note that since version 1.2.0.RC1 Spring Boot can auto-configure JavaMailSender
for you. Check out thispart of the documentation. As you can see from the documentation, almost no configuration is required to get up and running!
请注意,从 1.2.0.RC1 版本开始,Spring Boot 可以JavaMailSender
为您自动配置。查看文档的这一部分。从文档中可以看出,启动和运行几乎不需要任何配置!
回答by Neil McGuigan
In pom.xml
:
在pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
In application.properties
:
在application.properties
:
spring.mail.host=...
spring.mail.port=...
In Foo.java
:
在Foo.java
:
@Component
public class Foo {
@Autowired
private JavaMailSender mailSender;
public void send() {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("[email protected]");
message.setTo("[email protected]");
message.setSubject("hello");
mailSender.send(message);
}
}
Personally, I recommend running a localhost MTA, and using it to relay to your real MTA (like Gmail or SES, or your own). This gives you a "free" asynchronous queue, and centralizes config. I like OpenSMTP.
就个人而言,我建议运行本地 MTA,并使用它来中继到您真正的 MTA(如 Gmail 或 SES,或您自己的)。这为您提供了一个“免费”的异步队列,并集中了配置。我喜欢 OpenSMTP。
回答by sofend
With Spring-Boot it was close to trivial, with one adjustment needed for smtp.office365.com mail server - which is what this company is using.
使用 Spring-Boot,它几乎是微不足道的,只需要对 smtp.office365.com 邮件服务器进行一项调整——这就是该公司正在使用的。
Before making this adjustment the authentication to the Office365 SMTP server kept failing and we'd get an error along the lines of:
在进行此调整之前,对 Office365 SMTP 服务器的身份验证一直失败,我们会收到以下错误:
org.springframework.mail.MailSendException: Failed messages: com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.57 SMTP; Client was not authenticated to send anonymous mail during MAIL FROM
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:474)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:307)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:296)
This was even though we were setting a username and password that were being correctly picked up by Spring's MailProperties class.
即使我们设置了 Spring 的 MailProperties 类正确获取的用户名和密码,也是如此。
Turns out Office365 needs TLS authentication enabled and Spring's current JavaMail implementation doesn't have a simple way to do that with properties. The solution is to create our own javax.mail.Session instance and register it with Spring.
原来 Office365 需要启用 TLS 身份验证,而 Spring 的当前 JavaMail 实现没有一个简单的方法来使用属性来做到这一点。解决方案是创建我们自己的 javax.mail.Session 实例并在 Spring 中注册它。
The whole picture follows.
全图如下。
In the pom.xml file, add:
在 pom.xml 文件中,添加:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>${spring-boot.version}</version>
</dependency>
Where spring-boot.version is defined elsewhere (in a parent pom in this case) and in this case has a value of 1.3.1.RELEASE
其中 spring-boot.version 在别处定义(在这种情况下在父 pom 中)并且在这种情况下具有 1.3.1.RELEASE 的值
Make sure to include the package and/or the auto-configuration class if you itemize those in your main application - if you use the default @SpringBootApplication this isn't needed, but in my case I added MailSenderAutoConfiguration.class to the @Import annotation's list of classes.
如果您在主应用程序中逐项列出这些包和/或自动配置类,请确保包含包和/或自动配置类 - 如果您使用默认的 @SpringBootApplication 这不是必需的,但在我的情况下,我将 MailSenderAutoConfiguration.class 添加到 @Import 注释的类列表。
I created a simple EmailSender class:
我创建了一个简单的 EmailSender 类:
@SuppressWarnings("SpringJavaAutowiringInspection")
@Slf4j
@Service
@ConditionalOnClass(JavaMailSender.class)
public class EmailSender {
@Autowired
private EventBus mmEventBus;
@Autowired
private JavaMailSender mailSender;
@Autowired
private MessageConfig messageConfig;
@Subscribe
public void sendEmail(EmailMessageEvent eme) {
log.info("{}", eme);
SimpleMailMessage msg = new SimpleMailMessage(messageConfig.getMessageTemplate());
msg.setSubject(eme.getSubject());
msg.setText(eme.getMessage());
try {
mailSender.send(msg);
} catch (MailException ex) {
log.error("Error sending mail message: " + eme.toString(), ex);
}
}
@PostConstruct
public void start() throws MessagingException {
mmEventBus.register(this);
}
}
Where the @Slf4j is a lombok annotation, and the @Subscribe is for Guava's EventBus, which is how this app lets the EmailSender know there's a message to send. I use a trivial EmailMessageEvent POJO that has a subject and message text - good enough for this app's purposes.
其中@Slf4j 是lombok 注释,@Subscribe 用于Guava 的EventBus,这就是该应用程序如何让EmailSender 知道有消息要发送。我使用了一个简单的 EmailMessageEvent POJO,它有一个主题和消息文本——对于这个应用程序来说已经足够了。
The MessageConfig class just makes it easy to set up message defaults along with the rest of the application's configuration, and it has the one piece of special sauce that was needed to make this work with an Office365 SMTP server, a custom javax.mail.Session instance registered as a Spring Bean:
MessageConfig 类只是使设置消息默认值以及应用程序的其余配置变得容易,并且它具有使此功能与 Office365 SMTP 服务器(自定义 javax.mail.Session)一起使用所需的特殊调味料注册为 Spring Bean 的实例:
@Data
@Component
@ConfigurationProperties(prefix = "spring.message", ignoreUnknownFields = false)
@Slf4j
public class MessageConfig {
@SuppressWarnings("SpringJavaAutowiringInspection")
@Autowired
private MailProperties mailProperties;
private String from;
private String subject;
private String[] recipients;
private SimpleMailMessage messageTemplate;
public void setRecipients(String... r) {
this.recipients = r;
}
@PostConstruct
public void createTemplate() {
messageTemplate = new SimpleMailMessage();
messageTemplate.setFrom(from);
messageTemplate.setSubject(subject);
messageTemplate.setTo(recipients);
log.debug("Email Message Template defaults: {}", messageTemplate);
}
@Bean
public SimpleMailMessage getMessageTemplate() {
return messageTemplate;
}
@Bean
public Session getSession() {
log.debug("Creating javax.mail.Session with TLS enabled.");
// We could be more flexible and have auth based on whether there's a username and starttls based on a property.
Properties p = new Properties();
p.setProperty("mail.smtp.auth", "true");
p.setProperty("mail.smtp.starttls.enable", "true");
p.setProperty("mail.smtp.host", mailProperties.getHost());
p.setProperty("mail.smtp.port", mailProperties.getPort().toString());
return Session.getDefaultInstance(p, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(mailProperties.getUsername(), mailProperties.getPassword());
}
});
}
}
The @Data is again a Lombok annotation - automatagically adds mutator and accessor methods, toString(), equals() & hashCode(), etc.
@Data 又是一个 Lombok 注释——自动添加了 mutator 和 accessor 方法、toString()、equals() 和 hashCode() 等。
The limitation of Spring's JavaMailSender (JavaMailSenderImpl) is that its Session is not directly configurable, in particular there's no way to enable TLS authentication via a property. However, if there's a javax.mail.Session Bean registered in the context, that will be injected (conditionally autowired) into the MailSenderAutoConfiguration and then used to construct the JavaMailSenderImpl instance.
Spring 的 JavaMailSender (JavaMailSenderImpl) 的局限性在于其 Session 不可直接配置,尤其是无法通过属性启用 TLS 身份验证。但是,如果在上下文中注册了 javax.mail.Session Bean,它将被注入(有条件地自动装配)到 MailSenderAutoConfiguration 中,然后用于构造 JavaMailSenderImpl 实例。
So we register just such a Bean via the getSession() method. For good measure we make the Session we construct here the default one for the JVM - change it to call getInstance() if you don't want that behavior.
所以我们通过 getSession() 方法注册了这样一个 Bean。为了更好地衡量,我们将我们在此处构造的会话设为 JVM 的默认会话 - 如果您不想要这种行为,请将其更改为调用 getInstance()。
After adding this Session @Bean everything worked.
添加此会话@Bean 后一切正常。
回答by Sanjay
Using Spring Boot 1.2 onwards, a JavaMailSender could be auto-configured for you. I've got this videoexplaining how exactly to send mails using Spring Boot 1.2 onwards. Spring Lemon's source code could be referred to for the exact details.
使用 Spring Boot 1.2 以后,可以为您自动配置 JavaMailSender。我有这个视频,解释了如何使用 Spring Boot 1.2 或更高版本发送邮件。确切的细节可以参考Spring Lemon的源代码。
回答by Geoffrey
In addition to geoand's answer: if you don't want to hard code the mail properties or to write XML, you can add your properties to a file (mail.properties for example) in your resources, and add this kind of code in the MailConfig class:
除了 geoand 的回答:如果您不想硬编码邮件属性或编写 XML,您可以将您的属性添加到资源中的文件(例如 mail.properties),并在邮件配置类:
@Resource(name = "mailProperties")
private Properties mailProperties;
@Bean(name = "mailProperties")
public PropertiesFactoryBean mapper() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("mail.properties"));
return bean;
}
And the range of properties you can use is all defined on these pages
您可以使用的属性范围都在这些页面上定义
https://javamail.java.net/nonav/docs/api/
https://javamail.java.net/nonav/docs/api/
https://javamail.java.net/nonav/docs/api/com/sun/mail/smtp/package-summary.html
https://javamail.java.net/nonav/docs/api/com/sun/mail/smtp/package-summary.html
But you'll still have to set Host, Port, Username and Password from the JavaMailSenderImpl's methods as it wont directly use the ones set in your properties.
但是您仍然必须从 JavaMailSenderImpl 的方法中设置主机、端口、用户名和密码,因为它不会直接使用在您的属性中设置的那些。