dyerac  
dyerac In Java
公告

日历
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567
统计
  • 随笔 - 36
  • 文章 - 10
  • 评论 - 94
  • 引用 - 0

导航

常用链接

留言簿(5)

随笔分类(49)

随笔档案(36)

文章分类(11)

文章档案(10)

相册

dyerac

搜索

  •  

积分与排名

  • 积分 - 78702
  • 排名 - 706

最新随笔

最新评论

阅读排行榜

评论排行榜

 
   作为企业级应用的JavaEE,邮件收发毫无疑问是其重要技术组成;在这方面,JavaMail库和Apache的通用电子邮件软件包给我们提供了两个选择.不过通用电子邮件库实际上是包裹在JavaMail外层的API,所以无论我们选择哪种API,都需要JavaMail库;我们可能还需要JavaBeans激活框架(JavaBeans Activation Framework(JAF)),该框架将负责处理关于邮件选项的更复杂的内容.由于通用电子邮件软件包并没有实现收取邮件的操作,在这里,我们暂且只讨论JavaMail的实现.

一.邮件的发送
  第一件要知道的事情是,你的SMTP服务器的主机名,它负责将您的邮件发送到外部世界的机器.一般来说这些服务器都符合命名习惯,比如,如果你的邮箱是acmilan@sina.com.cn,那么SMTP服务器的主机名则是smtp.sina.com.cn;另外也可以参考各大网站自己的说明.为了方便,下文中以网易邮箱为例.
  JavaMail使用了Session类的概念来保存诸如SMTP主机和认证的信息,主要想法是基于会话(Sessions)在Java虚拟机中可以被隔离,这可以阻止恶意代码窃取其他用户在其他会话中的信息,这些信息可能包括用户名和密码等认证信息.你所要发送的邮件将保存在一个Message对象中,而这个Message对象则是由你所构造的session实例来创建
  要得到一个特定的session对象,可以通过一下代码:
      //设置session的属性
      Properties pro = new Properties();
      pro.put("mail.transport.protocol", "smtp");
      pro.put("mail.smtp.auth", "true");
      pro.put("mail.smtp.host", "smtp.126.com");
      pro.put("mail.host", "126.com");
     
      //设置认证器
      PopupAuthenticator pop = new PopupAuthenticator();
      pop.performCheck("My Name", "My Password");//你的帐户和密码
     
      //得到session
      Session mailSession = Session.getInstance(pro, pop);
  要注意的是,为了避免垃圾邮件,大多数的smtp服务器需要认证,SMTP认证(SMTP AUTH)需要用户名和密码来发送邮件;因此,必须在session的初始化参数中设置一个认证者(Authenticator)来返回所需的认证证书,具体代码必须由自己来实现:
     class PopupAuthenticator extends Authenticator {
       String username = null;
       String password = null;
       public PopupAuthenticator() {}
       public PasswordAuthentication performCheck(String user, String pass) {
         username = user;
         password = pass;
         return getPasswordAuthentication();
        }
       protected PasswordAuthentication getPasswordAuthentication() {
         return new PasswordAuthentication(username, password);
        }
      }

  接着,就可以用之前得到的session来构造Message对象:
    Message msg = new MimeMessage(mailSession); 
  在使用会话创建了一个MimeMessage后,我们需要来填充这个消息.首先是设置表头信息,Message类定义了邮件系统中使用的属性,由名字-值对组成,使用这些名字-值可以指定邮件表头信息,Javamail提供了一系列api用于设置常见的邮件表头,其中在涉及地址的操作时,我们用InternetAddress来进行封装:
      msg.setFrom(new InternetAddress ("acmilan@126.com");
      msg.setSubject("Hello");
      msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("intermilan@126.com", false));
      msg.setText("I will beat u");
      msg.setSentDate(new Date());
      //发送消息
      Transport.send(msg);
  对Transport类的调用将会去查找适当的会话,并找出如何发送消息,尽管这样做看上去有些不直观。当我们完成这一步的时候,我们的邮件就已经发送出去了。此时,我们还需要添加代码来捕获三种JavaMail可能抛出的异常,它们是AddressException、MessagingException和UnsupportedEncodingException. 但这就是最基本的使用JavaMail发送邮件的方法。
  有时候我们还需要给邮件添加附件.再回到之前对Message的讨论中,Message对象同样定义了邮件的内容,它可以定义一个消息内容,也可以定义多个消息内容,消息内容(通常指的是附件)都将由DataHandle下的类来处理.Message对象由Multipart组成,一个Multipart可含有多个BodyPart,这些BodyPart将用来保存文本信息和附件.
      MimeMultipart multipart = new MimeMultipart();
      BodyPart msgBodyPart = new MimeBodyPart();//用来放置文本内容
      msgBodyPart.setContent(message, "text/plain");
      BodyPart attBodyPart = new MimeBodyPart();//用来放置附件
      DataSource ds = new FileDataSource(new File("c:/td.txt"));
      attBodyPart.setDataHandler(new DataHandler(ds));//设置DataHandler
      attBodyPart.setFileName("bsbs.txt");//附件的显示名字
      multipart.addBodyPart(msgBodyPart);
      multipart.addBodyPart(attBodyPart);
      msg.setContent(multipart);
      Transport.send(msg);
   最后,我们来看看如何发送HTML格式的邮件,文本的格式必须相应的设置为text/html,邮件中的图片将以附件形式加载,另外还要指定一个内部ID以供调用;
      MimeMultipart multipart = new MimeMultipart();
      BodyPart msgBodyPart = new MimeBodyPart();
      //设置格式为"text/html"
      msgBodyPart.setContent("<H1>Hi! From HtmlJavaMail</H1> <img src=\"cid:logo\"/>", "text/html");
      BodyPart embedImage = new MimeBodyPart();
      DataSource ds = new URLDataSource(new URL("http://www.zdnet.com.cn/i/developer/images/builder_logo.gif"));
      embedImage.setDataHandler(new DataHandler(ds));
      //设置表头的内部ID,注意,所设置内容必须与前文对应,在此处,前文的引用为<img src=\"cid:logo\"/>,因此Content-ID表头对应
      //的应该是<logo>
      embedImage.setHeader("Content-ID", "<logo>");
      multipart.addBodyPart(msgBodyPart);
      multipart.addBodyPart(embedImage);
      msg.setContent(multipart);
   这样,一封HTML格式的邮件便完成了
      Transport.send(msg);


