33. 电子邮件

33.1 简介


Library dependencies

以下JAR需要位于应用程序的类路径中才能使用Spring Framework的电子邮件库。

这个库可以在网上免费获得 - 例如,在Maven Central中作为 com.sun.mail:javax.mail


Spring Framework提供了一个有用的实用程序库,用于发送电子邮件,保护用户免受底层邮件系统的细节影响,并负责代表客户端进行低级资源处理。

org.springframework.mail 包是Spring Framework电子邮件支持的根级包。发送电子邮件的中央界面是 MailSender 界面;一个简单的值对象封装了一个简单邮件的属性,例如from和to(以及许多其他的)是 SimpleMailMessage 类。此程序包还包含已检查异常的层次结构,这些异常对较低级别的邮件系统异常提供更高级别的抽象,并且根异常为 MailException 。有关富邮件异常层次结构的更多信息,请参阅javadocs。

org.springframework.mail.javamail.JavaMailSender 接口向 MailSender 接口(从中继承)添加了专门的JavaMail功能,例如MIME消息支持。 JavaMailSender 还提供了一个回调接口,用于准备一个名为 org.springframework.mail.javamail.MimeMessagePreparator 的'MimeMessage'。

33.2 用法

我们假设有一个名为 OrderManager 的业务接口:

public interface OrderManager {

    void placeOrder(Order order);

}

我们还假设需要说明需要生成带有订单号的电子邮件消息并将其发送给放置相关订单的客户。

33.2.1 基本MailSender和SimpleMailMessage用法

import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;

public class SimpleOrderManager implements OrderManager {

    private MailSender mailSender;
    private SimpleMailMessage templateMessage;

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

    public void setTemplateMessage(SimpleMailMessage templateMessage) {
        this.templateMessage = templateMessage;
    }

    public void placeOrder(Order order) {

        // Do the business calculations...

        // Call the collaborators to persist the order...

        // Create a thread safe "copy" of the template message and customize it
        SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
        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{
            this.mailSender.send(msg);
        }
        catch (MailException ex) {
            // simply 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>

<!-- this is a template message that we can pre-load with default state -->
<bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage">
    <property name="from" value="[email protected]"/>
    <property name="subject" value="Your order"/>
</bean>

<bean id="orderManager" class="com.mycompany.businessapp.support.SimpleOrderManager">
    <property name="mailSender" ref="mailSender"/>
    <property name="templateMessage" ref="templateMessage"/>
</bean>

33.2.2 使用JavaMailSender和MimeMessagePreparator

这是使用 MimeMessagePreparator 回调接口的 OrderManager 的另一个实现。请注意,在这种情况下 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 SimpleOrderManager 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 Exception {
                mimeMessage.setRecipient(Message.RecipientType.TO,
                        new InternetAddress(order.getCustomer().getEmailAddress()));
                mimeMessage.setFrom(new InternetAddress("[email protected]"));
                mimeMessage.setText("Dear " + order.getCustomer().getFirstName() + " " +
                        order.getCustomer().getLastName() + ", thanks for your order. " +
                        "Your order number is " + order.getOrderNumber() + ".");
            }
        };

        try {
            this.mailSender.send(preparator);
        }
        catch (MailException ex) {
            // simply log it and go on...
            System.err.println(ex.getMessage());
        }
    }

}

邮件代码是一个横切关注点,很可能是重构为自定义Spring AOP方面的候选者,然后可以在OrderManager目标上的适当连接点执行。

Spring Framework的邮件支持附带标准的JavaMail实现。有关更多信息,请参阅相关的javadoc。

33.3 使用JavaMail MimeMessageHelper

在处理JavaMail消息时非常方便的类是 org.springframework.mail.javamail.MimeMessageHelper 类,它使您不必使用详细的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("[email protected]");
helper.setText("Thank you for ordering!");

sender.send(message);

33.3.1 发送附件和内联资源

多部分电子邮件消息允许附件和内联资源。内联资源的示例可能是您要在邮件中使用的图像或样式表,但您不希望将其显示为附件。

附件

以下示例显示如何使用 MimeMessageHelper 发送电子邮件以及单个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("[email protected]");

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

内联资源

以下示例说明如何使用 MimeMessageHelper 发送电子邮件和内嵌图像。

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("[email protected]");

// 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(上例中的标识符1234)将内联资源添加到MimeMessage。添加文本和资源的顺序非常重要。一定要先添加文本,然后再添加资源。如果你这样做,反过来,它将无法正常工作!

33.3.2 使用模板库创建电子邮件内容

前面示例中的代码使用方法调用(例如 message.setText(..) )显式创建了电子邮件消息的内容。这对于简单的情况很好,并且在上述示例的上下文中是可以的,其目的是向您展示API的基础知识。

但是,在典型的企业应用程序中,出于多种原因,您不会使用上述方法创建电子邮件内容。

  • 使用Java代码创建基于HTML的电子邮件内容非常繁琐且容易出错

  • 显示逻辑和业务逻辑之间没有明确的区别

  • 更改电子邮件内容的显示结构需要编写Java代码,重新编译,重新部署...

通常,解决这些问题的方法是使用模板库,如FreeMarker或Velocity定义电子邮件内容的显示结构。这使您的代码仅负责创建要在电子邮件模板中呈现的数据并发送电子邮件。当您的电子邮件内容变得相当复杂时,这绝对是一种最佳实践,而Spring Framework的FreeMarker和Velocity支持类变得非常容易。下面是使用Velocity模板库创建电子邮件内容的示例。

基于速度的示例

要使用 Velocity 创建电子邮件模板,您需要在类路径中使用Velocity库。您还需要为应用程序所需的电子邮件内容创建一个或多个Velocity模板。在下面找到此示例将使用的Velocity模板。正如您所看到的那样,它是基于HTML的,因为它是纯文本,所以可以使用您喜欢的HTML或文本编辑器创建它。

# 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("[email protected]"); // 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.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>
Updated at: 5 months ago
32.5. 交易Table of content34. 任务执行和调度
Comment
You are not logged in.

There are no comments.