Spring封装的JavaMail配置及异常处理

spring-mail.properties(Spring的属性文件): 

mail.host=smtp.163.com
[email protected]
mail.password=123456
#非SSL端口号
mail.port=25
#SSL端口号
#mail.port=465
mail.encoding=UTF-8
mail.smtp.auth=true
mail.smtp.timeout=25000
[email protected];


spring-mail.xml(有关spring mail服务的Spring配置文件):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
            http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

	<!-- 扫描该包下的Bean -->
	<context:component-scan base-package="com.wenniuwuren.mail.service" />

	<!-- 邮件发送 -->
	<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
		<property name="host">
			<value>${mail.host}</value>
		</property>
		<property name="username">
			<value>${mail.username}</value>
		</property>
		<property name="password">
			<value>${mail.password}</value>
		</property>
		<property name="port">
			<value>${mail.port}</value>
		</property>
		<property name="defaultEncoding">
			<value>${mail.encoding}</value>
		</property>
		<property name="protocol">
			<value>smtp</value>
		</property>
		<property name="javaMailProperties">
			<props>
				<prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
				<!-- <prop key="mail.smtp.starttls.enable">true</prop> 取决于使用的邮件服务是否支持STARTTLS加密 -->
				<!-- <prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop> 取决于是否使用SSL端口发送邮件-->
				<prop key="mail.smtp.socketFactory.fallback">false</prop>
				<prop key="mail.smtp.timeout">${mail.smtp.timeout}</prop>
				<prop key="mail.sendTo">${mail.sendTo}</prop>
				<!-- <prop key="mail.debug">true</prop> 测试时开启-->
			</props>
		</property>
	</bean>

	<!-- 异步线程 -->
	<bean id="taskExecutor"
		class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
		<property name="corePoolSize" value="10" />
		<property name="maxPoolSize" value="30" />
	</bean>

</beans>
配置完上面的, 记得在容器能扫描到的配置文件里加上:

 <!-- 扫描邮件服务 -->
<import resource="classpath:META-INF/spring-mail.xml"/>
或者直接把上面的spring-mail.xml直接写在容器能扫描到的配置文件里, 但是会导致单个配置文件太长。


MailService接口:

public interface MailService {

	/**
	 * 邮件发送统一入口
	 * @param email
	 * 
	 */
	public abstract void sendMail(Email email) throws Exception;

	/**
	 * 异步发送
	 */
	public abstract void sendMailByAsynchronousMode(final Email email) throws Exception;

	/**
	 * 同步发送
	 */
	public abstract void sendMailBySynchronizationMode(Email email) throws Exception;
	
	/**
	 * 邮件发送
	 * @param subject
	 * @param content
	 */
	public void sendMail(String subject, String content) throws Exception;

}



MailService接口实现类: MailServiceImpl

import java.util.Properties;
import javax.annotation.Resource;
import javax.mail.internet.MimeMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.task.TaskExecutor;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;


@Service("mailService")
public class MailServiceImpl implements MailService{

	@Resource
	JavaMailSender mailSender;// 注入
	@Resource
	TaskExecutor taskExecutor;
    
	Logger logger = LoggerFactory.getLogger(MailServiceImpl.class);
    
	// 判断同步或者异步发送
	@Override
	public void sendMail(Email email) throws Exception {
		
		JavaMailSenderImpl senderImpl = (JavaMailSenderImpl)mailSender;
		Properties mailProperties = senderImpl.getJavaMailProperties();
		//获取接收人信息
		String sendTo = mailProperties.getProperty("mail.sendTo");
		email.setAddress(sendTo);
		
		if (email.getAddress() == null || email.getAddressArray().length == 0) {
			throw new ServiceException("缺少收件人地址");
		}
		if (email.getAddressArray().length > 5) {// 收件地址大于5时,异步发送
			sendMailByAsynchronousMode(email);
		} else {
			try {
				sendMailBySynchronizationMode(email);
			} catch (Exception e) {
				throw new Exception(e);
			}
		}
	}

