I'm trying to send an email with a given template but, when I call "templateEngine.process" it doesn't give any exception but it doesn't process the template, only returns a string with the template's name
My POM dependencies:
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Spring Doc -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.1.0</version>
</dependency>
<!-- Eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- LOMBOK -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
</dependencies>
My Config:
@Configuration
public class EmailConfiguration {
@Bean
public SpringTemplateEngine springTemplateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(htmlTemplateResolver());
return templateEngine;
}
@Bean
public ClassLoaderTemplateResolver htmlTemplateResolver(){
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("classpath:/templates/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode(TemplateMode.HTML);
emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return emailTemplateResolver;
}
}
My Controller:
@PostMapping("/send")
public boolean sendEmail(@RequestParam("lang") String language, @RequestBody EmailRequestDTO payload) throws NotifierEmailException {
emailService.sendSimpleMailMessage(payload, language);
return true;
}
My Service:
@Service
public class EmailService {
private static final String ENCODING = "UTF-8";
private final JavaMailSender emailSender;
public final TemplateEngine template = new SpringTemplateEngine();
@Autowired
public EmailService(JavaMailSender emailSender) {
this.emailSender = emailSender;
}
public void sendSimpleMailMessage(EmailRequestDTO emailRequestDTO, String language) throws NotifierEmailException {
try {
var locale = Locale.forLanguageTag(language);
// Prepare the evaluation context
final Context thymeleafContext = new Context(locale);
emailRequestDTO.getAttributes().forEach(thymeleafContext::setVariable);
// Prepare message using a Spring helper
final MimeMessage mimeMessage = emailSender.createMimeMessage();
final MimeMessageHelper message = new MimeMessageHelper(mimeMessage, ENCODING);
message.setSubject(emailRequestDTO.getSubject());
message.setFrom(emailRequestDTO.getEmailFrom());
message.setTo(emailRequestDTO.getEmailTo());
// Create the HTML body using Thymeleaf
/* This line here returns a string with the template name that I passed! */
final String htmlContent = template.process("activationEmail.html", thymeleafContext);
message.setText(htmlContent, true);
// Send mail
emailSender.send(mimeMessage);
} catch (Exception exception) {
throw new NotifierEmailException(HttpStatus.INTERNAL_SERVER_ERROR, exception.getMessage());
}
}
}
Didn't include the application.properties cause I'm not using it for thymeleaf.
The log when I executed (I'm hiding some data here):
DATA
354 Go ahead z15-20020aa785cf000000b006daa809584csm3243217pfn.182 - gsmtp
Date: Sat, 27 Jan 2024 19:50:01 -0300 (BRT)
From: [HIDDEN]
To: [HIDDEN]
Message-ID: <851717819.0.1706395805863@DESKTOP-MVK6CCP>
Subject: Activation
MIME-Version: 1.0
Content-Type: text/html;charset=UTF-8
Content-Transfer-Encoding: 7bit
activationEmail.html
.
250 2.0.0 OK 1706395825 z15-20020aa785cf000000b006daa809584csm3243217pfn.182 - gsmtp
DEBUG SMTP: message successfully delivered to mail server
QUIT
While you are creating a Bean of type SpringTemplateEngine
in your configuration class, your @Service
doesn't use this bean:
Service
public class EmailService {
private static final String ENCODING = "UTF-8";
private final JavaMailSender emailSender;
public final TemplateEngine template = new SpringTemplateEngine();
@Autowired
public EmailService(JavaMailSender emailSender) {
this.emailSender = emailSender;
}
Your template
field is initialised with a newly created SpringTemplateEngine
instance, and your constructor only takes a JavaMailSender
instance.
You need to add a TemplateEngine
parameter to your constructor and remove the initialisation of the template
field.
So your EamilService
looks like:
...
private final TemplateEngine template;
@Autowired
public EmailService(JavaMailSender emailSender, TemplateEngine templateEngine) {
this.emailSender = emailSender;
this.templateEngine = templateEngine;
}
...
As the Javadoc for TemplateEngine says, a TemplateEngine
with no ItemplateResolver
configured will use a StringTemplateResolver
which explains the behaviour you saw.