Отправка писем с Spring с помощью аннотаций Java

Как я мог отправить электронное письмо с Весна 4Весна Загрузки), используя чистый подход на основе аннотаций (согласно Конфигурации Java правила)?

5 ответов


простое решение (где вы будете использовать 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.host и email.port обычными способами (в случае весенней загрузки проще всего поставить тогда в приложение.свойства)

в любом классе, который нуждается в услугах JavaMailSender, просто введите один из обычных способов (например @Autowired private JavaMailSender javaMailSender)


обновление

обратите внимание, что начиная с версии 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, или ваш собственный). Это дает вам" свободную " асинхронную очередь и централизует config. Мне нравится OpenSMTP.


С Spring-Boot это было близко к тривиальному, с одной настройкой, необходимой для smtp.office365.com почтовый сервер-это то, что использует эта компания.

прежде чем сделать эту настройку, аутентификация на SMTP-сервере Office365 продолжала терпеть неудачу, и мы получили бы ошибку по строкам:

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)

Это было, хотя мы устанавливали имя пользователя и пароль, которые были правильно подобраны классом MailProperties Spring.

оказывается Office365 необходимо включить аутентификацию TLS, и текущая реализация JavaMail Spring не имеет простого способа сделать это со свойствами. Решение состоит в том, чтобы создать наш собственный javax.почта.Экземпляр сеанса и зарегистрируйте его с помощью Spring.

вся картина следует.

В пом.XML-файл, добавить:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
        <version>${spring-boot.version}</version>
    </dependency>

где весна-загрузки.версия определяется в другом месте (в Родительском pom в этом случае) и в этом случае имеет значение 1.3.1.Отпустите

обязательно включите пакет и / или класс автоматической настройки, если вы детализируете их в своем основном приложении-если вы используете по умолчанию @SpringBootApplication, это не нужно, но в моем случае я добавил MailSenderAutoConfiguration.класс в список классов аннотации @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 является аннотацией Ломбока, а @Subscribe - для EventBus Guava, именно так это приложение позволяет EmailSender знать, что есть сообщение для отправки. Я использую тривиальный EMAILMESSAGEEVENT POJO, который имеет тему и текст сообщения - достаточно хорошо для целей этого приложения.

класс MessageConfig просто упрощает настройку значений по умолчанию сообщений вместе с остальной конфигурацией приложения, и у него есть один кусок специального соуса, который был необходим для этой работы с SMTP-сервером Office365, пользовательским javax.почта.Экземпляр сеанса, зарегистрированный как 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 снова является Ломбок аннотации - automatagically добавляет мутатор и методов, метод toString(), метод equals() & hashCode(), то и т. д.

ограничение Javamailsender Spring (JavaMailSenderImpl) заключается в том, что его сеанс не настраивается напрямую, в частности, нет способа включить аутентификацию TLS через свойство. Однако, если есть javax.почта.Компонент сеанса, зарегистрированный в контексте, который будет введен (условно автоматически) в MailSenderAutoConfiguration и затем использован для создайте экземпляр JavaMailSenderImpl.

таким образом, мы регистрируем только такой боб с помощью метода getSession (). Для хорошей меры мы делаем сеанс, который мы строим здесь, по умолчанию для JVM-измените его, чтобы вызвать getInstance (), если вы не хотите этого поведения.

после добавления этого сеанса @Bean все работало.


используя Spring Boot 1.2 и далее, JavaMailSender может быть автоматически настроен для вас. У меня есть видео объясняя, как именно отправлять письма с помощью Spring Boot 1.2 и далее. Весна Лимон's исходный код может быть упомянут для получения точной информации.


в дополнение к ответу geoand: если вы не хотите жестко кодировать свойства почты или писать XML, вы можете добавить свои свойства в файл (mail.свойства, например) в ваших ресурсах и добавьте этот код в класс 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, поскольку он не будет напрямую использовать те, которые установлены в ваших свойствах.