22.3. 使用MimeMessageHelper

org.springframework.mail.javamail.MimeMessageHelper是处理JavaMail邮件时比较顺手组件之一。它可以让你摆脱繁复的JavaMail API。 通过使用MimeMessageHelper,创建一个MimeMessage实例将非常容易:

// of course you would use DI in any real-world cases
JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");

MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
helper.setTo("test@host.com");
helper.setText("Thank you for ordering!");

sender.send(message);

22.3.1. 发送附件和嵌入式资源(inline resources)

Multipart email允许添加附件和内嵌资源(inline resources)。内嵌资源可能是你在信件中希望使用的图像或样式表,但是又不想把它们作为附件。

22.3.1.1. 附件

下面的例子将展示如何使用MimeMessageHelper来发送一封email,使用一个简单的JPEG图片作为附件:

JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");

MimeMessage message = sender.createMimeMessage();

// use the true flag to indicate you need a multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("test@host.com");

helper.setText("Check out this image!");

// let's attach the infamous windows Sample file (this time copied to c:/)
FileSystemResource file = new FileSystemResource(new File("c:/Sample.jpg"));
helper.addAttachment("CoolImage.jpg", file);

sender.send(message);

22.3.1.2. 内嵌资源

下面的例子将展示如何使用MimeMessageHelper来发送一封含有内嵌资源的email:

JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");

MimeMessage message = sender.createMimeMessage();

// use the true flag to indicate you need a multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("test@host.com");

// use the true flag to indicate the text included is HTML
helper.setText("<html><body><img src='cid:identifier1234'></body></html>", true);

// let's include the infamous windows Sample file (this time copied to c:/)
FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg"));
helper.addInline("identifier1234", res);

sender.send(message);

警告

如你所见,嵌入式资源使用Content-ID(上例中是identifier1234)来插入到mime信件中去。你加入文本和资源的顺序是非常重要的。首先,你加入文本,随后是资源。如果顺序弄反了,它将无法正常运作!

22.3.2. 使用模板来创建邮件内容

在之前的代码示例中,所有邮件的内容都是显式定义的,并通过调用message.setText(..)来设置邮件内容。 这种做法针对简单的情况或在上述的例子中没什么问题,因为在这里只是为了向你展示基础API。

而在你自己的企业级应用程序中, 基于如下的原因,你不会以上述方式创建你的邮件内容:

  • 使用Java代码来创建基于HTML的邮件内容不仅容易犯错,同时也是一件单调乏味的事情

  • 这样做,你将无法将显示逻辑和业务逻辑很明确的区分开

  • 一旦需要修改邮件内容的显式格式和内容,你需要重新编写Java代码,重新编译,重新部署……

一般来说解决这些问题的典型的方式是使用FreeMarker或者Velocity这样的模板语言来定义邮件内容的显式结构。 这样,你的任务就是在你的代码中,只要创建在邮件模板中需要展示的数据,并发送邮件即可。通过使用Spring对FreeMarker和Velocity的支持类, 你的邮件内容将变得简单,这同时也是一个最佳实践。下面是一个使用Velocity来创建邮件内容的例子:

22.3.2.1. 一个基于Velocity的示例

使用Velocity来创建你的邮件模板,你需要把Velocity加入到classpath中。 同时要根据应用的需要为邮件内容创建一个或者多个Velocity模板。下面的Velocity模板是这个例子中所使用的基于HTML的模板。 这只是一个普通的文本,你可以通过各种其他的编辑器来编辑该文本,而无需了解Java方面的知识。

# in the com/foo/package
<html>
<body>
<h3>Hi ${user.userName}, welcome to the Chipping Sodbury On-the-Hill message boards!</h3>

<div>
   Your email address is <a href="mailto:${user.emailAddress}">${user.emailAddress}</a>.
</div>
</body>

</html>

下面提供了一些简单的代码与Spring XML配置,它们使用了上述Velocity模板来创建邮件内容并发送邮件。

package com.foo;

import org.apache.velocity.app.VelocityEngine;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.ui.velocity.VelocityEngineUtils;

import javax.mail.internet.MimeMessage;
import java.util.HashMap;
import java.util.Map;

public class SimpleRegistrationService implements RegistrationService {

   private JavaMailSender mailSender;
   private VelocityEngine velocityEngine;

   public void setMailSender(JavaMailSender mailSender) {
      this.mailSender = mailSender;
   }

   public void setVelocityEngine(VelocityEngine velocityEngine) {
      this.velocityEngine = velocityEngine;
   }

   public void register(User user) {

      // Do the registration logic...

      sendConfirmationEmail(user);
   }

   private void sendConfirmationEmail(final User user) {
      MimeMessagePreparator preparator = new MimeMessagePreparator() {
         public void prepare(MimeMessage mimeMessage) throws Exception {
            MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
            message.setTo(user.getEmailAddress());
            message.setFrom("webmaster@csonth.gov.uk"); // could be parameterized...
            Map model = new HashMap();
            model.put("user", user);
            String text = VelocityEngineUtils.mergeTemplateIntoString(
               velocityEngine, "com/dns/registration-confirmation.vm", model);
            message.setText(text, true);
         }
      };
      this.mailSender.send(preparator);
   }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

   <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
      <property name="host" value="mail.csonth.gov.uk"/>
   </bean>

   <bean id="registrationService" class="com.foo.SimpleRegistrationService">
      <property name="mailSender" ref="mailSender"/>
      <property name="velocityEngine" ref="velocityEngine"/>
   </bean>
   
   <bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
      <property name="velocityProperties">
         <value>
            resource.loader=class
            class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
         </value>
      </property>
   </bean>

</beans>