二.邮件的收取
  同样,第一步还是要获得服务器的名字.我们还是以网易为例.
  接收邮件包含两个协议,即POP3和IMAP。POP3是老协议,它提供一个单一收信箱,以存放一定顺序的邮件信息。IMAP相对比较新,它为邮件提供连接到一个层次关系的文件入口,其中一个入口即为收信箱。当然还有其它可以使用的协议,POP3和IMAP只是其中一种安全性很好的协议。JavaMail将这些协议提炼为一种邮件仓库(Store)的概念,这一仓库为文件等级的集合。这种提炼意味着仓库包含很多内容,但我们只需要弄清楚在一个服务文件夹中浏览与导航邮件信息的过程,而实际处理邮件协议的任务则通过JavaMail调用Provider来完成,不同的协议对应不同的provider。
  JavaMail的Provider操作服务于POP3和IMAP,你也可以将另外的Providers嵌入到JavaMail API以处理其它诸如NNTP或本地存储邮件的协议。在Sun主页上列出这方面的第三方Providers。
  在Javamail中,store和folder类是用来存储和接受消息.store由具体的session得到,它使用可带参数的connect方法与服务器连接,folder则和File有点类似,可以将其比作windows下的文件夹.客户由store类中取得folder,再对folder进行操作--进入特定的folder,读取folder中的消息.
     Session session;
     Store store = null;
     Folder folder = null;
     Folder inboxfolder = null;
    
     Properties props = System.getProperties();
     props.setProperty("mail.pop3s.rsetbeforequit", "true");//这样读取邮件时服务器不会删除原有的邮件
     props.setProperty("mail.pop3.rsetbeforequit", "true");
     session = Session.getInstance(props, null);

     store = session.getStore("pop3");//通过"pop3"得到适当的provider
     store.connect(emailserver, emailuser, emailpassword);
     folder = store.getDefaultFolder();//得到默认的顶级文件夹
  每一Folder可以包含很多其它的文件夹,通过getFolder方法来浏览特定文件夹。INBOX是邮件服务器表示的主文件夹保留的名称,pop3和imap存储都会提供一个INBOX文件夹.
     inboxfolder = folder.getFolder("INBOX");
     inboxfolder.open(Folder.READ_ONLY);//只读模式
     Message[] msgs = inboxfolder.getMessages();
  需要注意的是,此时真正的消息对象并没有存储到数组(msgs)中,数组保存的只是这些消息对象的引用,只有在调用了具体的Message.getXX()方法时,程序才会再次连接服务器并取得真正的结果.如果要进行对邮件的筛选工作,不停的调用每个消息对象的getXX方法无疑会影响性能.因此我们可以用FetchProfile类来预先抓取感兴趣的部分内容(如各表头内容),这就不需要每次调用getXX方法时都再连接服务器了.
     FetchProfile fp = new FetchProfile();
     fp.add("Subject");//即只读取主题信息
     inboxfolder.fetch(msgs, fp);//预读取每个消息的主题
     for (int j = 0 ;j <msgs.length; j++) {
        if (msgs[j].getSubject().startsWith("^_^")) {//只对标题为"^_^"的邮件进行操作
          .......
        }
  接下来,就可以调用Message的各种方法对邮件进行操作了.对不同格式的邮件,具体的操作当然也略微不同.一个做法是对每个具体的BodyPart进行操作,通过下列的递归方法可以获得每个BodyPart的引用
     private void extractPart(final Part part) throws MessagingException,IOException {
       if(part.getContent() instanceof Multipart) {
           Multipart mp=(Multipart)part.getContent();
           for (int i = 0; i < mp.getCount(); i++) {
               extractPart(mp.getBodyPart(i));
           }
      return;
    }
  Part的getContentType方法可以为我们对其采取何种方法处理提供依据
     part.getContentType().startsWith("text/plain").....
  如果是以"text/plain"或者"text/html"开头,通常我们可以直接取出其内容
    bodytext = (String) part.getContent();
  如果两者都不是,我们将其视之为附件,通过IO流来读取:
      InputStream in = part.getInputStream();//读取part中的附件
      ByteArrayOutputStream bos = new ByteArrayOutputStream();

      byte[] buffer = new byte[8192];
      int count = 0;
      while ( (count = in.read(buffer)) >= 0) {
        bos.write(buffer, 0, count);
      }
      in.close();
  接下来,就可以对流进行操作了.
  那么,关于Javamail的研究也就进行到这儿了.

参考文献:
  DJ Walker-Morgan          Getting the mail in: receiving in JavaMail
                                     Sending email in Java: There's more than one way
  赵强,乔新亮                   J2EE应用开发

posted on 2006-08-02 21:05 dyerac in java... 阅读(268) 评论(0)  编辑  收藏 所属分类: 原创文章学习笔记

只有注册用户登录后才能发表评论。


网站导航:
 
 
Copyright © dyerac in java... Powered by: 博客园 模板提供:沪江博客