3
votes

I'm tryting to have email templates rendered using Thymeleaf and I would like to have the subject and the body in the same file, but rendered separately. I do not want to use spring view, just plain SpringTemplateEngine.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<!--/*@thymesVar id="user" type="com.myapp.user.User"*/-->
<!--/*@thymesVar id="invitationId" type="java.util.UUID"*/-->
<head>
    <title th:fragment="subject">Hello <span th:text="${user.name}"/></title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<p>
    Hello <span th:text="${user.name}"></span>,<br>
    you've been invited to join MyApp.
</p>
<p>
    Click on the following link to confirm your email and setup a password:<br>
    <a th:href="@{https://myapp.com/accept-invitation(id=${invitationId})}">Accept invitation</a>
</p>
<p>
    Best regards,<br/>
    <em>The MyApp team</em>
</p>
</body>
</html>

There are several problems with this

First, I'm unable to get Thymeleaf render only contents of <title>

String subject = templateEngine.process(
    templateFile,
    ImmutableSet.of("subject"),
    new Context(Locale.ENGLISH, contextVariables)
);

it renders literary only Hello - it looks like the opening <title> tag is always removed and the fragment is trimmer right after the first tag.

And when I render the whole template, it returns

<!DOCTYPE html>
<html>
<head>
    Hello <span>pepa</span></title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<p>
    Hello <span>pepa</span>,<br>
...

Using the following in the <title> makes the output a bit nicer

<span th:text="${user.name}" th:remove="tag"></span>

but the opening tag is still missing.

When I would theoretically succeed in rendering the title correctly, I'd still have it wrapped in an HTML tag - which obviously cannot be used as an email subject. Is there a way to render only contents of the fragment?

I would really like to have both the email subject and body in the same template for cases, when for example I want to do some iteration in the title to generate it from a list - I do not want to do any string concatenations, I wanna have it in the template.

Any suggestions please?

1

1 Answers

-1
votes

If you want to include only the content of your fragment, assuming that your fragment is called your_fragment.html and is placed under /resources/templates/fragments you can do:

<head>
  <title th:replace="fragments/your_fragment::your_fragment"/></title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>

And your_fragment.html:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head></head>
<body>
    <div th:fragment="your_fragment" th:remove="tag">
      Hello <span th:text="${user.name}" th:remove="tag"></span>
    </div>
</body>
</html>

This will render:

<head>
  Hello username
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>