«1. Обзор
В нашей предыдущей статье мы видели, как использовать Spring для написания и отправки текстовых электронных писем.
Но также можно использовать механизмы шаблонов Spring для написания красивых электронных писем в формате HTML с динамическим содержимым.
В этом уроке мы узнаем, как это сделать, используя самые известные из них: Thymeleaf и FreeMarker.
2. Электронные письма в формате Spring HTML
Начнем с руководства по электронной почте Spring.
Во-первых, мы добавим в класс EmailServiceImpl метод для отправки писем с текстом HTML:
private void sendHtmlMessage(String to, String subject, String htmlBody) throws MessagingException {
MimeMessage message = emailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(to);
helper.setSubject(subject);
helper.setText(htmlBody, true);
emailSender.send(message);
}
Мы используем MimeMessageHelper для заполнения сообщения. Важной частью является истинное значение, передаваемое методу setText: оно определяет тип содержимого HTML.
Теперь посмотрим, как создать этот htmlBody с помощью шаблонов Thymeleaf и FreeMarker.
3. Настройка Thymeleaf
Начнем с настройки. Мы можем изолировать это в классе под названием EmailConfiguration.
Во-первых, мы должны предоставить распознаватель шаблонов для поиска каталога файлов шаблонов.
3.1. Шаблоны как ресурсы пути к классам
Файлы шаблонов могут быть отправлены в файле JAR, что является самым простым способом поддержания согласованности между шаблонами и их входными данными.
Чтобы найти шаблоны из JAR, мы используем ClassLoaderTemplateResolver. Наши шаблоны находятся в директории main/resources/mail-templates, поэтому мы устанавливаем атрибут Prefix относительно директории ресурсов:
@Bean
public ITemplateResolver thymeleafTemplateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("mail-templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
3.2. Шаблоны из внешнего каталога
В других случаях мы можем захотеть изменить шаблоны без пересборки и развертывания. Для этого мы можем поместить шаблоны в файловую систему.
Может быть полезно настроить этот путь в application.properties, чтобы мы могли изменять его для каждого развертывания. Доступ к этому свойству можно получить с помощью аннотации @Value:
@Value("${spring.mail.templates.path}")
private String mailTemplatesPath;
Затем мы передаем это значение в FileTemplateResolver вместо ClassLoaderTemplateResolver в нашем методе thymeleafTemplateResolver:
FileTemplateResolver templateResolver = new FileTemplateResolver();
templateResolver.setPrefix(mailTemplatesPath);
3.3. Настройка движка Thymeleaf
Последний шаг — создание фабричного метода для движка Thymeleaf. Нам нужно сообщить движку, какой TemplateResolver мы выбрали, который мы можем внедрить через параметр в метод фабрики компонентов:
@Bean
public SpringTemplateEngine thymeleafTemplateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
templateEngine.setTemplateEngineMessageSource(emailMessageSource());
return templateEngine;
}
Здесь созданный ранее преобразователь автоматически внедряется Spring в механизм шаблонов. заводской метод.
4. Конфигурация FreeMarker
Так же, как Thymeleaf, в классе EmailConfiguration мы настроим преобразователь шаблонов для шаблонов FreeMarker (.ftl): И на этот раз расположение шаблонов будет настроено в bean-компонент FreeMarkerConfigurer.
4.1. Шаблоны в пути к классам
Здесь у нас те же параметры, что и для Thymeleaf. Настроим шаблоны как ресурсы classpath:
@Bean
public FreeMarkerConfigurer freemarkerClassLoaderConfig() {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_27);
TemplateLoader templateLoader = new ClassTemplateLoader(this.getClass(), "/mail-templates");
configuration.setTemplateLoader(templateLoader);
FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.setConfiguration(configuration);
return freeMarkerConfigurer;
}
4.2. Шаблоны в файловой системе
Чтобы настроить шаблоны из другого пути в файловой системе, нам нужно заменить экземпляр TemplateLoader:
TemplateLoader templateLoader = new FileTemplateLoader(new File(mailTemplatesPath));
5. Локализация с помощью Thymeleaf и FreeMarker
Чтобы управлять переводами с помощью Thymeleaf, мы можем указать движку экземпляр MessageSource:
@Bean
public ResourceBundleMessageSource emailMessageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("mailMessages");
return messageSource;
}
@Bean
public SpringTemplateEngine thymeleafTemplateEngine() {
...
templateEngine.setTemplateEngineMessageSource(emailMessageSource());
...
}
src/main/resources/mailMessages_xx_YY.properties
Затем мы создадим пакеты ресурсов для каждой поддерживаемой локали:
Так как FreeMarker предлагает локализацию путем дублирования шаблонов, нам не нужно настраивать источник сообщения там.
6. Содержимое шаблонов Thymeleaf
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="#{greetings(${recipientName})}"></p>
<p th:text="${text}"></p>
<p th:text="#{regards}"></p>
<p>
<em th:text="#{signature(${senderName})}"></em> <br />
</p>
</body>
</html>
Далее давайте посмотрим на файл template-thymeleaf.html:
Как видно, мы использовали нотацию Thymeleaf, то есть ${â €¦} для переменных и #{…} для локализованных строк.
Поскольку механизм шаблонов настроен правильно, использовать его очень просто: мы просто создадим объект Context, который содержит переменные шаблона (здесь они передаются как карта).
@Autowired
private SpringTemplateEngine thymeleafTemplateEngine;
@Override
public void sendMessageUsingThymeleafTemplate(
String to, String subject, Map<String, Object> templateModel)
throws MessagingException {
Context thymeleafContext = new Context();
thymeleafContext.setVariables(templateModel);
String htmlBody = thymeleafTemplateEngine.process("template-thymeleaf.html", thymeleafContext);
sendHtmlMessage(to, subject, htmlBody);
}
Затем мы передадим его методу процесса вместе с именем шаблона:
Теперь давайте посмотрим, как сделать то же самое с FreeMarker.
7. Содержимое шаблонов FreeMarker
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Hi ${recipientName}</p>
<p>${text}</p>
<p>Regards,</p>
<p>
<em>${senderName} at Baeldung</em> <br />
</p>
</body>
</html>
Как видно, синтаксис FreeMarker проще, но опять же он не работает с локализованными строками. Итак, вот английская версия:
@Autowired
private FreeMarkerConfigurer freemarkerConfigurer;
@Override
public void sendMessageUsingFreemarkerTemplate(
String to, String subject, Map<String, Object> templateModel)
throws IOException, TemplateException, MessagingException {
Template freemarkerTemplate = freemarkerConfigurer.getConfiguration()
.getTemplate("template-freemarker.ftl");
String htmlBody = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerTemplate, templateModel);
sendHtmlMessage(to, subject, htmlBody);
}
«
«Затем мы должны использовать класс FreeMarkerConfigurer для получения файла шаблона и, наконец, FreeMarkerTemplateUtils для вставки данных из нашей карты:
Чтобы идти дальше, мы увидим, как добавить логотип в нашу электронную подпись.
8. Электронные письма со встроенными изображениями
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
Так как очень часто в электронные письма в формате HTML добавляются изображения, мы посмотрим, как это сделать с помощью вложения CID.
@Value("classpath:/mail-logo.png")
Resource resourceFile;
Первое изменение касается метода sendHtmlMessage. Мы должны установить MimeMessageHelper как состоящую из нескольких частей, передав true второму аргументу конструктора:
Затем мы должны получить файл изображения в качестве ресурса. Для этого мы можем использовать аннотацию @Value:
helper.addInline("attachment.png", resourceFile);
Обратите внимание, что файл mail-logo.png находится в каталоге src/main/resources.
<img src="cid:attachment.png" />
Возвращаясь к методу sendHtmlMessage, мы добавим resourceFile в качестве встроенного вложения, чтобы можно было ссылаться на него с помощью CID:
Наконец, на изображение нужно ссылаться как из электронных писем Thymeleaf, так и из электронных писем FreeMarker, используя CID обозначение:
9. Заключение
В этой статье мы увидели, как отправлять электронные письма Thymeleaf и FreeMarker, включая богатое содержимое HTML.