如何使用 JavaMail API 从文件中读取 HTML 模板来发送邮件?

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

我有一个任务要使用 JavaMail API 发送 HTML 邮件。 这是我的代码的一小部分:

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

现在我有一个任务要将 HTML 移到一个单独的文件中,并创建一个 class 来读取 HTML 模板并用它发送邮件。 关于如何做到这一点有什么建议吗?

我喜欢 jhipster 方法,只需使用 jhipster 生成应用程序。你得到了很好的例子。他们代码的一小部分

模板消息保存为您项目中的资源:

   <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title th:text="#{email.activation.title}">Activation</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link rel="shortcut icon" th:href="@{|${baseUrl}/favicon.ico|}" />
    </head>
    <body>
        <p th:text="#{email.activation.greeting(${user.login})}">
            Dear
        </p>
        <p th:text="#{email.activation.text1}">
            Your  account has been created, please click on the URL below to activate it:
        </p>
        <p>
            <a th:href="@{|${baseUrl}/#/activate?key=${user.activationKey}|}"
               th:text="@{|${baseUrl}/#/activate?key=${user.activationKey}|}">Activation Link</a>
        </p>
        <p>
            <span th:text="#{email.activation.text2}">Regards, </span>
            <br/>
            <em th:text="#{email.signature}">Innovation Development HUB.</em>
        </p>
    </body>
</html>

在 yaml 文件中配置凭据和发送电子邮件首选项之前的电子邮件发件人

@Service
public class MailService {

    private final Logger log = LoggerFactory.getLogger(MailService.class);

    private static final String USER = "user";

    private static final String BASE_URL = "baseUrl";

    private final JHipsterProperties jHipsterProperties;

    private final JavaMailSender javaMailSender;

    private final MessageSource messageSource;

    private final SpringTemplateEngine templateEngine;

    public MailService(JHipsterProperties jHipsterProperties, JavaMailSender javaMailSender,
            MessageSource messageSource, SpringTemplateEngine templateEngine) {

        this.jHipsterProperties = jHipsterProperties;
        this.javaMailSender = javaMailSender;
        this.messageSource = messageSource;
        this.templateEngine = templateEngine;
    }

    @Async
    public void sendEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) {
        log.debug("Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}",
            isMultipart, isHtml, to, subject, content);

        // Prepare message using a Spring helper
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, CharEncoding.UTF_8);
            message.setTo(to);
            message.setFrom(jHipsterProperties.getMail().getFrom());
            message.setSubject(subject);
            message.setText(content, isHtml);
            javaMailSender.send(mimeMessage);
            log.debug("Sent email to User '{}'", to);
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.warn("Email could not be sent to user '{}'", to, e);
            } else {
                log.warn("Email could not be sent to user '{}': {}", to, e.getMessage());
            }
        }
    }

    @Async
    public void sendEmailFromTemplate(User user, String templateName, String titleKey) {
        Locale locale = Locale.forLanguageTag(user.getLangKey());
        Context context = new Context(locale);
        context.setVariable(USER, user);
        context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl());
        String content = templateEngine.process(templateName, context);
        String subject = messageSource.getMessage(titleKey, null, locale);
        sendEmail(user.getEmail(), subject, content, false, true);

    }

    @Async
    public void sendActivationEmail(User user) {
        log.debug("Sending activation email to '{}'", user.getEmail());
        sendEmailFromTemplate(user, "activationEmail", "email.activation.title");
    }

    @Async
    public void sendCreationEmail(User user) {
        log.debug("Sending creation email to '{}'", user.getEmail());
        sendEmailFromTemplate(user, "creationEmail", "email.activation.title");
    }

    @Async
    public void sendPasswordResetMail(User user) {
        log.debug("Sending password reset email to '{}'", user.getEmail());
        sendEmailFromTemplate(user, "passwordResetEmail", "email.reset.title");
    }
}

并且你需要SpringTemplateEngine

public class SpringTemplateEngine extends TemplateEngine implements MessageSourceAware, InitializingBean {
    private static final SpringStandardDialect SPRINGSTANDARD_DIALECT = new SpringStandardDialect();
    private MessageSource messageSource = null;
    private MessageSource templateEngineMessageSource = null;

    public SpringTemplateEngine() {
        super.clearDialects();
        super.addDialect(SPRINGSTANDARD_DIALECT);
    }

    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    public void setTemplateEngineMessageSource(MessageSource templateEngineMessageSource) {
        this.templateEngineMessageSource = templateEngineMessageSource;
    }

    public void afterPropertiesSet() throws Exception {
        SpringMessageResolver springMessageResolver = new SpringMessageResolver();
        springMessageResolver.setMessageSource(this.templateEngineMessageSource == null ? this.messageSource : this.templateEngineMessageSource);
        super.setDefaultMessageResolvers(Collections.singleton(springMessageResolver));
    }

    protected final void initializeSpecific() {
        Configuration configuration = this.getConfiguration();
        Map<String, IDialect> dialects = configuration.getDialects();
        Iterator var3 = dialects.values().iterator();

        IDialect dialect;
        do {
            if (!var3.hasNext()) {
                throw new ConfigurationException("When using " + SpringTemplateEngine.class.getSimpleName() + ", at least one of the configured dialects must be or extend " + SpringStandardDialect.class.getName() + ".");
            }

            dialect = (IDialect)var3.next();
        } while(!(dialect instanceof SpringStandardDialect));

        this.initializeSpringSpecific();
    }

    protected void initializeSpringSpecific() {
    }
}

使用模板引擎

我用 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 作为构建工具创建了一个最小示例。


添加 Thymeleaf 依赖项

spring-boot-starter-thymeleaf 依赖项添加到您的项目。您使用的是 Maven 还是 Gradle?

专家

您的 pom.xml 依赖项应包括:

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

Gradle

您的 build.gradle 依赖项应包括:

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

在 Spring 引导中配置 Thymeleaf

添加所需的 @Bean。它们是:

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

他们可以进入任何用 @Configuration(或 @SpringBootApplication)注释的 class。


示例

现在,您可以从任何 class 访问您的 TemplateEngine,其字段由 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;
    }
}

mail.html 应位于 templates/ 下的 class 路径 (resources/)。

它应该是这样的:

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

您发布的代码片段现在看起来像这样(@Autowired SomeClass as someClass in the class outside 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();
}

当然,根据自己的需要更改示例!


编辑

您提到您需要填写模板 "with a list of some names"。这将是这样实现的:

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>

详细了解 data-th-each / th:each here。注意:您可以交替使用 data-th-th:,尽管 data-th- 更 HTML5 友好。