javamail详解
来源:互联网 发布:梦龙网络进度计划软件 编辑:程序博客网 时间:2024/05/21 14:40
JavaMail发送和接收邮件
一、JavaMail概述:
l
l
l
这三种协议都有对应SSL加密传输的协议,分别是SMTPS,POP3S和IMAPS。
除JavaMail服务提供程序之外,JavaMail还需要JAF(JavaBeans ActivationFramework)来处理不是纯文本的邮件内容,这包括MIME(多用途互联网邮件扩展)、URL页面和文件附件等内容。下图描述了JavaMail的体系结构。
mail.jar:此JAR文件包含JavaMail API和Sun提供的SMTP、IMAP和POP3服务提供程序;
activation.jar:此JAR文件包含JAF API和Sun的实现。
二、对相关协议的回顾:
您还将碰到 NNTP 和其它协议。理解所有协议的基本知识将有助于您理解如何使用 JavaMailAPI。虽然不了解这些协议您照样可以用这个API,却不能够克服那些基础协议的局限性。如果我们精选的协议不能支持某种性能,JavaMail API决不能魔术般的将这种性能添加上去。(您很快就会看到,在处理 POP 时这将成为一个难题。)
三、JavaMail的关键对象:
Properties:属性对象
属性名
属性类型
说明
mail.stmp.host
String
SMTP服务器地址,如smtp.sina.com.cn
mail.stmp.port
int
SMTP服务器端口号,默认为25
mail.stmp.auth
boolean
SMTP服务器是否需要用户认证,默认为false
mail.stmp.user
String
SMTP默认的登陆用户名
mail.stmp.from
String
默认的邮件发送源地址
mail.stmp.socketFactory.class
String
socket工厂类类名,通过设置该属性可以覆盖提供者默认的实现,必须实现javax.net.SocketFactory接口
mail.stmp.socketFactory.port
int
指定socket工厂类所用的端口号,如果没有规定,则使用默认的端口号
mail.smtp.socketFactory.fallback
boolean
设置为true时,当使用指定的socket类创建socket失败后,将使用java.net.Socket创建socket,默认为true
mail.stmp.timeout
int
I/O连接超时时间,单位为毫秒,默认为永不超时
Session:会话对象
l
l
l
l
l
l
Transport和Store:传输和存储
属性名
说明
mail.transport.protocol
默认的邮件传输协议,例如,smtp
mail.store.protocol
默认的存储邮件协议,例如:pop3
mail.host
默认的邮件服务地址,例如:192.168.67.1
mail.user
默认的登陆用户名,例如:zapldy
下面,我们再回头来了解Session的getTransport()和getStore()的重载方法。
l
l
如果Session中未包含Authenticator,以上两方法创建的Transport实例和邮件服务器交互时必须显示提供用户名/密码的认证信息。如果Authenticator非空,则可以在和邮件服务器交互时被作为认证信息使用。除了以上两种提供认证信息的方式外,Session还可以使用以下的方法为Transport提供认证信息。
Transport getTransport(URLNameurl):用户可以通过URLName入参指定邮件协议、邮件服务器、端口、用户名和密码信息,请看下面的代码:
Transport.send(message);
或者,您也可以从针对您的协议的会话中获得一个特定的实例,传递用户名和密码(如果不必要就不传),发送消息,然后关闭连接。
message.saveChanges(); // implicit with send()
Transport transport = session.getTransport("smtp");
transport.connect(host, username, password);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
后面这种方法在您要发送多条消息时最好,因为它能保持邮件服务器在消息间的活动状态。基本 send()机制为每个方法的调用设置与服务器独立的连接。
// Store store = session.getStore("imap");
Store store = session.getStore("pop3");
store.connect(host, username, password);
连接到 Store 之后,接下来,您就可以获取一个 Folder,您必需先打开它,然后才能读里面的消息。
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
Message message[] = folder.getMessages();
POP3 唯一可以用的文件夹是 INBOX。如果使用 IMAP,还可以用其它文件夹。
注意:Sun 的供应商有意变得聪明。虽然 Message message[] = folder.getMessages();看上去是个很慢的操作,它从服务器上读取每一条消息,但仅在你实际需要消息的一部分时,消息的内容才会被检索。
一旦有了要读的 Message,您可以用 getContent() 来获取其内容,或者用 writeTo()将内容写入流。getContent() 方法只能得到消息内容,而 writeTo() 的输出却包含消息头。
System.out.println(((MimeMessage)message).getContent());
一旦读完邮件,要关闭与 folder 和 store 的连接。
folder.close(aBoolean);
store.close();
传递给 folder 的 close() 方法的 boolean 表示是否清除已删除的消息从而更新 folder。
Message:消息对象
要创建一个 Message,请将 Session 对象传递给 MimeMessage 构造器:
MimeMessage message = new MimeMessage(session);
注意:还存在其它构造器,如用按 RFC822 格式的输入流来创建消息。
一旦获得消息,您就可以设置各个部分,因为 Message 实现 Part 接口(且 MimeMessage 实现MimePart )。设置内容的基本机制是 setContent() 方法,同时使用参数,分别代表内容和 mime 类型:
message.setContent("Hello", "text/plain");
但如果,您知道您在使用 MimeMessage,而且消息是纯文本格式,您就可以用 setText()方法,它只需要代表实际内容的参数,( MIME 类型缺省为 text/plain):
message.setText("Hello");
后一种格式是设置纯文本消息内容的首选机制。至于发送其它类型的消息,如 HTML 文件格式的消息,我们首选前者。
用 setSubject() 方法设置 subject(主题):
message.setSubject("First");
下面的代码演示了创建一个简单邮件信息的过程:
Message msg = newMimeMessage(session);
msg.setSubject("Test Title");
msg.setText("How are you!");
msg.setSentDate(new Date());
Address:地址
若创建的地址只包含电子邮件地址,只要传递电子邮件地址到构造器就行了。
Address address = newInternetAddress("president@whitehouse.gov");
若希望名字紧挨着电子邮件显示,也可以把它传递给构造器:
Address address = newInternetAddress("president@whitehouse.gov", "George Bush");
需要为消息的 from 域和 to 域创建地址对象。除非邮件服务器阻止,没什么能阻止你发送一段看上去是来自任何人的消息。
一旦创建了 address(地址),将它们与消息连接的方法有两种。如果要识别发件人,您可以用 setFrom() 和setReplyTo() 方法。
message.setFrom(address)
需要消息显示多个 from 地址,可以使用 addFrom() 方法:
Address address[] = ...;
message.addFrom(address);
若要识别消息 recipient(收件人),您可以使用 addRecipient() 方法。除address(地址)外,这一方法还请求一个 Message.RecipientType。
message.addRecipient(type, address)
三种预定义的地址类型是:
Message.RecipientType.TO
Message.RecipientType.CC
Message.RecipientType.BCC
如果消息是发给副总统的,同时发送一个副本(carbon copy)给总统夫人,以下做法比较恰当:
Address toAddress = newInternetAddress("vice.president@whitehouse.gov");
Address ccAddress = newInternetAddress("first.lady@whitehouse.gov");
message.addRecipient(Message.RecipientType.TO, toAddress);
message.addRecipient(Message.RecipientType.CC, ccAddress);
JavaMail API 没有提供电子邮件地址有效性核查机制。虽然通过编程,自己能够扫描有效字符(如 RFC 822中定义的)或验证邮件交换(mail exchange,MX)记录,但这些功能不属于 JavaMail API。
Authenticator:认证者
Properties props = new Properties();
// fill props with any information
Authenticator auth = new MyAuthenticator();
Session session = Session.getDefaultInstance(props, auth);
发送消息:
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,
您应该将代码放在一个 try-catch 程序块中,这样创建和发送消息时就能够抛出异常。
消息的提取:
对每条消息做些什么由您决定。上面的代码块只是显示这些消息的发件人和主题。技术上讲,from 地址列表可能为空,而getFrom()[0] 调用会抛出一个异常。
要显示全部信息,您可以在用户看完 from 和 subject 域之后给出提示,如用户有需要,就调用消息的 writeTo()方法来实现。
消息和标识的删除:
仅仅因为存在一个标志,并不意味着所有邮件服务器或供应商都支持这个标志。例如,除了删除消息标志外,POP协议不再支持其它任何标志。检查是否存在新邮件,这不是个 POP 任务,而是内建于邮件客户机的任务。为找出哪些标志能被支持,可以用getPermanentFlags() 向 folder 提出要求。
要删除消息,您可以设置消息的 DELETED flag:
message.setFlag(Flags.Flag.DELETED, true);
首先,请以 READ_WRITE 模式打开 folder:
folder.open(Folder.READ_WRITE);
然后,当所有消息的处理完成后,关闭 folder,并传递一个 true 值,从而擦除(expunge)有 delete标志的消息。
folder.close(true);
一个 Folder 的 expunge() 方法可以用来删除消息。但 Sun 的 POP3供应商不支持。其它供应商有的或许能够实现这一功能,而有的则不能。IMAP 供应商极有可能实现此功能。因为 POP只支持单个对邮箱的访问,对 Sun 的供应商来说,您必需关闭 folder 以删除消息。
要取消标志,只要传递 false 给 setFlag() 方法就行了。想知道是否设置过标志,可以用 isSet()检查。
亲自认证:
不用主机、用户名和密码与 Store 相连接,而是设置 Properties 来拥有主机,然后告诉 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();
然后,您创建一个 Authenticator 子类并从 getPasswordAuthenticatio
import javax.mail.*;
import javax.swing.*;
import java.util.*;
public class PopupAuthenticator extends Authenticator {
}
因为 PopupAuthenticator 涉及到 Swing,它会启动 AWT的事件处理线程。这一点基本上要求您在代码中添加一个对 System.exit() 的调用来终止程序。
消息的回复:
MimeMessage reply = (MimeMessage)message.reply(false);
reply.setFrom(newInternetAddress("president@whitehouse.gov"));
reply.setText("Thanks");
Transport.send(reply);
在发送消息时要配置 reply to(被回复人) 地址,可以用 setReplyTo() 方法。
消息的转发:
转发消息有一点棘手。没有单独的方法可以调用,您通过对组成消息各部分的处理来组织要转发的消息。
一条邮件消息可以由多个部分组成。在处理 MIME 消息时,消息中每部分都是 BodyPart,再特殊些,是MimeBodyPart。不同的 body part(信体部件或正文部件)结合成一个容器,名为 Multipart,再特殊些,就是MimeMultipart。要转发一条消息,您为自己的消息正文创建一个部件,要转发的消息作为另一部件。并且将两个部件结合成一个multipart(多部件)。然后您将这个 multipart 添加到一则已写好恰当地址的消息中,并发送。
本质上就是如此。要将一条消息内容复制到另一条,只要复制 DataHandler (JavaBeans ActivationFramework 中的类)就行了。
// Create the message to forward
Message forward = new MimeMessage(session);
// Fill in header
forward.setSubject("Fwd: " + message.getSubject());
forward.setFrom(new InternetAddress(from));
forward.addRecipient(Message.RecipientType.TO,
// Create your new message part
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(
// Create a multi-part to combine the parts
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Create and fill part for the forwarded content
messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(message.getDataHandler());
// Add part to multi part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with message
forward.setContent(multipart);
// Send message
Transport.send(forward);
附件的处理:
附件是邮件消息的相关资源,如通常不包含在消息正文里文本文件、电子表格或图像等。常见的邮件程序,如 Eudora 和 pine之类,可以用 JavaMail API 将资源 attach(附加) 到您的消息上,就可以在收到消息时得到。
附件的发送:
发送附件非常像转发消息。您建立各部分以组成完整消息。完成第一部件,即消息正文后,您添加其它部件,其中每个 DataHandler都代表附件,而不是转发消息情况下的共享处理程序。如果从文件中读附件,附件的数据源是 FileDataSource。而如果从 URL中读时,附件的数据源是 URLDataSource。一旦存在 DataSource,只要先把它传递给 DataHandler构造器,最后再用 setDataHandler() 把它附加到 BodyPart。假定您要保留附件的原始文件名,最终要做的是用BodyPart 的 setFileName() 方法设置与附件相关的文件名。如下所示:
就消息引入附件时,若程序是个 servlet (小服务程序),除告知消息发送到何处外,还必需上载附件。可以将multipart/form-data 表单编码类型(form encoding type)用于每个上载文件的处理。
<FORM ENCTYPE="multipart/form-data"
</FORM>
注意:消息大小由 SMTP 服务器而不是 JavaMail API 来限制。如果您碰到问题,可以考虑用设置 ms 和 mx参数的方法增大 Java 堆大小。
附件的获取:
从消息中获取附件比发送它们棘手些,因为 MIME 没有简单的关于附件的概念。当消息包含附件时,消息的内容是个 Multipart对象。接着,您需要处理每个 Part,获取主要内容和附件。标有从 part.getDisposition() 获得的Part.ATTACHMENT 配置(disposition)的部件(Part)无疑就是附件。但是,没有配置(以及一个非文本 MIME类型)和带 Part.INLINE 配置的部件也可能是附件。当配置要么是 Part.ATTACHMENT,要么是Part.INLINE 时,这个消息部件的内容就能被保存。只要用 getFileName() 和 getInputStream()就能分别得到原始文件名和输入流。
Multipart mp = (Multipart)message.getContent();
for (int i=0, n=multipart.getCount(); i<n; i++){
}
saveFile() 方法仅依据文件名创建了一个File,它从输入流中将字节读出,然后写入到文件中。万一文件已经存在,就在文件名后添加一个数字作为新文件名,如果这个文件名仍存在,则继续添,直到找不到这样的文件名为止。
// from saveFile()
File file = new File(filename);
for (int i=0; file.exists(); i++) {
}
上面的代码涵盖了最简单的情况 — 消息中各部件恰当的标记了。要涵盖所有情况,还要在配置为空时进行处理,并且获取部件的 MIME类型来进行相应处理。
if (disposition == null) {
}
对 HTML消息的处理
发送基于 HTML文件格式消息的工作量比发送纯文本消息多,虽然不一定非要这些多余的工作量。如何选择完全取决于给定的请求。
HTML 消息的发送:
若您所要做的全部事情是发送一份 HTML文件的等价物作为消息,但让邮件阅读者为不能提取任何内嵌图像或相关片段而担心的话,可以使用 Message 的 setContent()方法,把内容当作一个 String 传入,并将内容类型设置成 text/html。
String htmlText ="<H1>Hello</H1>"+
message.setContent(htmlText, "text/html"));
在接收端,如果您用 JavaMail API 提取消息,API 中没有内建的显示 HTML 消息的东西。 JavaMailAPI 只把它看成一串字节流。要显示 HTML 文件格式的消息,您必需使用 Swing JEditorPane 或其它第三方 HTML格式查看器组件。
if (message.getContentType().equals("text/html")) {
}
在消息中引入图像:
另一方面,如果您想让 HTML 文件格式内容的消息完整(内嵌的图像作为消息的一部分),您必需把图像作为附件,并且用一个给定的cid URL 引用图像,其中 cid 是图像附件 Content-ID 头的引用。
嵌入图像的过程与附加文件到消息的过程非常相似,唯一的区别在于您必需通过设置 MimeMultipart构造器中的子类型(或者说用 setSubType())告知 MimeMultipart 各个相关部件,并且将这个图像的Content-ID 头设置成随机字符串,作为图像的 src 在 img 标记中使用。完整的演示如下。
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,
// Create your new message part
BodyPart messageBodyPart = new MimeBodyPart();
String htmlText ="<H1>Hello</H1>"+
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 image
messageBodyPart = new MimeBodyPart();
// Fetch the image and associate to part
DataSource fds = new FileDataSource(file);
messageBodyPart.setDataHandler(new DataHandler(fds));
messageBodyPart.setHeader("Content-ID","memememe");
// Add part to multi-part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with message
message.setContent(multipart);
- javamail详解
- JavaMail详解
- JavaMail详解
- JavaMail详解
- javamail详解
- javaMail 详解
- Javamail详解
- JavaMail详解
- javaMail详解
- JavaMail实例详解
- JavaMail API详解
- JavaMail API详解
- JavaMail API详解
- JavaMail API详解
- javamail api详解
- JavaMail API详解
- JavaMail API详解
- JavaMail API详解
- Java中static、final用法小结
- window.showModalDialog的基本用法
- Spring AOP详解
- json 解析
- Spring MVC PK Struts2
- javamail详解
- javamail 邮件发送
- iOS----NSClassFromString跟NSStringFromClass
- javamail发送邮件
- spring各种邮件发送
- Eclipse的版本命名
- Spring Quartz调度详细介绍
- hibernateTemplate.find查的list的…
- Web前端优化最佳实践及工具集锦