摘 要 :邮件群发是消息在Internet 传递的最好办法,同时也是垃圾邮件的来源。本文以使用JAVAMAIL 为例,讨论实现大规模邮件发送的方法和技巧。
关键字 :SMTP 、MIME 、JAVAMAIL 、群发邮件
一、引言
邮件群发是Internet 生活中最常见的一种信息传递方式,其传递信息的主动性、高效率和低费用而被众多商家广泛采用。我们的电子邮箱随之充满了各种类型的商业邮件,一般称这些商业邮件为垃圾邮件。本文笔者运用JAVA 语言开发了一个基于SMTP 服务器的邮件群发软件,在以下内容中将逐一介绍SMTP 协议,JAVAMAIL 包,以及邮件群发程序的片段等。
二、简单邮件传输协议与JAVAMAIL 类库
1 .简单邮件传输协议(SMTP )从1982 年起被用来在不同计算机系统间传递电子邮件。SMTP 使用简单的ASCII 码文本命令,命令定义长度为4 个字符。SMTP 基本命令集及功能如表一所示。
命令 |
功能 |
HELO |
从客户端打开问候信息 |
|
标识发件人 |
RCPT |
标识收件人 |
DATA |
标识邮件开始 |
SEND |
向终端发送邮件 |
SOML |
执行SEND 或MAIL 命令 |
SAML |
执行SEND 或MAIL 命令 |
RSET |
重置SMTP 连接 |
VRFY |
验证系统用户名 |
EXPN |
查询列表和别名 |
HELP |
查询命令列表 |
NOOP |
不操作 |
QUIT |
终止SMTP 连接 |
TURN |
变换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 ,有四个大类,如表二所示。
javax.mail |
邮件系统模型类 |
javax.mail.event |
Javamail API 监听和事件处理类 |
javax.mail.internet |
Internet 邮件系统类 |
javax.mail.search |
JavaMail API 邮件搜索类 |
表二
这些类操作分别属于 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(Message.RecipientType.CC,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 java.net.*;
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 + “,” + fileline;
}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);
}