Search code examples
javaemailjakarta-mailhtml-email

How can I read an HTML template from a file to send a mail with it using the JavaMail API?


I've got an assigment to send HTML mail with the JavaMail API. Here is a small part of my code:

MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);

try {
    helper.setTo(recipients);
    helper.setSubject("Simple mail template");
    helper.setText("<html><body>Hi There</body><html>",html:true);
} catch (MessagingException e) {
        e.printStackTrace();
}

Now I've got an assigment to move the HTML in a separate file, and create a class to read that HTML template and send a mail with it. Any suggestions on how to do that?


Solution

  • Use a template engine

    I've created a minimal example with Thymeleaf as a template engine. You first wrote that you are using Spring Boot in your project, so I assume you can use it. I also assume you are using either Maven or Gradle as a build tool.


    Adding the Thymeleaf dependency

    Add the spring-boot-starter-thymeleaf dependency to your project. Are you using Maven or Gradle?

    Maven

    Your pom.xml dependencies should include:

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

    Gradle

    Your build.gradle dependencies should include:

    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    

    Configuring Thymeleaf in Spring Boot

    Add the required @Beans. Those are:

    @Bean
    public ITemplateResolver templateResolver()
    {
        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
        templateResolver.setPrefix("templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode(TemplateMode.HTML);
    
        return templateResolver;
    }
    
    @Bean
    public TemplateEngine templateEngine()
    {
        TemplateEngine templateEngine = new TemplateEngine();
        templateEngine.setTemplateResolver(this.templateResolver());
    
        return templateEngine;
    }
    

    They can go into any class annotated with @Configuration (or @SpringBootApplication).


    Examples

    Now, you can access your TemplateEngine from any class whose fields are injected by Spring.

    @Component
    public class SomeClass
    {
        @Autowired
        private TemplateEngine templateEngine;
    
        public String generateMailHtml(String text)
        {
            Map<String, Object> variables = new HashMap<>();
            variables.put("mailtext", text);
    
            final String templateFileName = "mail"; //Name of the template file without extension
            String output = this.templateEngine.process(templateFileName, new Context(Locale.getDefault(), variables));
    
            return output;
        }
    }
    

    The mail.html should be located in the classpath (resources/) under templates/.

    Template file path

    And it should look like this:

    <html>
        <body data-th-text="${mailtext}"></body>
    </html>
    

    Your code snippet you posted could now look like this (@Autowired SomeClass as someClass in the class outside of the method):

    MimeMessage message = sender.createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(message);
    
    try {
        helper.setTo(recipients);
        helper.setSubject("Simple mail template");
        helper.setText(someClass.generateMailHtml("Hi There"), true);
    } catch (MessagingException e) {
        e.printStackTrace();
    }
    

    Of course, change the examples according to your needs!


    Edit

    You mentioned you need to fill the template "with a list of some names". This would be achieved like that:

    public String generateMailHtml(List<String> names)
    {
        Map<String, Object> variables = new HashMap<>();
        variables.put("names", names);
    
        final String templateFileName = "mail"; //Name of the template file without extension
        String output = this.templateEngine.process(templateFileName, new Context(Locale.getDefault(), variables));
    
        return output;
    }
    

    mail.html

    <html>
        <body>
            <ul>
                <li data-th-each="name : ${names}" data-th-text="${name}"></li>
            </ul>
        </body>
    </html>
    

    Read more about data-th-each / th:each here. Note: You can use data-th- and th: interchangably, though data-th- is more HTML5-friendly.