使用Java注释通过Spring发送电子邮件

vde*_*ris 17 email spring spring-boot spring-java-config

如何使用基于纯注释的方法(根据Java配置规则)发送Spring 4(和Spring Boot)的电子邮件?

geo*_*and 33

一个简单的解决方案(您将使用没有身份验证的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

春天必须能够解决性能email.hostemail.port通常的方式(在春季启动的情况下,最简单的就是把那么application.properties)

在任何需要JavaMailSender服务的类中,只需注入一种常用方法(例如@Autowired private JavaMailSender javaMailSender)


UPDATE

请注意,从版本1.2.0.RC1 Spring Boot可以自动配置JavaMailSender.查看文档的这一部分.从文档中可以看出,启动和运行几乎不需要任何配置!


Nei*_*gan 10

pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)

application.properties:

spring.mail.host=...
spring.mail.port=...
Run Code Online (Sandbox Code Playgroud)

Foo.java:

@Component
public class Foo {

    @Autowired
    private JavaMailSender mailSender;

    public void send() {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom("foo@example.com");
        message.setTo("bar@example.com");
        message.setSubject("hello");
        mailSender.send(message);
    }
}
Run Code Online (Sandbox Code Playgroud)

就个人而言,我建议运行localhost MTA,并使用它转发到您真正的MTA(如Gmail或SES,或您自己的).这为您提供了"免费"异步队列,并集中配置.我喜欢OpenSMTP.


sof*_*end 7

使用Spring-Boot,它几乎是微不足道的,smtp.office365.com邮件服务器需要进行一次调整 - 这是该公司正在使用的.

在进行此调整之前,对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)
Run Code Online (Sandbox Code Playgroud)

即使我们设置的是Spring的MailProperties类正确选择的用户名和密码.

事实证明Office365需要启用TLS身份验证,而Spring的当前JavaMail实现没有一种简单的方法来实现属性.解决方案是创建我们自己的javax.mail.Session实例并将其注册到Spring.

整个画面如下.

在pom.xml文件中,添加:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
        <version>${spring-boot.version}</version>
    </dependency>
Run Code Online (Sandbox Code Playgroud)

其中spring-boot.version在别处定义(在本例中为父pom),在这种情况下的值为1.3.1.RELEASE

如果你在主应用程序中逐条列出它们,请确保包括包和/或自动配置类 - 如果使用默认的@SpringBootApplication,则不需要,但在我的情况下,我将MailSenderAutoConfiguration.class添加到@Import注释中课程列表.

我创建了一个简单的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);
    }

}
Run Code Online (Sandbox Code Playgroud)

@ Slf4j是一个lombok注释,而@Subscribe是用于Guava的EventBus,这个应用程序让EmailSender知道有一条消息要发送.我使用了一个简单的EmailMessageEvent POJO,它有一个主题和消息文本 - 足以满足这个应用程序的需要.

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());
            }
        });
    }

}
Run Code Online (Sandbox Code Playgroud)

@Data再次是一个Lombok注释 - 自动添加mutator和accessor方法,toString(),equals()和hashCode()等.

Spring的JavaMailSender(JavaMailSenderImpl)的限制是它的Session不能直接配置,特别是没有办法通过属性启用TLS身份验证.但是,如果在上下文中注册了javax.mail.Session Bean,则会将其注入(有条件地自动装入)到MailSenderAutoConfiguration中,然后用于构造JavaMailSenderImpl实例.

所以我们通过getSession()方法注册这样一个Bean.为了更好地衡量,我们将我们在此构造的Session作为JVM的默认值 - 如果您不想要这种行为,请将其更改为调用getInstance().

添加此Session @Bean后一切正常.