Отправлять письма с помощью Spring с помощью аннотаций Java
Как я могу отправить электронное письмо с Spring 4 (и Spring Загрузка), используя чистый подход, основанный на аннотациях (в соответствии с правилами Java Configurations )?
Ответы
Ответ 1
Простое решение (где вы будете использовать 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
обычными способами (в случае Spring Boot самый простой - это поставить в application.properties)
В любом классе, который нуждается в сервисах JavaMailSender, просто введите один из обычных способов (например, @Autowired private JavaMailSender javaMailSender
)
UPDATE
Обратите внимание, что поскольку версия 1.2.0.RC1 Spring Boot может автоматически настроить JavaMailSender
для вас. Ознакомьтесь с этой частью документации. Как вы можете видеть из документации, для запуска и запуска почти никакой конфигурации не требуется!
Ответ 2
В 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("[email protected]");
message.setTo("[email protected]");
message.setSubject("hello");
mailSender.send(message);
}
}
Лично я рекомендую запустить localhost MTA и использовать его для передачи на ваш реальный MTA (например, Gmail или SES или ваш собственный). Это дает вам "бесплатную" асинхронную очередь и централизует конфигурацию. Мне нравится OpenSMTP.
Ответ 3
С 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)
Это было даже при том, что мы установили имя пользователя и пароль, которые были правильно подобраны классом 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 знать там сообщение для отправки. Я использую тривиальный POJO EmailMessageEvent, который имеет тему и текст сообщения - достаточно хорош для целей этого приложения.
Класс MessageConfig просто упрощает настройку сообщений по умолчанию вместе с остальной конфигурацией приложения, и в нем есть один кусок специального соуса, который необходим для работы с SMTP-сервером Office365, настраиваемый 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 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) заключается в том, что его сеанс напрямую не настраивается, в частности, нет возможности включить проверку подлинности TLS через свойство. Однако, если в этом контексте зарегистрирован javax.mail.Session Bean, который будет инъецирован (условно автоподтвержден) в MailSenderAutoConfiguration, а затем используется для создания экземпляра JavaMailSenderImpl.
Итак, мы регистрируем только такой Bean с помощью метода getSession(). Для хорошей меры мы создаем здесь сессию по умолчанию для JVM - изменим ее на вызов getInstance(), если вы не хотите этого поведения.
После добавления сеанса @ Bean все сработало.
Ответ 4
Используя Spring Boot 1.2, JavaMailSender может быть настроен автоматически для вас. У меня есть это видео, объясняющее, как именно отправлять почту с помощью Spring Boot 1.2 и далее. Spring Исходный код Lemon можно указать для точной информации.
Ответ 5
В дополнение к запросу 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
Но вам все равно придется устанавливать Host, Port, Username и Password из методов JavaMailSenderImpl, так как он напрямую не использует те, которые установлены в ваших свойствах.