1. 概要

前の記事では、Springを使用してテキストメールを作成および送信する方法を説明しました。

ただし、 Springテンプレートエンジンを使用して、動的コンテンツを含む美しいHTMLメールを作成することもできます。

このチュートリアルでは、最も有名なThymeleafとFreeMarkerを使用してそれを行う方法を学習します。

2. SpringHTMLメール

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メソッドに渡されるtrue値です。これはHTMLコンテンツタイプを指定します。

ThymeleafおよびFreeMarkerテンプレートを使用してこのhtmlBodyを構築する方法を見てみましょう。

3. Thymeleaf構成

構成から始めましょう。 これは、EmailConfigurationというクラスで分離できます。

まず、テンプレートリゾルバーを提供して、テンプレートファイルディレクトリを見つける必要があります。

3.1. クラスパスリソースとしてのテンプレート

テンプレートファイルはJARファイル内で出荷できます。これは、テンプレートとその入力データ間の結合を維持するための最も簡単な方法です。

JARからテンプレートを見つけるには、ClassLoaderTemplateResolverを使用します。 テンプレートはmain/ resources / mail-templates ディレクトリにあるため、resourceディレクトリを基準にして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;

次に、thymeleafTemplateResolverメソッドのClassLoaderTemplateResolverの代わりに、この値をFileTemplateResolverに渡します。

FileTemplateResolver templateResolver = new FileTemplateResolver();
templateResolver.setPrefix(mailTemplatesPath);

3.3. Thymeleafエンジンを構成する

最後のステップは、Thymeleafエンジンのファクトリメソッドを作成することです。 選択したTemplateResolverをエンジンに通知する必要があります。これは、パラメーターを介してbeanファクトリメソッドに挿入できます。

@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)テンプレートリゾルバーを構成します。今回は、の場所テンプレートは、FreeMarkerConfigurerbeanで構成されます。

4.1. クラスパスのテンプレート

ここでは、Thymeleafと同じオプションがあります。 テンプレートをクラスパスリソースとして構成しましょう。

@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テンプレートのコンテンツ

次に、template-thymeleaf.htmlファイルを見てみましょう。

<!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>

ご覧のとおり、Thymeleaf表記を使用しました。つまり、変数には $ {…}を使用し、ローカライズされた文字列には#{…}を使用しました

テンプレートエンジンは正しく構成されているため、使用は非常に簡単です。テンプレート変数(ここでは Map として渡されます)を含むContextオブジェクトを作成するだけです。

次に、それをテンプレート名とともにprocessメソッドに渡します。

@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テンプレートのコンテンツ

ご覧のとおり、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>

次に、 FreeMarkerConfigurerクラスを使用してテンプレートファイルを取得し、最後にFreeMarkerTemplateUtilsを使用してMapからデータを挿入する必要があります。

@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);
}

さらに進むために、電子メールの署名にロゴを追加する方法を見ていきます。

8. 画像が埋め込まれたメール

HTMLメールに画像を含めることは非常に一般的であるため、CID添付ファイルを使用してこれを行う方法を説明します。

最初の変更は、sendHtmlMessageメソッドに関するものです。 コンストラクターの2番目の引数にtrueを渡して、MimeMessageHelperをマルチパートとして設定する必要があります。

MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");

次に、画像ファイルをリソースとして取得する必要があります。 これには、@Valueアノテーションを使用できます。

@Value("classpath:/mail-logo.png")
Resource resourceFile;

mail-logo.pngファイルがsrc/ main /resourcesディレクトリにあることに注意してください。

sendHtmlMessage メソッドに戻り、 resourceFileをインライン添付ファイルとして追加して、CIDで参照できるようにします。

helper.addInline("attachment.png", resourceFile);

最後に、画像は、CID表記を使用してThymeleafとFreeMarkerの両方の電子メールから参照する必要があります。

<img src="cid:attachment.png" />

9. 結論

この記事では、リッチHTMLコンテンツを含むThymeleafおよびFreeMarkerの電子メールを送信する方法を見てきました。

結論として、ほとんどの作業はSpringに関連しています。 したがって、どちらを使用するかは、電子メールの送信などの単純なニーズと非常によく似ています。

いつものように、例の完全なソースコードはGitHubにあります。