邮件发送文档
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
利用Spring框架封装的JavaMail现实同步或异步
邮件发送
作者:张纪豪
J2EE简单地讲是在JDK上扩展了各类应用的标准规范,邮件处理便是其中一个重要的应用。
它既然是规范,那么我们就可以通过JDK遵照邮件协议编写一个邮件处理系统,但事实上已经有很多厂商和开源组织这样做了。
Apache 是J2EE最积极的实现者之一,当然还有我们的老大——SUN。
聊起老大,感慨万端!他已经加入Oracle——甲骨文(不是刻在乌龟壳上的那种文字吗?是我中华,也是人类上最早的语言啊,比Java早几千年哦),其掌门人拉里·埃里森是个不错的水手,别以为那只是在帆船上,至少他不至于盖茨那么不仁道——开源万岁。
有理由相信Java世界还有一段辉煌的历程。
Google 的Android和Chrome OS两大操作系统,还会首选Java作应用开发基础语言,即便是推出自己的易语言。
同时笔者预感到ChromeOS前景不可估量,它可能是推动云计算一个重要组成部分,Andtroid(主用在移动设备上,未来可能是手机上主流的操作系统),乃至微软的Windows将来可能都是该系统的小窗口而已。
微软已显得老态龙钟了,再与大势已去的雅虎合作,前进步伐必将大大减缓。
投资者此时可以长线买入Google股票(投资建议,必自判断)。
笔者也常用google搜索引擎、gmail。
好了,闲话少聊,言归主题。
可能大家如笔者一样用的最多的是老大的javamail,虽然老大实现了邮件功能,但调用起来还是需要较复杂的代码来完成,而且初学者调用成功率很低(因为它还要与外界服务器通信),这就使得初学者对于它越学越迷茫。
不过这
方面的例子很多,因此笔者不再在此重复这些示例代码,而着重利用Spring 框架封装的邮件处理功能。
开工之前,我们先了解下环境。
笔者开的是web工程,所需要的基础配置如下:
▲ JDK 1.6
▲ J2EE 1.5
▲ JavaMail 1.4 稍作说明:J2EE 1.5中已经纳入了邮件规范,因此在开发期不要导入javamail中的jar包,运行期则需要,因此可以将jar包放入到web容器的java库中(例如Tomcat的lib目录下),要了解其意可以参考数据库驱动包的运用。
文章结尾会对其进一步说明;
▲ Spring 2.5
▲ 一个邮箱如上所述,笔者爱用Google的Gmail邮箱。
主要文件清单:
■ MailService.java 邮件处理对象接口
■ MailServiceImpl.java上述实现
■ Email.java一个普通的JavaBean,用于封装邮件数据,并与html页面中form表单对应
■ MailController.java动作处理器
■ spring-core-config.xml Spring核心配置
笔者的web工程中,WEB层使用的是Spring @MVC,当然我们仅需要了解其原理,利用servlet或struts框架来做web层动作处理器都能实现。
其它的文件,例如web.xml,WEB层配置均略。
下面开始代码:
spring-core-config.xml:
<!--①邮件服务器-->
这是邮件处理的两个核心配置,第一个配置(①)是往容器中装配一个JavaMailSender Bean,它就是JavaMail的封装,其中最关键的是装配过程的属性参数,这些属性既要严格遵照JavaMail规范,又要满足邮件提供商的要求,例如SMTP服务器端口是多少、发送时是否要身份验证、服务器是否采用安全连接、连接时是否加密以及采用什么样的加密方式,邮件服务商提供的这些参数直接影响到上述的配置,这往往是新手最容易忽视的环节,因此配置之前一定要到邮件提供商的站点上详细了解邮箱的技术参数。
同步异步发送问题:JavaMail邮件处理是同步的,即用户触发事件、与SMTP Server 通信、服务器返回状态消息、程序结束是单线程内,这时往往因Socket通信、服务器业务处理速度等原因而使得处理时间是个未知数。
举个简单的应用实例:若用户在提交注册的同时发送一封激活账户邮件,用户有可能不知道是因为邮件服务器那儿阻塞致半天没有反应而以为注册失败并放弃,这将是失败的设计,但异步方式能解决这些问题。
异步方式简单地说就是将邮件处理任务交给另外一个线程,J2EE有两种解决方案,一是种利用JMS,JMS 可以实现同步和异步的消息处理,将邮件作为一个异步的消息,就可以实现异步邮件发送。
JMS属于J2EE的高级应用,所以对于仅以WEB功能的容器还不支持这种服务,例如Tomcat(当然可以找到插件来解决),由于篇幅限制,本文不再牵涉到新的模块。
另一种方案是利用JDK中Executor的支持,JDK 5.0后继版本增加了java.util.concurrent 一个强大的并发工具包,它包含了执行器、计时器、锁、线程安全队列、线程任务框架等等。
Executor——执行器,它可以将任务的“提交”与“执行”分离解耦,我们的邮件处理任务完全可以借用它实现异步执行。
而Spring框架提供了封装,见②。
下面我们来看如何使用它,代码如下。
MailServiceImpl.java :
此类实现了MailService接口,该接口仅三个方法(接口文件代码省略):一个发送分流器、一个同步发送方法、一个异步发送方法。
通过其实现者MailServiceImpl的代码可以看出,邮件发送仅在同步发送这个方法中,当需要异步执行的时候,只需要将其扔进taskExecutor异步执行器中,就这么简单。
这三个方法都是public修饰的,所以在上层随意调用哪个都行。
以下看一个简单的调用代码。
调用之前,为让初学者能更好地接受,先列出Email.java代码:
Email.java:
这个类就是一个简单的JavaBean,用于封装邮件数据,对于习惯使用Struts框架的读者,完全可以把它理解为一个ActionForm。
但对于MultipartFile类型且是数组的attachment属性可能较难理解,熟悉Struts框架的可以看作是FormFile,在Struts2中可能好理解些。
笔者使用的是Spring MVC,框架中内置了这种属性编辑器,因此很容易地将form表单上传的文件进行转换成这个字段。
我们来看看WEB层调用,其实到此为止,就已经完成本文的主题了,因此WEB怎么调用都是围绕MailService中的三个方法,为便有全面的认识,将代码列出,不过最好需要了解Spring @MVC的一些知识。
MailController.java:
当一个get方法请求的连接进来,此控制器会转向一个html页面,其页面中有form 表单,表单中的字段与Email.java对应,当post方法过来后,Spring MVC会把表单中的数据填充到Email对象中,交给MailService处理就ok了。
最后讲述下最容易出现的错误:
网上很多人都说J2EE5兼容性不好,例如典型的javamail1.4中包与J2EE5中包接口包引起冲突,导致单元测试经常报如下错误:
ng.NoClassDefFoundError:
com/sun/mail/util/BEncoderStream
当然这个错误是没有将javamail的实现者引进工程(没有导包),但导包后,就会出现另外一个错误:
ng.NoClassDefFoundError:
com/sun/mail/util/LineInputStream
此时甚至web容器都无法启动,经常会有网友们为这两个异常搞得焦头烂额,如此更换J2EE1.4,会对工程造成影响。
但是一定要把概念弄清楚,问题就好解决。
J2EE5中mail.jar包定义的只是接口,没有实现,是不能真正发送邮件的,但开发编译肯定是可以过去的,因为我们是针对J2EE规范编的程序。
而运行期用Sun公司的JavaMail1.4的实现才可以开始发送邮件,但老大为什么把这两个弄冲突了?
笔者的解决办法是:
开发期不要导包,运行期将javamail1.4压缩文件中的mail.jar包放入到tomcat\lib目录下,这样完全可以通过开发和运行。
若要做单元测试则新开一个Java Project,注意,不是web工程,此时可以将javamail1.4压缩包中的mail.jar放入到工程的classpath下。
如果有疑问或建议请MSN至jihao_zh@,共同探讨。
文本原创,转载请注明出处。
摘要:邮件群发是消息在Internet传递的最好办法,同时也是垃圾邮件的来
源。
本文以使用JAVAMAIL为例,讨论实现大规模邮件发送的方法
和技巧。
关键字:SMTP、MIME、JAVAMAIL、群发邮件
一、引言
邮件群发是Internet生活中最常见的一种信息传递方式,其传递信息的主
动性、高效率和低费用而被众多商家广泛采用。
我们的电子邮箱随之充满了各
种类型的商业邮件,一般称这些商业邮件为垃圾邮件。
本文笔者运用JAVA语
言开发了一个基于SMTP服务器的邮件群发软件,在以下内容中将逐一介绍SMTP协议,JAVAMAIL包,以及邮件群发程序的片段等。
二、简单邮件传输协议与JAVAMAIL类库
1.简单邮件传输协议(SMTP)从1982年起被用来在不同计算机系统间传递电子邮件。
SMTP使用简单的ASCII码文本命令,命令定义长度为4个字符。
SMTP基本命令集及功能如表一所示。
表一
绝大多数SMTP系统采用一种标准的邮件报文格式,即RFC822来“规范”邮件的形式。
RFC822明确的划分邮件为两个部分,一部分称为邮件头,起其作用是标识邮件;第二部分是邮件体。
邮件头中包括:
1)Received:用来标识将邮件从最初发送者到目的地进行中间转发的SMTP服务器,其中含有发信人及发信服务器真实的信息。
2)Return-path:用来标识邮件发送到目的服务器所经过的路径。
3)From:显示发信人的地址。
格式为From:user-name。
4)Date:记录邮件发送时间。
5)Destination:记录收邮件地址, 标识电子邮件的接受方地址,这些地址是纯粹地信息,SMTP仅通过RCPT命令发送信件。
包括To主收件人,Cc
抄送收件人,Bcc暗抄送收件人,格式为To/Cc/Bcc:address。
6)Resent:表示一封邮件处于某中原因需要从客户端再次发送。
2.JAVAMAIL关于邮件操作最新包是JavaMail1.2,有四个大类,如表二所示。
表二
这些类操作分别属于mailapi.jar(文件包含核心API类),smtp.jar (实现SMTP协议功能),pop3.jar(实现POP3协议功能),imap.jar(包含IMAP协议功能)等四个文件。
同时这四个文件都被包含在mail.jar中,如过图省事的话,直接包含mail.jar即可。
如果要实现带附件的邮件收发功能,还需要包含activation.jar,它提供通过二进制数据流的形式处理MIME类型的访问。
三、程序举例
1.首先是连接SMTP服务器,JAVAMAIL1.2不能实现SMTP服务的功能,但可以连接已有的SMTP服务器。
//创建一个属性对象
Properties props=System.getProperties(); //创建系统属性对象
props.setProperty("mail.transport.protocol","smtp"); //设置使用smtp协议
props.setProperty("mail.smtp.host",server); //设置SMTP服务器地址
props.setProperty("mail.smtp.port",""+port); //设置SMTP端口号 props.setProperty("mail.smtp.auth","true"); //SMTP服务用户认
证
//创建一个过程对象
javax.mail.Session sess =
javax.mail.Session.getDefaultInstance(props, null);
2.创建一封新邮件,一般定义该MimeMessage创建一个邮件对象。
MimeMessage msg=new MimeMessage(sess); //创建邮件对象
msg.setSubject(“邮件群发”); //设置邮件主题
msg.setSentDate(new Date()); //设置发信日期
msg.setFrom(Address address); //设置发信人邮件地址只要符合带有“@”符号并且使用“.”分成三段的字符串都会被SMTP服务器接受,发送广告邮件的商家一般都会在这里修改发信人地址,所以我们的收件箱中看见的广告邮件显示中发信人内容一些的根本不存在邮件地址。
如果想查看真正地发信人,应该查看邮件头中Received的内容。
//设置主收件人
msg.setRecipients(Message.RecipientType.TO,Address
toaddress);
//设置抄送收件人
msg.addRecipients(,Address
coaddress);
//设置暗抄送人
msg.addRecipients(Message.RecipientType.BCC,Address
bcoaddress);
SMTP允许一封邮件有多个接受者,我们可以利用这个特点,在这三个收件人中填写多个收件人地址来提高大规模发邮件效率。
另外Bcc这个字段可以隐藏收件人的地址,你有时可能发现邮件的收件人不是自己却收到了这封邮件,就是利用了暗抄这个属性。
3.邮件体一般分为邮件正文本部分和附件部分。
正文部分需要设置文本的格式,包括text文本类型,messafe报文类型,image图象类型,video视频
类型,audio声音类型,application应用程序类型,multipart混合类型等。
如下例,
String m_body; //为需要添加文本内容
MimeMultipart content=new MimeMultipart(); //创建邮件体对象
if(content==null) return false;
MimeBodyPart part=new MimeBodyPart(); //创建文本部分对象
String type="text/plain"; //文本类型默认为
text/plain
if(m_body.startsWith("<html>") ||
m_body.startsWith("<HTML>"))
type="text/html"; //如果是网页形式的内容,则改变类型为text/html
part.setText(m_body);
part.setHeader("Content-Type",type);
content.addBodyPart(part);
msg.setContent(content); //添加文本至邮件中msg.saveChanges(); //保存修改
4.如何向的邮件中添加附件,利用多用途互联网邮件扩展(MIME)协议可以直接二进制数据添加到标准的RFC822邮件中。
在JAVAMAIL中实现方法如下,
String filename; //用于存储文件名称与存放路径
if(filename!=null || filename.length()>0){
MimeBodyPart part=new MimeBodyPart();//创建MIME对象 DataSource fds = new FileDataSource(filename); //创建文件流对象
part.setDataHandler(new DataHandler(fds));
part.setFileName(MimeUtility.encodeText(fds.getName()));
content.addBodyPart(part); //添加二进制编码至邮件体中 }
msg.setContent(content); //添加文本至邮件中msg.saveChanges(); //保存修改
5.邮件的基本内容设置完毕,发送SMTP电子邮件。
Transport trans=sess.getTransport(); //创建发送对象
trans.send (msg); //发送
6.如何群发邮件,首先我们要有一个邮件地址列表,邮件地址列表可以向从公共网站获得,也可以根据某单位名称按字典法生成,或者购买用户表。
邮件地址列表应该按行存放每个邮件地址。
发信的速度和SMTP的响应速度有密切的关系,所以因该充分利用一封邮件可以有多个接受地址的条件,将邮件地址按组读入进行发送,才能提高邮件群发地效率。
下面的例子是每一封信发给10个邮件地址。
import java.io.*;
import .*;
import java.util.*;
import javax.mail.*;
import javax.activation.*;
import javax.mail.internet.*;
class massmail(){
try{
FileReader fis = new FileReader(“邮件列表文件”);
BufferedReader dis = new BufferedReader(fis);
int i=0;
while((fileline = dis.readLine())!=null){
if((i%10)==0)
MimeMessage msg=new MimeMessage(sess);
……
if((i%10)!=0){ //多个邮件地址之间要加“,”
maillist = maillist + “,” + fil eline;
}else{
maillist = fileline;
}
i++;
if((i%10)==0){ //一封邮件在暗抄地址处加10个收件人
msg.addRecipients(Message.RecipientType.BCC, maillist);
…… //设置邮件内容
Transport trans=sess.getTransport(); //创建发送对象
trans.send (msg); //发送
}
}
fis.close();
}catch(Exception error){
System.out.println("Exception:" + error);
}。