外贸软件市场中,神卓外贸管理软件肯定是一款优秀的外贸业务流程管理软件,用户数众多,最牛的功能是邮件群发功能,今天要说的是邮件群发,常规的企业邮件一天中一般发送不会超过70封邮件,多了就有可能会被退信,更不用说是要发营销邮件了,而市面上有一些是第三方代发邮件的,这样的业务效果都不好,最好的效果当然是要用自己的邮箱发邮件啦,如果要实现大批量发送不会被退信,是不是很反理论?其实没有那么神秘,
仔细分析一下神卓的实现功能,界面如下

首先功能上是主题支持多个主题,可设置邮件回复的地址和阅读跟踪功能,话不多说,直接上代码:
1:使用的技术是JDK 1.9+MYSQL+Redis
当前版本:javamail1_4_4.zip 可以去oracle去下载最新的版本
发复杂的邮件,html内容,包括带附件的,邮件内容嵌入图片的邮件
首先,要导入的包有:
dsn.jar
mailapi.jar
smtp.jar
本demo只演示后台Javamail的发送核心过程代码,就不写前台界面了。
demo1:演示简单的纯文本邮件的发送
import java.io.ObjectInputStream.GetField;
import java.util.Date;
import java.util.Properties;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.swing.text.html.MinimalHTMLWriter;
public class SendMailText {
//发件人地址
public static String senderAddress = "xxx@163.com";
//收件人地址
public static String recipientAddress = "xxx@qq.com";
//发件人账户名
public static String senderAccount = "xxx";
//发件人账户密码
public static String senderPassword = "xxx";
public static void main(String[] args) throws Exception {
//1、连接邮件服务器的参数配置
Properties props = new Properties();
//设置用户的认证方式
props.setProperty("mail.smtp.auth", "true");
//设置传输协议
props.setProperty("mail.transport.protocol", "smtp");
//设置发件人的SMTP服务器地址
props.setProperty("mail.smtp.host", "smtp.163.com");
//2、创建定义整个应用程序所需的环境信息的 Session 对象
Session session = Session.getInstance(props);
//设置调试信息在控制台打印出来
session.setDebug(true);
//3、创建邮件的实例对象
Message msg = getMimeMessage(session);
//4、根据session对象获取邮件传输对象Transport
Transport transport = session.getTransport();
//设置发件人的账户名和密码
transport.connect(senderAccount, senderPassword);
//发送邮件,并发送到所有收件人地址,message.getAllRecipients() 获取到的是在创建邮件对象时添加的所有收件人, 抄送人, 密送人
transport.sendMessage(msg,msg.getAllRecipients());
//如果只想发送给指定的人,可以如下写法
//transport.sendMessage(msg, new Address[]{new InternetAddress("xxx@qq.com")});
//5、关闭邮件连接
transport.close();
}
/**
* 获得创建一封邮件的实例对象
* @param session
* @return
* @throws MessagingException
* @throws AddressException
*/
public static MimeMessage getMimeMessage(Session session) throws Exception{
//创建一封邮件的实例对象
MimeMessage msg = new MimeMessage(session);
//设置发件人地址
msg.setFrom(new InternetAddress(senderAddress));
/**
* 设置收件人地址(可以增加多个收件人、抄送、密送),即下面这一行代码书写多行
* MimeMessage.RecipientType.TO:发送
* MimeMessage.RecipientType.CC:抄送
* MimeMessage.RecipientType.BCC:密送
*/
msg.setRecipient(MimeMessage.RecipientType.TO,new InternetAddress(recipientAddress));
//设置邮件主题
msg.setSubject("邮件主题","UTF-8");
//设置邮件正文
msg.setContent("简单的纯文本邮件!", "text/html;charset=UTF-8");
//设置邮件的发送时间,默认立即发送
msg.setSentDate(new Date());
return msg;
}
}
要说的注意点都在上文中的注释中了,如果不懂得可以给我留言,我一定回复。
注意:大家自己在运行时请将收件人,发件人等信息更改成自己的。
执行完上述代码,就可以收到邮件了,(在收件箱里查看)
中途会遇到的问题:
①、发件人的邮箱账户名和密码:有的邮箱设置了独立密码,还有的必须用授权码登录(qq邮箱或者163个别邮箱都会有)
邮件客户端的主要任务是向邮件服务器发送邮件,以及接收来自邮件服务器的邮件。
Sun公司制定了一套API,它封装了邮件通信的各种协议。为Java开发者提供了收发电子邮件的公共接口。
需要的jar包
mail.jar和activation-1.1.0.jar
Javax.mail.Session:
Session -用于设置服务器,协议类型和密码等
表示会话,是JavaMailApi的最高层入口类。Session对像从Properties中获取信息,如IP、协议、用户名密码等。
Javax.mail.Message类,它的一个重要子类为MimeMessage.
Message类表示电子邮件的正文部分。
一封电子邮件包含以下内容:
地址信息、标题、日期、正文。
Java.mail.Address:收件人地址
表示邮件的地址。常用的子类为:javax.mail.internet.InternetAddress.
Javax.mail.Transport:负责发送邮件
指定邮件发送的协议。通常为SMTP.
它的静态方法send(Message)负责发送邮件。
MailSSLSocketFactory-负责SSL加密(如果有邮箱是用ssl加密传输的,就需要用到这个类,否则不需要-以前的老版本jar包中没有此类)
好了,发送纯文本邮件没有问题了,相信阅读的人都能看懂并收获不少。其实编程这件事情,很多时候就是你听起来一个功能的实现好像很难,但当你着手去实现,去研究他的实现过程的时候就会发现其实也没有想象中那么难。接下来给大家介绍一下如何实现复杂邮件的传输。
跟上面章一样涉及到2个步骤:1.创建一封复杂邮件;2.发送复杂邮件。第2步发送邮件的过程和上一篇一模一样,这边就不多介绍了,详情可见上一篇文章。这边重点说一下第1步创建复杂文件的实现,主要可以分为:①创建图片节点;②创建文本节点;③文本和图片节点结合;④创建附件节点;⑤将(文本+图片)节点和附件节点结合;⑥将整个混合节点添加到邮件内容中,并保存邮件设置。
接下来直接上代码,代码中都有详细的注释,如果有不清楚或者实现不了的可以自行百度,或者评论进行讨论交流哦~~~!
public MimeMessage createComplicatedMessage(Session session,String sendMail,String[] receiveMail,String subject,String msgContent) throws Exception{
MimeMessage message =new MimeMessage(session);
message.setFrom(new InternetAddress(sendMail,"发件人昵称","UTF-8"));
Address[] addr = new Address[receiveMail.length];
for(int i=0;i<addr.length;i++){
addr[i] = new InternetAddress(receiveMail[i], "收件人昵称", "UTF-8");
}
message.addRecipients(RecipientType.TO, addr);
message.setSubject(subject);
/*
* 邮件内容的创建:图片和附件
*/
//创建图片节点
MimeBodyPart image = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("bgicon.jpg")); //读取本地文件
image.setDataHandler(dh); //将数据添加到节点
image.setContentID("image_id");// 为“节点”设置一个唯一编号(在文本“节点”将引用该ID)
//创建文本节点
MimeBodyPart text = new MimeBodyPart();
//将图片包含到文本内容中
text.setContent("这是一张图片<br/><img src='cid:image_id'/>", "text/html;charset=UTF-8");
//将文本和图片节点结合
MimeMultipart text_image = new MimeMultipart();
text_image.addBodyPart(text);
text_image.addBodyPart(image);
text_image.setSubType("related"); //关联关系 有内嵌资源要定义related
//将混合节点封装成普通节点BodyPart,邮件最终由多个BodyPart组成
MimeBodyPart text_image_body = new MimeBodyPart();
text_image_body.setContent(text_image);
//添加附件节点
MimeBodyPart document = new MimeBodyPart();
DataHandler dhdoc = new DataHandler(new FileDataSource("d:\\123.doc")); //读取本地文档
document.setDataHandler(dhdoc); //将附件数据添加到节点
document.setFileName(MimeUtility.decodeText(dhdoc.getName())); //设置附件文件名
//设置文本和图片,附件的关系(混合大节点)
MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(text_image_body);
mm.addBodyPart(document);
mm.setSubType("mixed"); //有附件资源要定义mixed
//最终节点添加到邮件中
message.setContent(mm);
message.setSentDate(new Date());
message.saveChanges();
return message;
}
@Test//发送没有附件的邮件
public void send1() throws Exception{
//跟smtp服务器建立一个连接
Properties p = new Properties();
// 设置邮件服务器主机名
p.setProperty("mail.host", "smtp.qq.com");//指定邮件服务器,默认端口 25
// 发送服务器需要身份验证
p.setProperty("mail.smtp.auth", "true");//要采用指定用户名密码的方式去认证
// 发送邮件协议名称
p.setProperty("mail.transport.protocol", "smtp");
// 开启SSL加密,否则会失败
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
p.put("mail.smtp.ssl.enable", "true");
p.put("mail.smtp.ssl.socketFactory", sf);
// 开启debug调试,以便在控制台查看
//session.setDebug(true);也可以这样设置
//p.setProperty("mail.debug", "true");
// 创建session
Session session = Session.getDefaultInstance(p, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
//用户名可以用QQ账号也可以用邮箱的别名
PasswordAuthentication pa = new PasswordAuthentication("your username", "your password");
// 后面的字符是授权码,用qq密码不行!!
return pa;
}
});
session.setDebug(true);//设置打开调试状态
for (int i = 0; i <1; i++) {//发送几封邮件
//声明一个Message对象(代表一封邮件),从session中创建
MimeMessage msg = new MimeMessage(session);
//邮件信息封装
//1发件人
msg.setFrom(new InternetAddress("*****@qq.com"));
//2收件人
msg.setRecipient(RecipientType.TO, new InternetAddress(
"******@126.com"));
//3邮件内容:主题、内容
msg.setSubject("这是我用Java发来的邮件QQ....");
//msg.setContent("Hello, 今天没下雨!!!", "text/plain;charset=utf-8");//纯文本
msg.setContent(
"Hello <a href='http://www.baidu.com?id=ddd'>你好,快乐吗?<a/>",
"text/html;charset=utf-8");//发html格式的文本
//发送动作
Transport.send(msg);
}
}
注意以上代码在国内云服务器上发送不了的,原因是国内25端口被封掉了,不过是有办法解决的
public class sendqqMail {
public static void main(String[] args) throws Exception {
Properties prop = new Properties();
// 开启debug调试,以便在控制台查看
prop.setProperty("mail.debug", "true");
// 设置邮件服务器主机名
prop.setProperty("mail.host", "smtp.qq.com");
// 发送服务器需要身份验证
prop.setProperty("mail.smtp.auth", "true");
// 发送邮件协议名称
prop.setProperty("mail.transport.protocol", "smtp");
// 开启SSL加密,否则会失败
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", sf);
// 创建session
Session session = Session.getInstance(prop);
// 通过session得到transport对象
Transport ts = session.getTransport();
// 连接邮件服务器:邮箱类型,帐号,授权码代替密码(更安全)
ts.connect("smtp.qq.com", "#####@qq.com", "肯定是你的邮箱授权码了");
// 后面的字符是授权码,用qq密码失败了
// 创建邮件
Message message = createSimpleMail(session);
// 发送邮件
ts.sendMessage(message, message.getAllRecipients());
ts.close();
}
/**
* @Method: createSimpleMail
* @Description: 创建一封只包含文本的邮件
*/
public static MimeMessage createSimpleMail(Session session)
throws Exception {
// 创建邮件对象
MimeMessage message = new MimeMessage(session);
// 指明邮件的发件人
message.setFrom(new InternetAddress("这里填写收件人邮箱地址"));
// 指明邮件的收件人
message.setRecipient(Message.RecipientType.TO, new InternetAddress(
"*****@126.com"));
// 邮件的标题
message.setSubject("QQ邮件测试");//
// 邮件的文本内容
message.setContent("发送邮件成功!", "text/html;charset=UTF-8");
// 返回创建好的邮件对象
return message;
}
}
注意:正式发送
相对于没带附件的:用MimeBodyPart来构建体,向体中添加内容,附件。最后利用MimeMultipart —addBodyPart(body); 把体加入。
@Test//发送含附件的邮件
public void send2() throws Exception{
//跟smtp服务器建立一个连接
Properties p = new Properties();
// 开启debug调试,以便在控制台查看
p.setProperty("mail.debug", "true");
p.setProperty("mail.host", "smtp.sina.com");//指定邮件服务器,默认端口 25
p.setProperty("mail.smtp.auth", "true");//要采用指定用户名密码的方式去认证
// 发送邮件协议名称
p.setProperty("mail.transport.protocol", "smtp");
// 开启SSL加密,否则会失败
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
p.put("mail.smtp.ssl.enable", "true");
p.put("mail.smtp.ssl.socketFactory", sf);
// 创建session
Session session = Session.getInstance(p);
// 通过session得到transport对象
Transport ts = session.getTransport();
// 连接邮件服务器:邮箱类型,帐号,授权码代替密码(更安全)
ts.connect("smtp.qq.com", "61*****29", "jnjt*******bdab");
// 后面的字符是授权码,不能用qq密码
//声明一个Message对象(代表一封邮件),从session中创建
MimeMessage msg = new MimeMessage(session);
//邮件信息封装
//1发件人
msg.setFrom( new InternetAddress("61******29@qq.com") );
//2收件人
msg.setRecipient(RecipientType.TO, new InternetAddress("ch*****ox@126.com") );
//3邮件内容:主题、内容
msg.setSubject("这是我用Java发来的邮件--带附件的....");
//添加附件部分
//邮件内容部分1---文本内容
MimeBodyPart body0 = new MimeBodyPart(); //邮件中的文字部分
body0.setContent("这是两张<font color='red'>图片</font>....","text/html;charset=utf-8");
//邮件内容部分2---附件1
MimeBodyPart body1 = new MimeBodyPart(); //附件1
body1.setDataHandler( new DataHandler( new FileDataSource("./imgs/1.jpg")) );//./代表项目根目录下
body1.setFileName( MimeUtility.encodeText("中文1.jpg") );//中文附件名,解决乱码
//邮件内容部分3---附件2
MimeBodyPart body2 = new MimeBodyPart(); //附件2
body2.setDataHandler( new DataHandler( new FileDataSource("./imgs/2.jpg")) );
body2.setFileName("2.jpg");
//把上面的3部分组装在一起,设置到msg中
MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(body0);
mm.addBodyPart(body1);
mm.addBodyPart(body2);
msg.setContent(mm);
// 发送邮件
ts.sendMessage(msg,msg.getAllRecipients());
ts.close();
}
一、JavaMail API简介
JavaMail API是读取、撰写、发送电子信息的可选包。我们可用它来建立如Eudora、Foxmail、MS Outlook Express一般的邮件用户代理程序(Mail User Agent,简称MUA)。而不是像sendmail或者其它的邮件传输代理(Mail Transfer Agent,简称MTA)程序那样可以传送、递送、转发邮件。从另外一个角度来看,我们这些电子邮件用户日常用MUA程序来读写邮件,而MUA依赖着MTA处理邮件的递送。
在清楚了到MUA与MTA之间的关系后,让我们看看JavaMail API是如何提供信息访问功能的吧!JavaMail API被设计用于以不依赖协议的方式去发送和接收电子信息,这个API被分为两大部分:
基本功能:如何以不依赖于协议的方式发送接收电子信息,这也是本文所要描述的,不过在下文中,大家将看到这只是一厢情愿而已。
第二个部分则是依赖特定协议的,比如SMTP、POP、IMAP、NNTP协议。在这部分的JavaMail API是为了和服务器通讯,并不在本文的内容中。
二、相关协议一览
在我们步入JavaMail API之前,先看一下API所涉及的协议。以下便是大家日常所知、所乐于使用的4大信息传输协议:
SMTP
POP
IMAP
MIME
当然,上面的4个协议,并不是全部,还有NNTP和其它一些协议可用于传输信息,但是由于不常用到,所以本文便不提及了。理解这4个基本的协议有助于我们更好的使用JavaMail API。然而JavaMail API是被设计为与协议无关的,目前我们并不能克服这些协议的束缚。确切的说,如果我们使用的功能并不被我们选择的协议支持,那么JavaMail API并不可能如魔术师一样神奇的赋予我们这种能力。
1.SMTP
简单邮件传输协议定义了递送邮件的机制。在下文中,我们将使用基于Java-Mail的程序与公司或者ISP的SMTP服务器进行通讯。这个SMTP服务器将邮件转发到接收者的SMTP服务器,直至最后被接收者通过POP或者IMAP协议获取。这并不需要SMTP服务器使用支持授权的邮件转发,但是却的确要注意SMTP服务器的正确设置(SMTP服务器的设置与JavaMail API无关)。
2.POP
POP是一种邮局协议,目前为第3个版本,即众所周知的POP3。POP定义了一种用户如何获得邮件的机制。它规定了每个用户使用一个单独的邮箱。大多数人在使用POP时所熟悉的功能并非都被支持,例如查看邮箱中的新邮件数量。而这个功能是微软的Outlook内建的,那么就说明微软Outlook之类的邮件客户端软件是通过查询最近收到的邮件来计算新邮件的数量来实现前面所说的功能。因此在我们使用JavaMail API时需要注意,当需要获得如前面所讲的新邮件数量之类的信息时,我们不得不自己进行计算。
3.IMAP
IMAP使用在接收信息的高级协议,目前版本为第4版,所以也被称为IMAP4。需要注意的是在使用IMAP时,邮件服务器必须支持该协议。从这个方面讲,我们并不能完全使用IMAP来替代POP,不能期待IMAP在任何地方都被支持。假如邮件服务器支持IMAP,那么我们的邮件程序将能够具有以下被IMAP所支持的特性:每个用户在服务器上可具有多个目录,这些目录能在多个用户之间共享。
其与POP相比高级之处显而易见,但是在尝试采取IMAP时,我们认识到它并不是十分完美的:由于IMAP需要从其它服务器上接收新信息,将这些信息递送给用户,维护每个用户的多个目录,这都为邮件服务器带来了高负载。并且IMAP与POP的一个不同之处是POP用户在接收邮件时将从邮件服务器上下载邮件,而IMAP允许用户直接访问邮件目录,所以在邮件服务器进行备份作业时,由于每个长期使用此邮件系统的用户所用的邮件目录会占有很大的空间,这将直接导致邮件服务器上磁盘空间暴涨。
4.MIME
MIME并不是用于传送邮件的协议,它作为多用途邮件的扩展定义了邮件内容的格式:信息格式、附件格式等等。一些RFC标准都涉及了MIME:RFC 822, RFC 2045, RFC 2046, RFC 2047,有兴趣的Matrixer可以阅读一下。而作为JavaMail API的开发者,我们并不需关心这些格式定义,但是这些格式被用在了程序中。
5.NNTP和其它的第三方协议
正因为JavaMail API在设计时考虑到与第三方协议实现提供商之间的分离,故我们可以很容易的添加一些第三方协议。SUN维护着一个第三方协议实现提供商的列表:http://java.sun.com/products/javamail/Third_Party.html,通过此列表我们可以找到所需要的而又不被SUN提供支持的第三方协议:比如NNTP这个新闻组协议和S/MIME这个安全的MIME协议。
三、安装
1.安装JavaMail
为了使用JavaMail API,需要从http://java.sun.com/products/javamail/downloads/index.html下载文件名格式为javamail-[version].zip的文件(这个文件中包括了JavaMail实现),并将其中的mail.jar文件添加到CLASSPATH中。这个实现提供了对SMTP、IMAP4、POP3的支持。
注意:在安装JavaMail实现之后,我们将在demo目录中发现许多有趣的简单实例程序。
在安装了JavaMail之后,我们还需要安装JavaBeans Activation Framework,因为这个框架是JavaMail API所需要的。如果我们使用J2EE的话,那么我们并无需单独下载JavaMail,因为它存在于J2EE.jar中,只需将J2EE.jar加入到CLASSPATH即可。
2.安装JavaBeans Activation Framework
从http://java.sun.com/products/javabeans/glasgow/jaf.html下载JavaBeans Activation Framework,并将其添加到CLASSPATH中。此框架增加了对任何数据块的分类、以及对它们的处理的特性。这些特性是JavaMail API需要的。虽然听起来这些特性非常模糊,但是它对于我们的JavaMail API来说只是提供了基本的MIME类型支持。
到此为止,我们应当把mail.jar和activation.jar都添加到了CLASSPATH中。
当然如果从方便的角度讲,直接把这两个Jar文件复制到JRE目录的lib/ext目录中也可以。
四、初次认识JavaMail API
1.了解我们的JavaMail环境
A.纵览JavaMail核心类结构
打开JavaMail.jar文件,我们将发现在javax.mail的包下面存在着一些核心类:Session、Message、Address、Authenticator、Transport、Store、Folder。而且在javax.mail.internet包中还有一些常用的子类。
B.Session
Session类定义了基本的邮件会话。就像Http会话那样,我们进行收发邮件的工作都是基于这个会话的。Session对象利用了java.util.Properties对象获得了邮件服务器、用户名、密码信息和整个应用程序都要使用到的共享信息。
Session类的构造方法是私有的,所以我们可以使用Session类提供的getDefaultInstance()这个静态工厂方法获得一个默认的Session对象:
Properties props = new Properties();
// fill props with any information
Session session = Session.getDefaultInstance(props, null);
或者使用getInstance()这个静态工厂方法获得自定义的Session:
Properties props = new Properties();
// fill props with any information
Session session = Session.getInstance(props, null);
从上面的两个例子中不难发现,getDefaultInstance()和getInstance()方法的第二个参数都是null,这是因为在上面的例子中并没有使用到邮件授权,下文中将对授权进行详细介绍。
从很多的实例看,在对mail server进行访问的过程中使用共享的Session是足够的,即使是工作在多个用户邮箱的模式下也不例外。
C.Message
当我们建立了Session对象后,便可以被发送的构造信息体了。在这里SUN提供了Message类型来帮助开发者完成这项工作。由于Message是一个抽象类,大多数情况下,我们使用javax.mail.internet.MimeMessage这个子类,该类是使用MIME类型、MIME信息头的邮箱信息。信息头只能使用US-ASCII字符,而非ASCII字符将通过编码转换为ASCII的方式使用。
为了建立一个MimeMessage对象,我们必须将Session对象作为MimeMessage构造方法的参数传入:
MimeMessage message = new MimeMessage(session);
注意:对于MimeMessage类来讲存在着多种构造方法,比如使用输入流作为参数的构造方法。
在建立了MimeMessage对象后,我们需要设置它的各个part,对于MimeMessage类来说,这些part就是MimePart接口。最基本的设置信息内容的方法就是通过表示信息内容和米么类型的参数调用setContent()方法:
message.setContent("Hello", "text/plain");
然而,如果我们所使用的MimeMessage中信息内容是文本的话,我们便可以直接使用setText()方法来方便的设置文本内容。
message.setText("Hello");
前面所讲的两种方法,对于文本信息,后者更为合适。而对于其它的一些信息类型,比如HTML信息,则要使用前者。
别忘记了,使用setSubject()方法对邮件设置邮件主题:
message.setSubject("First");
D.Address
到这里,我们已经建立了Session和Message,下面将介绍如何使用邮件地址类:Address。像Message一样,Address类也是一个抽象类,所以我们将使用javax.mail.internet.InternetAddress这个子类。
通过传入代表邮件地址的字符串,我们可以建立一个邮件地址类:
Address address = new InternetAddress("president@whitehouse.gov");
如果要在邮件地址后面增加名字的话,可以通过传递两个参数:代表邮件地址和名字的字符串来建立一个具有邮件地址和名字的邮件地址类:
Address address = new InternetAddress("president@whitehouse.gov", "George Bush");
本文在这里所讲的邮件地址类是为了设置邮件信息的发信人和收信人而准备的,在建立了邮件地址类后,我们通过message的setFrom()和setReplyTo()两种方法设置邮件的发信人:
message.setFrom(address);
message.setReplyTo(address);
若在邮件中存在多个发信人地址,我们可用addForm()方法增加发信人:
Address address[] = ...;
message.addFrom(address);
为了设置收信人,我们使用addRecipient()方法增加收信人,此方法需要使用Message.RecipientType的常量来区分收信人的类型:
message.addRecipient(type, address)
下面是Message.RecipientType的三个常量:
Message.RecipientType.TO
Message.RecipientType.CC
Message.RecipientType.BCC
因此,如果我们要发送邮件给总统,并发用一个副本给第一夫人的话,下面的方法将被用到:
Address toAddress = new InternetAddress("vice.president@whitehouse.gov");
Address ccAddress = new InternetAddress("first.lady@whitehouse.gov");
message.addRecipient(Message.RecipientType.TO, toAddress);
message.addRecipient(Message.RecipientType.CC, ccAddress);
JavaMail API并没有提供检查邮件地址有效性的机制。当然我们可以自己完成这个功能:验证邮件地址的字符是否按照RFC822规定的格式书写或者通过DNS服务器上的MX记录验证等。
E.Authenticator
像java.net类那样,JavaMail API通过使用授权者类(Authenticator)以用户名、密码的方式访问那些受到保护的资源,在这里“资源”就是指邮件服务器。在javax.mail包中可以找到这个JavaMail的授权者类(Authenticator)。
在使用Authenticator这个抽象类时,我们必须采用继承该抽象类的方式,并且该继承类必须具有返回PasswordAuthentication对象(用于存储认证时要用到的用户名、密码)getPasswordAuthentication()方法。并且要在Session中进行注册,使Session能够了解在认证时该使用哪个类。
下面代码片断中的MyAuthenticator就是一个Authenticator的子类。
Properties props = new Properties();
// fill props with any information
Authenticator auth = new MyAuthenticator();
Session session = Session.getDefaultInstance(props, auth);
F.Transport
在发送信息时,Transport类将被用到。这个类实现了发送信息的协议(通称为SMTP),此类是一个抽象类,我们可以使用这个类的静态方法send()来发送消息:
Transport.send(message);
当然,方法是多样的。我们也可由Session获得相应协议对应的Transport实例。并通过传递用户名、密码、邮件服务器主机名等参数建立与邮件服务器的连接,并使用sendMessage()方法将信息发送,最后关闭连接:
message.saveChanges(); // implicit with send()
Transport transport = session.getTransport("smtp");
transport.connect(host, username, password);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
评论:上面的方法是一个很好的方法,尤其是在我们在同一个邮件服务器上发送多个邮件时。因为这时我们将在连接邮件服务器后连续发送邮件,然后再关闭掉连接。send()这个基本的方法是在每次调用时进行与邮件服务器的连接的,对于在同一个邮件服务器上发送多个邮件来讲可谓低效的方式。
注意:如果需要在发送邮件过程中监控mail命令的话,可以在发送前设置debug标志:
session.setDebug(true)
G.Store和Folder
接收邮件和发送邮件很类似都要用到Session。但是在获得Session后,我们需要从Session中获取特定类型的Store,然后连接到Store,这里的Store代表了存储邮件的邮件服务器。在连接Store的过程中,极有可能需要用到用户名、密码或者Authenticator。
// Store store = session.getStore("imap");
Store store = session.getStore("pop3");
store.connect(host, username, password);
在连接到Store后,一个Folder对象即目录对象将通过Store的getFolder()方法被返回,我们可从这个Folder中读取邮件信息:
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
Message message[] = folder.getMessages();
上面的例子首先从Store中获得INBOX这个Folder(对于POP3协议只有一个名为INBOX的Folder有效),然后以只读(Folder.READ_ONLY)的方式打开Folder,最后调用Folder的getMessages()方法得到目录中所有Message的数组。
注意:对于POP3协议只有一个名为INBOX的Folder有效,而对于IMAP协议,我们可以访问多个Folder(想想前面讲的IMAP协议)。而且SUN在设计Folder的getMessages()方法时采取了很智能的方式:首先接收新邮件列表,然后再需要的时候(比如读取邮件内容)才从邮件服务器读取邮件内容。
在读取邮件时,我们可以用Message类的getContent()方法接收邮件或是writeTo()方法将邮件保存,getContent()方法只接收邮件内容(不包含邮件头),而writeTo()方法将包括邮件头。
System.out.println(((MimeMessage)message).getContent());
在读取邮件内容后,别忘记了关闭Folder和Store。
folder.close(aBoolean);
store.close();
传递给Folder.close()方法的boolean 类型参数表示是否在删除操作邮件后更新Folder。
H.继续向前进!
在讲解了以上的七个Java Mail核心类定义和理解了简单的代码片断后,下文将详细讲解怎样使用这些类实现JavaMail API所要完成的高级功能。
五、使用JavaMail API
在明确了JavaMail API的核心部分如何工作后,本人将带领大家学习一些使用Java Mail API任务案例。
1.发送邮件
在获得了Session后,建立并填入邮件信息,然后发送它到邮件服务器。这便是使用Java Mail API发送邮件的过程,在发送邮件之前,我们需要设置SMTP服务器:通过设置Properties的mail.smtp.host属性。
String host = ...;
String from = ...;
String to = ...;
// Get system properties
Properties props = System.getProperties();
// Setup mail server
props.put("mail.smtp.host", host);
// Get session
Session session = Session.getDefaultInstance(props, null);
// Define message
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
message.setSubject("Hello JavaMail");
message.setText("Welcome to JavaMail");
// Send message
Transport.send(message);
由于建立邮件信息和发送邮件的过程中可能会抛出异常,所以我们需要将上面的代码放入到try-catch结构块中。
2.接收邮件
为了在读取邮件,我们获得了session,并且连接到了邮箱的相应store,打开相应的Folder,然后得到我们想要的邮件,当然别忘记了在结束时关闭连接。
String host = ...;
String username = ...;
String password = ...;
// Create empty properties
Properties props = new Properties();
// Get session
Session session = Session.getDefaultInstance(props, null);
// Get the store
Store store = session.getStore("pop3");
store.connect(host, username, password);
// Get folder
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
// Get directory
Message message[] = folder.getMessages();
for (int i=0, n=message.length; i<n; i++) {
System.out.println(i + ": " + message[i].getFrom()[0]
+ " " + message[i].getSubject());
}
// Close connection
folder.close(false);
store.close();
上面的代码所作的是从邮箱中读取每个邮件,并且显示邮件的发信人地址和主题。从技术角度讲,这里存在着一个异常的可能:当发信人地址为空时,getFrom()[0]将抛出异常。
下面的代码片断有效的说明了如何读取邮件内容,在显示每个邮件发信人和主题后,将出现用户提示从而得到用户是否读取该邮件的确认,如果输入YES的话,我们可用Message.writeTo(java.io.OutputStream os)方法将邮件内容输出到控制台上,关于Message.writeTo()的具体用法请看JavaMail API。
BufferedReader reader = new BufferedReader (
new InputStreamReader(System.in));
// Get directory
Message message[] = folder.getMessages();
for (int i=0, n=message.length; i<n; i++) {
System.out.println(i + ": " + message[i].getFrom()[0]
+ " " + message[i].getSubject());
System.out.println("Do you want to read message? " +
"[YES to read/QUIT to end]");
String line = reader.readLine();
if ("YES".equals(line)) {
message[i].writeTo(System.out);
} else if ("QUIT".equals(line)) {
break;
}
}
我们在前面已经学会了如何使用Authenticator类来代替直接使用用户名和密码这两字符串作为Session.getDefaultInstance()或者Session.getInstance()方法的参数。在前面的小试牛刀后,现在我们将了解到全面认识一下邮件认证。
我们在此取代了直接使用邮件服务器主机名、用户名、密码这三个字符串作为连接到POP3 Store的方式,使用存储了邮件服务器主机名信息的属性文件,并在获得Session时传入自定义的Authenticator实例:
// Setup properties
Properties props = System.getProperties();
props.put("mail.pop3.host", host);
// Setup authentication, get session
Authenticator auth = new PopupAuthenticator();
Session session = Session.getDefaultInstance(props, auth);
// Get the store
Store store = session.getStore("pop3");
store.connect();
PopupAuthenticator类继承了抽象类Authenticator,并且通过重载Authenticator类的getPasswordAuthentication()方法返回PasswordAuthentication类对象。而getPasswordAuthentication()方法的参数param是以逗号分割的用户名、密码组成的字符串。
import javax.mail.*;
import java.util.*;
public class PopupAuthenticator extends Authenticator {
public PasswordAuthentication getPasswordAuthentication(String param) {
String username, password;
StringTokenizer st = new StringTokenizer(param, ",");
username = st.nextToken();
password = st.nextToken();
return new PasswordAuthentication(username, password);
}
}
使用附件
附件作为与邮件相关的资源经常以文本、表格、图片等格式出现,如流行的邮件客户端一样,我们可以用JavaMail API从邮件中获取附件或是发送带有附件的邮件。
A.发送带有附件的邮件
发送带有附件的邮件的过程有些类似转发邮件,我们需要建立一个完整邮件的各个邮件体部分,在第一个部分(即我们的邮件内容文字)后,增加一个具有DataHandler的附件而不是在转发邮件时那样复制第一个部分的DataHandler。
如果我们将文件作为附件发送,那么要建立FileDataSource类型的对象作为附件数据源;如果从URL读取数据作为附件发送,那么将要建立URLDataSource类型的对象作为附件数据源。
然后将这个数据源(FileDataSource或是URLDataSource)对象作为DataHandler类构造方法的参数传入,从而建立一个DataHandler对象作为数据源的DataHandler。
接着将这个DataHandler设置为邮件体部分的DataHandler。这样就完成了邮件体与附件之间的关联工作,下面的工作就是BodyPart的setFileName()方法设置附件名为原文件名。
最后将两个邮件体放入到Multipart中,设置邮件内容为这个容器Multipart,发送邮件。
// Define message
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
message.setSubject("Hello JavaMail Attachment");
// Create the message part
BodyPart messageBodyPart = new MimeBodyPart();
// Fill the message
messageBodyPart.setText("Pardon Ideas");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Part two is attachment
messageBodyPart = new MimeBodyPart();
DataSource source = new FileDataSource(filename);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
multipart.addBodyPart(messageBodyPart);
// Put parts in message
message.setContent(multipart);
// Send the message
Transport.send(message);