今天把之前写的使用JavaMail异步发送邮件的demo程序贴出来。
最近一段时间,发现新浪微博手机客户端也开始支持异步发送信息了。不管是发微博,还是评论微博,点击过“发送”按钮之后,马上会被告知“已经进入发送队列”,我觉得这明显增加了用户体验,并且这个提升也不存在任何技术困难。这样一种情况,比如我发一个带图的微博消息,在不使用wifi的情况下,上传一个稍大些的图片可能会耗费不少时间。假如微博客户端不支持异步发送,也许就因为图片的上传,这个客户端得卡上好半天,直到上传完成为止。这种完全阻塞的方式,对用户来说可不是种好的体验。
发送邮件的时候同样存在着类似上面的情况。整个邮件的发送过程是比较耗时的,假如使用普通的单线程串行处理方式,当并发量大时,必然带来灾难性的后果。在下面的例子中,我使用多线程的方式来解决这个问题,使得邮件支持异步发送。
要支持新浪微博的异步发送,可以使用多线程方式,也可以使用消息服务。我本身对于JMS的方式不太了解,因此选择了一种相对熟悉和容易实现的方式,即每个邮件发送请求都作为一个线程任务,由线程池中的线程来处理每一个邮件发送任务。
首先,介绍邮件的JavaBean对象Mail。很简单,无需赘言。
package org.tang.financial.domain;
import java.util.List;
public class Mail {
/**
* 发送人
*/
private String sender;
/**
* 收件人
*/
private List<String> recipientsTo;
/**
* 抄送人
*/
private List<String> recipientsCc;
/**
* 密送人
*/
private List<String> recipientsBcc;
/**
* 主题
*/
private String subject;
/**
* 正文
*/
private String body;
/**
* 附件列表
*/
private List<String> attachments;
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public List<String> getRecipientsTo() {
return recipientsTo;
}
public void setRecipientsTo(List<String> recipientsTo) {
this.recipientsTo = recipientsTo;
}
public List<String> getRecipientsCc() {
return recipientsCc;
}
public void setRecipientsCc(List<String> recipientsCc) {
this.recipientsCc = recipientsCc;
}
public List<String> getRecipientsBcc() {
return recipientsBcc;
}
public void setRecipientsBcc(List<String> recipientsBcc) {
this.recipientsBcc = recipientsBcc;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public List<String> getAttachments() {
return attachments;
}
public void setAttachments(List<String> attachments) {
this.attachments = attachments;
}
}
其次,是邮件发送程序当中需要用到的常量。各个常量的含义都已经有说明,也无需赘言。
package org.tang.financial.mail;
public abstract class MailProperties {
/**
* SMTP服务器
*/
public static final String MAIL_SMTP_HOST = "mail.smtp.host";
/**
* SMTP服务器端口号
*/
public static final String MAIL_SMTP_PORT = "mail.smtp.port";
/**
* 登录SMTP服务器是否需要通过授权。可选值为true和false
*/
public static final String MAIL_SMTP_AUTH = "mail.smtp.auth";
/**
* 登录SMTP服务器默认邮箱账号
*/
public static final String MAIL_SMTP_USER = "mail.smtp.user";
/**
* 登录SMTP服务器默认邮箱账号对应密码
*/
public static final String MAIL_SMTP_PASSWORD = "mail.smtp.password";
/**
* 是否打开程序调试。可选值包括true和false
*/
public static final String MAIL_DEBUG = "mail.debug";
}
接着,是邮件发送程序需要使用到得properties属性配置文件。各个键值的含义参考上面的说明。
mail.smtp.host = smtp.example.com
mail.smtp.port = 25
mail.smtp.auth = true
mail.smtp.user = username@example.com
mail.smtp.password = password
mail.debug = true
最后,邮件发送的处理程序。
package org.tang.financial.service;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import org.tang.financial.domain.Mail;
import org.tang.financial.mail.MailProperties;
import org.tang.financial.util.CollectionUtils;
import org.tang.financial.util.StringUtils;
@Component
public class MailService {
private static Log logger = LogFactory.getLog(MailService.class);
private static final String MAIL_PROPERTIE_NAME = "JavaMail.properties";
private static Properties mailPro = new Properties();
private static Executor executor = Executors.newFixedThreadPool(10);
static {
//初始化,读取属性文件的过程
InputStream in = null;
try {
in = MailService.class.getResourceAsStream(MAIL_PROPERTIE_NAME);
mailPro.load(in);
} catch (IOException e) {
if (logger.isErrorEnabled()) {
logger.error(e);
}
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
if (logger.isErrorEnabled()) {
logger.error(e);
}
}
}
}
}
public boolean sendMail(final Mail mail) {
if(mail == null){
return false;
}
//创建邮件发送任务
Runnable task = new Runnable() {
@Override
public void run() {
final String username = mailPro.getProperty(MailProperties.MAIL_SMTP_USER);
final String password = mailPro.getProperty(MailProperties.MAIL_SMTP_PASSWORD);
//创建发送邮件的会话
Session session = Session.getDefaultInstance(mailPro, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
try {
//创建邮件消息
MimeMessage msg = new MimeMessage(session);
//设置邮件发送人
msg.setFrom(new InternetAddress(StringUtils.isEmpty(mail
.getSender()) ? mailPro
.getProperty(MailProperties.MAIL_SMTP_USER) : mail
.getSender()));
//分别设置邮件的收件人、抄送人和密送人
msg.setRecipients(Message.RecipientType.TO, strListToInternetAddresses(mail.getRecipientsTo()));
msg.setRecipients(Message.RecipientType.CC, strListToInternetAddresses(mail.getRecipientsCc()));
msg.setRecipients(Message.RecipientType.BCC, strListToInternetAddresses(mail.getRecipientsBcc()));
//设置邮件主题
msg.setSubject(mail.getSubject());
Multipart mp = new MimeMultipart();
//创建邮件主体内容
MimeBodyPart mbp1 = new MimeBodyPart();
mbp1.setText(mail.getBody());
mp.addBodyPart(mbp1);
if(!CollectionUtils.isEmpty(mail.getAttachments())){
//循环添加邮件附件
MimeBodyPart attach = null;
for(String path : mail.getAttachments()){
attach = new MimeBodyPart();
try {
attach.attachFile(path);
mp.addBodyPart(attach);
} catch (IOException e) {
if (logger.isErrorEnabled()) {
logger.error(e);
}
}
}
}
msg.setContent(mp);
msg.setSentDate(new Date());
//邮件开始发送
Transport.send(msg);
} catch (AddressException e) {
if (logger.isErrorEnabled()) {
logger.error(e);
}
} catch (MessagingException e) {
if (logger.isErrorEnabled()) {
logger.error(e);
}
}
}
};
//使用Executor框架的线程池执行邮件发送任务
executor.execute(task);
return true;
}
/**
* 将列表中的字符串转换成InternetAddress对象
* @param list 邮件字符串地址列表
* @return InternetAddress对象数组
*/
private InternetAddress[] strListToInternetAddresses(List<String> list) {
if (list == null || list.isEmpty()) {
return null;
}
int size = list.size();
InternetAddress[] arr = new InternetAddress[size];
for (int i = 0; i < size; i++) {
try {
arr[i] = new InternetAddress(list.get(i));
} catch (AddressException e) {
e.printStackTrace();
}
}
return arr;
}
}
分享到:
相关推荐
spring里配置javamail支持ftl模板,支持异步发送最大支持1000份,可以带多份附件
①主要功能模块: 开发此系统的需求源于:加盟... 里面用到的技能点有,JavaBean,Jsp/Servlet,JDBC,javaMail实现邮件发送, Ajax实现异步提交,用SmartUpload组件上传 图片。 注意:只能用于学习,不可做其他用途
> 注册成功时,使用javaMail给注册用户发送激活邮件,邮件中包含用于激活的链接,链接包含激活码参数; * 用户激活:通过激活码查询用户,如果查询不到用户,那么无效激活码!激活码使用uuid生成! * 用户登录: ...
> 注册成功时,使用javaMail给注册用户发送激活邮件,邮件中包含用于激活的链接,链接包含激活码参数; * 用户激活:通过激活码查询用户,如果查询不到用户,那么无效激活码!激活码使用uuid生成! * 用户登录: ...
发送邮寄是异步的,代码如下: package com.email.demo.async; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.spring...
> 注册成功时,使用javaMail给注册用户发送激活邮件,邮件中包含用于激活的链接,链接包含激活码参数; * 用户激活:通过激活码查询用户,如果查询不到用户,那么无效激活码!激活码使用uuid生成! * 用户登录: > ...
> 注册成功时,使用javaMail给注册用户发送激活邮件,邮件中包含用于激活的链接,链接包含激活码参数; 用户激活:通过激活码查询用户,如果查询不到用户,那么无效激活码!激活码使用uuid生成! > 登录成功时会把...
15.3.2 编写发送邮件的实例 223 15.3.3 编写接收邮件的实例 235 15.4 小结 241 第16章 基于良好设计模式的Spring 243 16.1 Spring简介 243 16.2 实例——用Spring来打招呼 246 16.3 小结 248 第17章 ...
使用JPA访问数据库 第12章 整合其他ORM框架 第4篇 业务层应用 第13章 任务调度和异步执行器 第14章 JavaMail发送邮件 第15章 在Spring中使用JMS 第16章 在Spring中开发Web Service 第17章 使用...
使用JPA访问数据库 第12章 整合其他ORM框架 第4篇 业务层应用 第13章 任务调度和异步执行器 第14章 JavaMail发送邮件 第15章 在Spring中使用JMS 第16章 在Spring中开发Web Service 第17章 使用...
使用JPA访问数据库 第12章 整合其他ORM框架 第4篇 业务层应用 第13章 任务调度和异步执行器 第14章 JavaMail发送邮件 第15章 在Spring中使用JMS 第16章 在Spring中开发Web Service 第17章 使用...
7.2.3 使用JavaMail发送邮件 277 7.2.4 使用JavaMail接收邮件 281 7.3 应用服务器的JavaMail支持 287 7.3.1 在WebLogic中配置JavaMail 288 7.3.2 通过WebLogic的邮件支持来 发送邮件 290 7.3.3 在JBoss中配置...
│ 08-用户分页查询-异步请求方式-代码开发 │ 09-用户分页查询-条件查询 │ 10-模糊查询-注意事项 │ 11-附录1.JS中局部变量和全局变量区别 │ d( L, Z2 p" ] ├─众筹项目-第05天《Atcrowdfunding》) A% ]3 K. N. ...
18.1.3、发送普通邮件 18.1.4、发送带附件的HTML风格邮件 18.2、操作Excel文件 18.2.1、JExcelAPI简介 18.2.2、创建一个Excel文件 18.2.3、读取Excel文件 18.2.4、格式化文本 18.3、本章摘要 附录B:...
18.1.3、发送普通邮件 18.1.4、发送带附件的HTML风格邮件 18.2、操作Excel文件 18.2.1、JExcelAPI简介 18.2.2、创建一个Excel文件 18.2.3、读取Excel文件 18.2.4、格式化文本 18.3、本章摘要 附录B:...
18.1.3、发送普通邮件 18.1.4、发送带附件的HTML风格邮件 18.2、操作Excel文件 18.2.1、JExcelAPI简介 18.2.2、创建一个Excel文件 18.2.3、读取Excel文件 18.2.4、格式化文本 18.3、本章摘要 附录B:...
18.1.3、发送普通邮件 18.1.4、发送带附件的HTML风格邮件 18.2、操作Excel文件 18.2.1、JExcelAPI简介 18.2.2、创建一个Excel文件 18.2.3、读取Excel文件 18.2.4、格式化文本 18.3、本章摘要 附录B:...
18.1.3、发送普通邮件 18.1.4、发送带附件的HTML风格邮件 18.2、操作Excel文件 18.2.1、JExcelAPI简介 18.2.2、创建一个Excel文件 18.2.3、读取Excel文件 18.2.4、格式化文本 18.3、本章摘要 附录B:...
18.1.3、发送普通邮件 18.1.4、发送带附件的HTML风格邮件 18.2、操作Excel文件 18.2.1、JExcelAPI简介 18.2.2、创建一个Excel文件 18.2.3、读取Excel文件 18.2.4、格式化文本 18.3、本章摘要 附录B:...
18.1.3、发送普通邮件 18.1.4、发送带附件的HTML风格邮件 18.2、操作Excel文件 18.2.1、JExcelAPI简介 18.2.2、创建一个Excel文件 18.2.3、读取Excel文件 18.2.4、格式化文本 18.3、本章摘要 附录B:...