簡體   English   中英

使用Java注釋通過Spring發送電子郵件

[英]Send emails with Spring by using Java annotations

如何使用基於純注釋的方法(根據Java配置規則)發送Spring 4 (和Spring Boot )的電子郵件?

一個簡單的解決方案(您將使用沒有身份驗證的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必須能夠以通常的方式解析屬性email.hostemail.port (在Spring Boot的情況下,最簡單的是將其放在application.properties中)

在任何需要JavaMailSender服務的類中,只需注入一種常用方法(例如@Autowired private JavaMailSender javaMailSender


UPDATE

請注意,從1.2.0.RC1版本開始,Spring Boot可以為您自動配置JavaMailSender 查看文檔的這一部分。 從文檔中可以看出,啟動和運行幾乎不需要任何配置!

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

application.properties

spring.mail.host=...
spring.mail.port=...

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

就個人而言,我建議運行localhost MTA,並使用它轉發到您真正的MTA(如Gmail或SES,或您自己的)。 這為您提供了“免費”異步隊列,並集中配置。 我喜歡OpenSMTP。

使用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)

即使我們設置的是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>

其中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);
    }

}

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

}

@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后一切正常。

使用Spring Boot 1.2,可以為您自動配置JavaMailSender。 我已經有了這個視頻,解釋了如何使用Spring Boot 1.2向前發送郵件。 Spring Lemon的源代碼可以參考具體細節。

除了geoand的答案:如果您不想硬編碼郵件屬性或編寫XML,您可以將屬性添加到資源中的文件(例如mail.properties),並在此處添加此類代碼。 MailConfig類:

@Resource(name = "mailProperties")
private Properties mailProperties;

@Bean(name = "mailProperties")
public PropertiesFactoryBean mapper() {
    PropertiesFactoryBean bean = new PropertiesFactoryBean();
    bean.setLocation(new ClassPathResource("mail.properties"));
    return bean;
}

您可以使用的屬性范圍都在這些頁面上定義

https://javamail.java.net/nonav/docs/api/

https://javamail.java.net/nonav/docs/api/com/sun/mail/smtp/package-summary.html

但是你仍然需要從JavaMailSenderImpl的方法中設置主機,端口,用戶名和密碼,因為它不會直接使用屬性中設置的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM