Spring邮件抽象层的主要包为org.springframework.mail。它包括了发送电子邮件的主要接口MailSender,和值对象SimpleMailMessage,它封装了简单邮件的属性如from, to,cc, subject,text。 包里还包含一棵以MailException为根的checked Exception继承树,它们提供了对底层邮件系统异常的高级别抽象。 要获得关于邮件异常层次的更丰富的信息,请参考Javadocs。
为了使用JavaMail中的一些特色, 比如MIME类型的信件, Spring提供了MailSender的一个子接口, 即org.springframework.mail.javamail.JavaMailSender。Spring还提供了一个回调接口org.springframework.mail.javamail.MimeMessagePreparator, 用于准备JavaMail的MIME信件。
public interface MailSender { /** * Send the given simple mail message. * @param simpleMessage message to send * @throws MailException in case of message, authentication, or send errors */ public void send(SimpleMailMessage simpleMessage) throws MailException; /** * Send the given array of simple mail messages in batch. * @param simpleMessages messages to send * @throws MailException in case of message, authentication, or send errors */ public void send(SimpleMailMessage[] simpleMessages) throws MailException; }
public interface JavaMailSender extends MailSender { /** * Create a new JavaMail MimeMessage for the underlying JavaMail Session * of this sender. Needs to be called to create MimeMessage instances * that can be prepared by the client and passed to send(MimeMessage). * @return the new MimeMessage instance * @see #send(MimeMessage) * @see #send(MimeMessage[]) */ public MimeMessage createMimeMessage(); /** * Send the given JavaMail MIME message. * The message needs to have been created with createMimeMessage. * @param mimeMessage message to send * @throws MailException in case of message, authentication, or send errors * @see #createMimeMessage */ public void send(MimeMessage mimeMessage) throws MailException; /** * Send the given array of JavaMail MIME messages in batch. * The messages need to have been created with createMimeMessage. * @param mimeMessages messages to send * @throws MailException in case of message, authentication, or send errors * @see #createMimeMessage */ public void send(MimeMessage[] mimeMessages) throws MailException; /** * Send the JavaMail MIME message prepared by the given MimeMessagePreparator. * Alternative way to prepare MimeMessage instances, instead of createMimeMessage * and send(MimeMessage) calls. Takes care of proper exception conversion. * @param mimeMessagePreparator the preparator to use * @throws MailException in case of message, authentication, or send errors */ public void send(MimeMessagePreparator mimeMessagePreparator) throws MailException; /** * Send the JavaMail MIME messages prepared by the given MimeMessagePreparators. * Alternative way to prepare MimeMessage instances, instead of createMimeMessage * and send(MimeMessage[]) calls. Takes care of proper exception conversion. * @param mimeMessagePreparators the preparator to use * @throws MailException in case of message, authentication, or send errors */ public void send(MimeMessagePreparator[] mimeMessagePreparators) throws MailException; }
public interface MimeMessagePreparator { /** * Prepare the given new MimeMessage instance. * @param mimeMessage the message to prepare * @throws MessagingException passing any exceptions thrown by MimeMessage * methods through for automatic conversion to the MailException hierarchy */ void prepare(MimeMessage mimeMessage) throws MessagingException; }
假设某个业务接口名为 OrderManager:
public interface OrderManager { void placeOrder(Order order); }
同时有一个用例为:需要生成带有订单号的email信件, 并向客户发送该订单。 为此,我们会使用MailSender接口和SimpleMailMessage类。
请注意,通常情况下,我们在业务代码中使用接口而让Spring ioc容器负责组装我们需要的合作者。
以下是OrderManager的实现:
import org.springframework.mail.MailException; import org.springframework.mail.MailSender; import org.springframework.mail.SimpleMailMessage; public class OrderManagerImpl implements OrderManager { private MailSender mailSender; private SimpleMailMessage message; public void setMailSender(MailSender mailSender) { this.mailSender = mailSender; } public void setMessage(SimpleMailMessage message) { this.message = message; } public void placeOrder(Order order) { // Do the business calculations... // Call the collaborators to persist the order... //Create a thread safe "sandbox" of the message SimpleMailMessage msg = new SimpleMailMessage(this.message); msg.setTo(order.getCustomer().getEmailAddress()); msg.setText( "Dear " + order.getCustomer().getFirstName() + order.getCustomer().getLastName() + ", thank you for placing order. Your order number is " + order.getOrderNumber()); try{ mailSender.send(msg); } catch(MailException ex) { //log it and go on System.err.println(ex.getMessage()); } } }
上面的代码的bean定义应该是这样的:
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="host" value="mail.mycompany.com"/> </bean> <bean id="mailMessage" class="org.springframework.mail.SimpleMailMessage"> <property name="from" value="customerservice@mycompany.com"/> <property name="subject" value="Your order"/> </bean> <bean id="orderManager" class="com.mycompany.businessapp.support.OrderManagerImpl"> <property name="mailSender" ref="mailSender"/> <property name="message" ref="mailMessage"/> </bean>
下面是OrderManager接口的实现,使用了MimeMessagePreparator回调接口。 请注意这里的mailSender属性的类型为JavaMailSender,这样做是为了能够使用JavaMail的MimeMessage:
import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage; import org.springframework.mail.MailException; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessagePreparator; public class OrderManagerImpl implements OrderManager { private JavaMailSender mailSender; public void setMailSender(JavaMailSender mailSender) { this.mailSender = mailSender; } public void placeOrder(final Order order) { // Do the business calculations... // Call the collaborators to persist the order... MimeMessagePreparator preparator = new MimeMessagePreparator() { public void prepare(MimeMessage mimeMessage) throws MessagingException { mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(order.getCustomer().getEmailAddress())); mimeMessage.setFrom(new InternetAddress("mail@mycompany.com")); mimeMessage.setText( "Dear " + order.getCustomer().getFirstName() + order.getCustomer().getLastName() + ", thank you for placing order. Your order number is " + order.getOrderNumber()); } }; try { mailSender.send(preparator); } catch (MailException ex) { //log it and go on System.err.println(ex.getMessage()); } } }
如果你想获得JavaMail MimeMessage的全部能力,你可以使用MimeMessagePreparator。
Note | |
---|---|
以上的邮件代码是一个横切关注点,是重构为定制SpringAOP advice的完美候选者,这样就可以在目标对象OrderManager合适的joinpoint中运行。请参阅Chapter 6, 使用Spring进行面向切面编程(AOP)章节。 |
Spring直接提供两种MailSender的实现:标准的JavaMail实现,和基于Jason Hunter 编写的MailMessage类之上的实现,后者位于http://servlets.com/cos (com.oreilly.servlet)。进一步的资料请查阅相关Javadocs。
org.springframework.mail.javamail.MimeMessageHelper是处理JavaMail邮件常用的顺手组件之一。它可以让你摆脱繁复的javax.mail.internetAPI类。下面是一些通常的场景:
使用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);
Email允许添加附件,也允许在multipart信件中内嵌资源。内嵌资源可能是你在信件中希望使用的图像,或者样式表,但是又不想把它们作为附件。下面的例子演示如何使用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); // if you would need to include the file as an attachment, use // the various addAttachment() methods on the MimeMessageHelper sender.send(message);
Warning | |
---|---|
如你所见,嵌入式资源使用Content-ID(上例中是identifier1234)来插入到mime信件中去。你加入文本或者资源的顺序是非常重要的。首先,你加入文本,随后是资源。如果你弄反了顺序,它将无法正常运作! |