	// 实现异步只需把同步发送放到Concurrent里面执行
	@Override
	public void sendMailByAsynchronousMode(final Email email) throws Exception {
		taskExecutor.execute(new Runnable() {
			public void run() {
				try {
					sendMailBySynchronizationMode(email);
				} catch (Exception e) {
				  throw new Exception(e);
				}
			}
		});
	}

	// 同步发送邮件
	@Override
	public void sendMailBySynchronizationMode(Email email)
			throws Exception {
		try{
			JavaMailSenderImpl senderImpl = (JavaMailSenderImpl)mailSender;
		
			MimeMessage mime = mailSender.createMimeMessage();
			MimeMessageHelper helper = new MimeMessageHelper(mime, false, "utf-8");
			helper.setFrom(senderImpl.getUsername());// 发件人
			helper.setTo(email.getAddressArray());// 收件人
			
			if (email.getCc() != null && email.getCc().trim().length() > 0) {
				String cc[] = email.getCc().split(";");
				helper.setCc(cc);// 抄送
			}
			helper.setSubject(email.getSubject());// 邮件主题
			helper.setText(email.getContent(), true);// true表示设定html格式
	
			mailSender.send(mime);
		}catch(Exception e){
			throw new Exception(e);
		}
	}
	
	// 发送邮件 入口方法
	public void sendMail(String subject, String content) throws Exception {
		try {
			Email mail = new Email();
			mail.setSubject(subject);
			mail.setContent(content);
			sendMail(mail);

		} catch (Exception e) {
            throw new Exception(e);
		}
	}

}


Model层的JavaBean: Email

import java.io.Serializable;

public class Email implements Serializable{

	private static final long serialVersionUID = -1;

	/** 收件人 **/
	private String address;

	/** 抄送给 **/
	private String cc;

	/** 邮件主题 **/
	private String subject;

	/** 邮件内容 **/
	private String content;

	// ////////////////////////解析邮件地址//////////////////////////////

	public String[] getAddressArray() {
		if (this.address == null || this.address.trim().length()==0) {
			return null;
		}
		address = address.trim();
		address.replaceAll(";", ";");
		address.replaceAll(" ", ";");
		address.replaceAll(",", ";");
		address.replaceAll(",", ";");
		address.replaceAll("|", ";");
		return address.split(";");
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getCc() {
		return cc;
	}

	public void setCc(String cc) {
		this.cc = cc;
	}

	public String getSubject() {
		return subject;
	}

	public void setSubject(String subject) {
		this.subject = subject;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

}
	


剩下最后一步就是调用了, 看各自业务的需求, 以下代码是在程序发生异常时发邮件通知负责人:

@Resource
private MailService mailService; // 注入
try{
    
    // 业务逻辑
	
	}catch(Exception e){
			
			//发送邮件
			mailService.sendMail("邮件主题", "邮件内容");
		
	}


编码过程遇到的问题:
1. 错误:javax.mail.AuthenticationFailedException: 错误码(400 ~ 599) 

   这是最经常看到的, 原因可能有:

      -- 用户名密码错误
      -- 防火墙或杀毒软件屏蔽SMTP协议

      -- 邮箱本身没有开启SMTP/POP协议支持(默认都是关闭的)


2. 错误:Could not send email: Could not convert socket to TLS

 原因: 所使用的邮件服务器不支持通过STARTTLS keyword 的TLS加密 

  解决办法: 注释掉这个配置<prop key="mail.smtp.starttls.enable">true</prop>, 参照上文

3. 错误: javax.mail.MessagingException: Could not connect to SMTP host: smtp.163.com, port: 465, response: -1

       原因:使用了SSL端口465但是却配置却没使用SSL的配置       

      解决办法: 配置<prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>

                    参照上文, 把注释去掉就行了。


4. 其他服务器可以发送, 但是个别邮件服务器就算开启了SMTP协议支持也不行(如现在的QQ邮箱)

    解决办法: 暂无(不知道广大博友怎么搞定)... 友情提示:先别试QQ邮箱, 试网易的136会省掉很多找bug的时间。  



本文参考资料:

                          博客: 利用Spring框架封装的JavaMail实现同步或异步邮件发送

                          Wikipedia: STARTTLS

                          SVNForum: Thread: Could not send email: Could not convert socket to TLS

你可能感兴趣的:(spring,socket,javamail,smtp)