SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP协议属于TCP/IP协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。通过SMTP协议所指定的服务器,就可以把E-mail寄到收信人的服务器上了,整个过程只要几分钟。SMTP服务器则是遵循SMTP协议的发送邮件服务器,用来发送或中转发出的电子邮件。
POP是一种邮局协议,目前为第3个版本,即众所周知的POP3。POP定义了一种用户如何获得邮件的机制。它规定了每个用户使用一个单独的邮箱。大多数人在使用POP时所熟悉的功能并非都被支持,例如查看邮箱中的新邮件数量。而这个功能是微软的Outlook内建的,那么就说明微软Outlook之类的邮件客户端软件是通过查询最近收到的邮件来计算新邮件的数量来实现前面所说的功能。因此在我们使用JavaMail API时需要注意,当需要获得如前面所讲的新邮件数量之类的信息时,我们不得不自己进行计算。
IMAP(Internet Mail Access Protocol,Internet邮件访问协议)以前称作交互邮件访问协议(Interactive Mail Access Protocol)。IMAP是斯坦福大学在1986年开发的一种邮件获取协议。它的主要作用是邮件客户端(例如MS Outlook Express)可以通过这种协议从邮件服务器上获取邮件的信息,下载邮件等。当前的权威定义是RFC3501。IMAP协议运行在TCP/IP协议之上,使用的端口是143。它与POP3协议的主要区别是用户可以不用把所有的邮件全部下载,可以通过客户端直接对服务器上的邮件进行操作。
MIME并不是用于传送邮件的协议,它作为多用途邮件的扩展定义了邮件内容的格式:信息格式、附件格式等等。
1、打开cmd,输入命令如下(以新浪邮箱为例):
telent smtp.sina.com 25
2、连接以后,打开新窗口,输入:
ehlo
3、输入命令
auth login
4、输入用户名
注:需要使用base64编码转换
5、输入密码
(同样需要进行编码转换)
6、开始发邮件
mail from: //发件人
rcpt to: //收件人
data //表示开始输入邮件内容
from: //邮件主题显示的发件人
to: xxxx
subject:
date:
//此处需空一行,上述四行为邮件头部内容
xxxxxxxxx //内容
. //以英文符号的句号结束,表示邮件书写完毕
//发送成功
quit //退出
注:在书写过程中,应该按照顺序书写每一个字母,如果字母书写错误就会出现
里边的内容。
包含开发java mail所需要的API
下载:http://pan.baidu.com/s/1geXlZoB
对任何数据块的分类、以及对它们的处理的特性。这些特性是JavaMail API需要的。
下载:http://pan.baidu.com/s/1gfLWY8F
Session类定义了基本的邮件会话。就像Http会话那样,我们进行收发邮件的工作都是基于这个会话的。Session对象利用了java.util.Properties对象获得了邮件服务器、用户名、密码信息和整个应用程序都要使用到的共享信息。
Session类的构造方法是私有的,所以可以使用Session类提供的getDefaultInstance()这个静态工厂方法获得一个默认的Session对象:
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
或者使用getInstance()这个静态工厂方法获得自定义的Session:
Properties props = new Properties();
Session session = Session.getInstance(props, null);
从上面的两个例子中不难发现,getDefaultInstance()和getInstance()方法的第二个参数都是null,这是因为在上面的例子中并没有使用到邮件授权,下文中将对授权进行详细介绍。
从很多的实例看,在对mail server进行访问的过程中使用共享的Session是足够的,即使是工作在多个用户邮箱的模式下也不例外。
建立了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 mail", "text/plain");
然而,如果我们所使用的MimeMessage中信息内容是文本的话,我们便可以直接使用setText()方法来方便的设置文本内容。
message.setText("Hello mail");
前面所讲的两种方法,对于文本信息,后者更为合适。而对于其它的一些信息类型,比如HTML信息,则要使用前者。
需要注意的是,使用setSubject()方法对邮件设置邮件主题:
message.setText("Hello mail");
Address,跟Message一样,Address类也是一个抽象类,所以需要使用javax.mail.internet.InternetAddress这个子类。
通过传入代表邮件地址的字符串,可以建立一个邮件地址类:
Address address = new InternetAddress("[email protected]");
如果要在邮件地址后面增加名字的话,可以通过传递两个参数:代表邮件地址和名字的字符串来建立一个具有邮件地址和名字的邮件地址类:
Address address = new InternetAddress("[email protected]", "swxctx");
在建立了邮件地址类后,可以通过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([email protected]);
Address ccAddress = new InternetAddress([email protected]);
message.addRecipient(Message.RecipientType.TO, toAddress);
message.addRecipient(Message.RecipientType.CC, ccAddress);
JavaMail API并没有提供检查邮件地址有效性的机制。当然我们可以自己完成这个功能:验证邮件地址的字符是否按照RFC822规定的格式书写或者通过DNS服务器上的MX记录验证等。
像java.net类那样,JavaMail API通过使用授权者类(Authenticator)以用户名、密码的方式访问那些受到保护的资源,在这里“资源”就是指邮件服务器。
在javax.mail包中可以找到这个JavaMail的授权者类(Authenticator)。
在使用Authenticator这个抽象类时,必须采用继承该抽象类的方式,并且该继承类必须具有返回PasswordAuthentication对象(用于存储认证时要用到的用户名、密
码)getPasswordAuthentication()方法。并且要在Session中进行注册,使Session能够了解在认证时该使用哪个类。
下面代码片断中的MyAuthenticator就是一个Authenticator的子类。
Properties props = new Properties();
Authenticator auth = new MyAuthenticator();
Session session = Session.getDefaultInstance(props, auth);
在发送信息时,Transport类将被用到。这个类实现了发送信息的协议(通称为SMTP),此类是一个抽象类,可以使用这个类的静态方法send()来发送消息,如下:
Transport.send(message);
我们也可由Session获得相应协议对应的Transport实例。
通过传递用户名、密码、邮件服务器主机名等参数建立与邮件服务器的连接,并使用sendMessage()方法将信息发送,最后关闭连接,如下示例:
message.saveChanges();
Transport transport = session.getTransport("smtp");//使用smtp服务器
transport.connect(host, username, password);//连接服务器
transport.sendMessage(message, message.getAllRecipients());//发送消息
transport.close();//关闭连接
注意:如果需要在发送邮件过程中监控mail命令的话,可以在发送前设置debug标志:
session.setDebug(true);
接收邮件和发送邮件很类似都要用到Session。但是在获得Session后,需要从Session中获取特定类型的Store,然后连接到Store,
这里的Store代表了存储邮件的邮件服务器。在连接Store的过程中,极有可能需要用到用户名、密码或者Authenticator。
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();//得到消息数组
注:对于POP3协议只有一个名为INBOX的Folder有效,而对于IMAP协议,我们可以访问多个Folder。
而且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。
在获得了Session后,建立并填入邮件信息,然后发送它到邮件服务器。这便是使用Java Mail API发送邮件的过程,在发送邮件之前,
需要设置SMTP服务器:通过设Properties的mail.smtp.host属性。
String host = ...;//smtp服务器名
String from = ...;//发件人
String to = ...; //收件人
Properties props = System.getProperties();
// 服务器认证
props.put("mail.smtp.host", host);
// 获取session
Session session = Session.getDefaultInstance(props, null);
//定义消息
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");//正文
// 发送消息
Transport.send(message);
由于建立邮件信息和发送邮件的过程中可能会抛出异常,所以需要将上面的代码放入到try-catch结构块中。
为了在读取邮件,我们获得了session,并且连接到了邮箱的相应store,打开相应的Folder,然后得到我们想要的邮件,当然别忘记了在结束时关闭连接。
String host = ...;//服务器
String username = ...;//邮箱
String password = ...;//密码
Properties props = new Properties();
//获取session
Session session = Session.getDefaultInstance(props, null);
// 获取store
Store store = session.getStore("pop3");//pop3服务器
store.connect(host, username, password); //连接
// 得到文件夹
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
// 得到文件消息
Message message[] = folder.getMessages();
for (int i=0, n=message.length; i
上面的代码所作的是从邮箱中读取每个邮件,并且显示邮件的发信人地址和主题。
下面的代码片断有效的说明了如何读取邮件内容,在显示每个邮件发信人和主题后,将出现用户提示从而得到用户是否读取该邮件的确认,如果输入YES的话,
可用Message.writeTo(java.io.OutputStream os)方法将邮件内容输出到控制台上,关于Message.writeTo()的具体用法请看JavaMail API。
BufferedReader reader = new BufferedReader ( new InputStreamReader(System.in));
Message message[] = folder.getMessages();
for (int i=0, n=message.length; i
设置与message相关的Flags是删除邮件的常用方法。这些Flags表示了一些系统定义和用户定义的不同状态。在Flags类的内部类Flag中预定义了一些标志:
Flags.Flag.ANSWERED
Flags.Flag.DELETED
Flags.Flag.DRAFT
Flags.Flag.FLAGGED
Flags.Flag.RECENT
Flags.Flag.SEEN
Flags.Flag.USER
在使用时需要注意:标志存在并非意味着这个标志被所有的邮件服务器所支持。
例如,对于删除邮件的操作,POP协议不支持上面的任何一个。所以要确定哪些标志是被支持的。
通过访问一个已经打开的Folder对象的getPermanetFlags()方法,它将返回当前被支持的Flags类对象。
删除邮件时,我们可以设置邮件的DELETED标志:
message.setFlag(Flags.Flag.DELETED, true);
但是首先要采用READ_WRITE的方式打开Folder:
folder.open(Folder.READ_WRITE);
在对邮件进行删除操作后关闭Folder时,需要传递一个true作为对删除邮件的擦除确认。
folder.close(true);
Folder类中另一种用于删除邮件的方法expunge()也同样可删除邮件,但是它并不为sun提供的POP3实现支持,
而其它第三方提供的POP3实现支持或者并不支持这种方法。
另外,介绍一种检查某个标志是否被设置的方法:Message.isSet(Flags.Flag flag)方法,其中参数为被检查的标志。
在前面已经学会了如何使用Authenticator类来代替直接使用用户名和密码这两字符串作为Session.getDefaultInstance()或者Session.getInstance()方法的参数。
我们在此取代了直接使用邮件服务器主机名、用户名、密码这三个字符串作为连接到POP3 Store的方式,使用存储了邮件服务器主机名信息的属性文件,
并在获得Session时传入自定义的Authenticator实例:
Properties props = System.getProperties();
props.put("mail.pop3.host", host);
Authenticator auth = new PopupAuthenticator();
Session session = Session.getDefaultInstance(props, auth);
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);
}
}
回复邮件的方法很简单:使用Message类的reply()方法,通过配置回复邮件的收件人地址和主题(如果没有提供主题的话,系统将默认将“Re:”作为邮件的主体),
这里不需要设置任何的邮件内容,只要复制发信人或者reply-to到新的收件人。而reply()方法中的boolean参数表示是否将邮件回复给发送者(参数值为false),
或是恢复给所有人(参数值为true)。
reply-to地址需要在发信时使用setReplyTo()方法设置。
MimeMessage reply = (MimeMessage)message.reply(false);
reply.setFrom(new InternetAddress("[email protected]"));
reply.setText("Thanks");
Transport.send(reply);
转发邮件的过程不如前面的回复邮件那样简单,它将建立一个转发邮件,这并非一个方法就能做到。
每个邮件是由多个部分组成,每个部分称为一个邮件体部分,是一个BodyPart类对象,对于MIME类型邮件来讲就是MimeBodyPart类对象。
这些邮件体包含在成为Multipart的容器中对于MIME类型邮件来讲就是MimeMultiPart类对象。
在转发邮件时,我们建立一个文字邮件体部分和一个被转发的文字邮件体部分,然后将这两个邮件体放到一个Multipart中。
说明一下,复制一个邮件内容到另一个邮件的方法是仅复制它的DataHandler(数据处理者)即可。
这是由JavaBeans Activation Framework定义的一个类,它提供了对邮件内容的操作命令的访问、管理了邮件内容操作,是不同的数据源和数据格式之间的一致性接口。
Message forward = new MimeMessage(session);
forward.setSubject("Fwd: " + message.getSubject());
forward.setFrom(new InternetAddress(from));
forward.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText( "Here you go with the original message:\n\n");
// Create a multi-part to combine the parts
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Create and fill part for the forwarded contentmessage
BodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(message.getDataHandler());
// Add part to multi part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with messageforward.
setContent(multipart);
// Send message
Transport.send(forward);
附件作为与邮件相关的资源经常以文本、表格、图片等格式出现,如流行的邮件客户端一样,可以用JavaMail API从邮件中获取附件或是发送带有附件的邮件。
发送带有附件的邮件的过程有些类似转发邮件,我们需要建立一个完整邮件的各个邮件体部分,在第一个部分(即我们的邮件内容文字)后,
增加一个具有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 messagemessage
BodyPart.setText("Pardon Ideas");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Part two is attachmentmessageBodyPart = 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);
如果使用servlet实现发送带有附件的邮件,则必须上传附件给servlet,这时需要注意提交页面form中对编码类型的设置应为multipart/form-data。
读取邮件中的附件的过程要比发送它的过程复杂一点。因为带有附件的邮件是多部分组成的,必须处理每一个部分获得邮件的内容和附件。
但是如何辨别邮件信息内容和附件呢?Sun在Part类(BodyPart类实现的接口类)中提供了getDisposition()方法让开发者获得邮件体部分的部署类型,
当该部分是附件时,其返回之将是Part.ATTACHMENT。但附件也可以没有部署类型的方式存在或者部署类型为Part.INLINE,
无论部署类型为Part.ATTACHMENT还是Part.INLINE,都能把该邮件体部分导出保存。
Multipart mp = (Multipart)message.getContent();
for (int i=0, n=multipart.getCount(); i
下列代码中使用了saveFile方法是自定义的方法,它根据附件的文件名建立一个文件,如果本地磁盘上存在名为附件的文件,那么将在文件名后增加数字表示区别。
然后从邮件体中读取数据写入到本地文件中(代码省略)。
// from saveFile()
File file = new File(filename);
for (int i=0; file.exists(); i++) {
file = new File(filename+i);
}
以上是邮件体部分被正确设置的简单例子,如果邮件体部分的部署类型为null,那么我们通过获得邮件体部分的MIME类型来判断其类型作相应的处理
代码结构框架如下:
if (disposition == null) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart)part;
if (mbp.isMimeType("text/plain")) {
// Handle plain
} else {
// Special non-attachment cases here of
// image/gif, text/html, ... }
...}
前面的例子中发送的邮件都是以文本为内容的(除了附件),下面介绍如何接收和发送基于HTML的邮件。
假如需要发送一个HTML文件作为邮件内容,并使邮件客户端在读取邮件时获取相关的图片或者文字的话,只要设置邮件内容为html代码,
并设置内容类型为text/html即可:
String htmlText = " Hello " +message.setContent(htmlText, "text/html"));
注意:这里的图片并不是在邮件中内嵌的,而是在URL中定义的。邮件接收者只有在线时才能看到。
在接收邮件时,如果我们使用JavaMail API接收邮件的话是无法实现以HTML方式显示邮件内容的。
因为JavaMail API邮件内容视为二进制流。所以要显示HTML内容的邮件,我们必须使用JEditorPane或者第三方HTML展现组件。
以下代码显示了如何使用JEditorPane显示邮件内容:
if (message.getContentType().equals("text/html"))
{ String content = (String)message.getContent();
JFrame frame = new JFrame();
JEditorPane text = new JEditorPane("text/html", content);
text.setEditable(false);
JScrollPane pane = new JScrollPane(text);
frame.getContentPane().add(pane);
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.show();}
如果我们在邮件中使用HTML作为内容,那么最好将HTML中使用的图片作为邮件的一部分,这样无论是否在线都会正确的显示HTML中的图片。
处理方法就是将HTML中用到的图片作为邮件附件并使用特殊的cid URL作为图片的引用,这个cid就是对图片附件的Content-ID头的引用。
处理内嵌图片就像向邮件中添加附件一样,不同之处在于我们必须通过设置图片附件所在的邮件体部分的header中Content-ID为一个随机字符串,
并在HTML中img的src标记中设置为该字符串。这样就完成了图片附件与HTML的关联。
String file = ...;// Create the message
Message message = new MimeMessage(session);
// Fill its headers
message.setSubject("Embedded Image");
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
// Create your new message part
BodyPart messageBodyPart = new MimeBodyPart();
String htmlText = " Hello" + " ";
messageBodyPart.setContent(htmlText, "text/html");
// Create a related multi-part to combine the parts
MimeMultipart multipart = new MimeMultipart("related");
multipart.addBodyPart(messageBodyPart);
// Create part for the imagemessageBodyPart = new MimeBodyPart();
// Fetch the image and associate to par
tDataSource fds = new FileDataSource(file);
messageBodyPart.setDataHandler(new DataHandler(fds));
messageBodyPart.setHeader("Content-ID","");
// Add part to multi-part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with message
message.setContent(multipart);
JavaMail API提供了过滤器机制,它被用来建立搜索短语。这个短语由javax.mail.search包中的SearchTerm抽象类来定义,
在定义后我们便可以使用Folder的Search()方法在Folder中查找邮件:
SearchTerm st = ...;Message[] msgs = folder.search(st);
下面有22个不同的类(继承了SearchTerm类)供我们使用:
AND terms (class AndTerm)
OR terms (class OrTerm)
NOT terms (class NotTerm)
SENT DATE terms (class SentDateTerm)
CONTENT terms (class BodyTerm)
HEADER terms (FromTerm / FromStringTerm, RecipientTerm / RecipientStringTerm, SubjectTerm, etc.)
使用这些类定义的断语集合,我们可以构造一个逻辑表达式,并在Folder中进行搜索。
下面是一个实例:在Folder中搜索邮件主题含有“XC”字符串或者发信人地址为[email protected]的邮件。
SearchTerm st = new OrTerm( new SubjectTerm("XC:"),
new FromStringTerm("[email protected]"));
Message[] msgs = folder.search(st);
此文来源于网络与个人总结,感谢DIY的指导。
Java mail已经是多年以前的技术,现在各大公司发展的也比较成熟,但是作为一名java程序员,掌握java mail也是必须的;
对于基本的操作是需要掌握的,对于高并发与垃圾等处理则是需要深入研究的,毕竟在市场是需要考虑很多东西的;此系个人
观点,广大爱好者请多指教。