Javamail详解

引用自http://blog.sina.com.cn/s/articlelist_1832656582_7_1.html

[JavaMail]1 基础

A、简介

JavaMail,顾名思义,提供给开发者处理电子邮件相关的编程接口。它是Sun发布的用来处理email的API。它可以方便地执行一些常用的邮件传输。我们可以基于JavaMail开发出类似于Microsoft Outlook的应用程序。

JavaMail包中用于处理电子邮件的核心类是:Session,Message,Address,Authenticator,Store,Transport, Folder等。Session定义了一个基本的邮件会话,它需要从Properties中读取类似于邮件服务器,用户名和密码等信息。

 

B、javaMail常用类

B .1、Properties

java.util.Properties:JavaMail需要Properties来创建一个session对象。它将寻找字符串mail.smtp.host,属性值就是发送邮件的主机,如:

   Properties props = new Properties ();

   props.put(mail.smtp.host, smtp.abcd.com);//可以换上你的smtp主机名。

B .2、Session

Javax.mail.Session:Session类定义了一个基本邮件会话(session),是Java Mail API最高层入口类。所有其它类都是经由这个session才得以生效。Session对象用Java.util.Properties对象获取信息,如邮件服务器、用户名、密码及整个应用程序中共享的其它信息。

这个Session类代表JavaMail中的一个邮件session。每一个基于JavaMail的应用程序至少有一个session但是可以有任意多的session。Session对象需要知道用来处理邮件的SMTP服务器。为了做到这一点,你可以参照下面的例子用Properties 来创建一个Session 对象

  Session sendMailSession;

  sendMailSession = Session.getInstance(props, null);

B .3、Message、MimeMessage

Javax.mail.Message、javax.mail.MimeMessage:一旦获得Session对象,就可以继续创建要发送的消息。这由Message类来完成。因为Message是个抽象类,必需用一个子类,多数情况下为 Javax.mail.internet.MimeMessage。MimeMessage是个能理解MIME类型和头的电子邮件消息,正如不同RFC中所定义的。虽然在某些头部域非ASCII字符也能被译码,但Message头只能被限制为用 US-ASCII 字符。

Message对象将存储我们实际发送的电子邮件信息,Message对象被作为一个MimeMessage对象来创建并且需要知道应当选择哪一个JavaMail session。

Message newMessage = new MimeMessage(sendMailSession);

B .4、Transport

Javax.mail.Transport:消息发送的最后一部分是使用Transport类。这个类用协议指定的语言发送消息(通常是SMTP)。它是抽象类,它的工作方式与Session有些类似。仅调用静态send() 方法,就能使用类的缺省版本:Transport.send(message)。或者,读者也可以从针对自己的协议的会话中获得一个特定的实例,传递用户名和密码(如果不必要就不传),发送消息,然后关闭连接。

邮件是既可以被发送也可以被受到。JavaMail使用了两个不同的类来完成这两个功能:Transport和Store。Transport是用来发送信息的,而Store用来收信。

  Transport transport;

  transport = sendMailSession.getTransport(smtp);

用JavaMail Session对象的getTransport方法来初始化Transport。传过去的字符串申明了对象所要使用的协议,如smtp。这将为我们省了很多时间。因为JavaMail以境内置了很多协议的实现方法。

注意: JavaMail并不是绝对支持每一个协议,目前支持IMAP、 SMTP和 POP3。

B .5、Store

Javax.mail.Store:Store类实现特定邮件协议上的读、写、监视、查找等操作。通过Javax.mail.Store类可以访问Javax.mail.Folder类。

Store store=s.getSorte(pop3);

store.connect(popserver,username,password);

B .6、Folder

Javax.mail.Folder:Folder类用于分级组织邮件,并提供照Javax.mail.Message格式访问email的能力。

Folder folder=store.getFolder(INBOX);

folder.open(Folder.READ_ONLY);

B .7、Address、InternetAddress

Javax.mail.Address、Javax.mail.internet.InternetAddress:一旦您创建了Session 和 Message,并将内容填入消息后,就可以用 Address 确定信件地址了。和 Message 一样,Address 也是个抽象类。您用的是 Javax.mail.internet.InternetAddress 类。

B .8、Authenticator

Javax.mail. Authenticator:与 Java.net 类一样,JavaMail API 也可以利用 Authenticator 通过用户名和密码访问受保护的资源。对于JavaMail API来说,这些资源就是邮件服务器。JavaMail Authenticator在Javax.mail包中,而且它和Java.net中同名的类Authenticator不同。两者并不共享同一个Authenticator,因为JavaMail API 用于Java 1.1,它没有 Java.net 类别。

要使用 Authenticator,先创建一个抽象类的子类,并从 getPasswordAuthentication() 方法中返回 PasswordAuthentication 实例。创建完成后,您必需向 session 注册 Authenticator。然后,在需要认证的时候,就会通知 Authenticator。您可以弹出窗口,也可以从配置文件中(虽然没有加密是不安全的)读取用户名和密码,将它们作为 PasswordAuthentication 对象返回给调用程序。

B .9、Multipart、MimeMultpart

javax.mail.Multipart、javax.mail.Internet.MimeMultpart:一般保存电子邮件内容的容器是Multipart抽象类,它定义了增加和删除及获得电子邮件不同部分内容的方法。由于Multipart是抽象类,我们必须为它使用一个具体的子类,JavaMail API提供javax.mail.Internet.MimeMultpart类来使用MimeMessage对象。

         MimeMultipart multipart=new MimeMultipart();

注:我们使用MimeMultipart对象的一个方法是addBodyPart(),它在我们的电子邮件内容里添加BodyPart对象。消息可以有很多部分,一个BodyPart可以代表一个部分。

B .10、BodyPart 、MimeBodyPart

javax.mail.BodyPart、javax.mail.Internet.MimeBodyPart:MimeBodyPart是BodyPart具体用于mimeMessage的一个子类。MimeBodyPart对象代表一个MimeMessage对象内容的一部分。每个MimeBodyPart被认为有两部分:MIME类型和匹配这个类型的内容

MimeBodyPart mdp=new MimeBodyPart();

String text=Hello JavaMail!;

mdp.setContent(text,text/plain);

//定义MIME类型为text/plain,并设置MimeBodyPart的内容

 

C、应用

C.1、通过SMTP发送一封邮件

package com.test;

 

import java.util.Date;

import java.util.Properties;

import javax.mail.Message;

import javax.mail.Multipart;

import javax.mail.Session;

import javax.mail.Transport;

import javax.mail.internet.InternetAddress;

import javax.mail.internet.MimeBodyPart;

import javax.mail.internet.MimeMessage;

import javax.mail.internet.MimeMultipart;

 

public class SimpleSender {

 

    public static void main(String args[]) {

 

       try {

           String smtpServer = 192.168.1.254;

           String to =  jizhou@xxxx.com ;

           String from =  lijy@xxxx.com ;

           String subject =  test mail ;

           String body =  test mail ;

String msgAttachment =  This is an attachment string! ;
           send(smtpServer, to, from, subject, body, msgAttachment);          } catch (Exception ex) {

           System.out.println(ex.toString());

       }

       System.exit(0);

    }

 

    // 发送一封简单的邮件

    public static void send(String smtpServer, String to, String from,

           String subject, String body) {

       try {

           Properties props = System.getProperties();//属性封装

           props.put( mail.smtp.host , smtpServer);

           Session session = Session.getDefaultInstance(props, null);//建立会话

           Message msg = new MimeMessage(session);//生成消息体

           msg.setFrom(new InternetAddress(from));

           // 发件人地址
           InternetAddress[] address = { new InternetAddress(to) };

           msg.setRecipients(Message.RecipientType.TO, address);

           // 收件人地址,可以是一个或多个。
           msg.setSubject(subject);

           // 邮件主题
           msg.setSentDate(new Date());

           // 发送时间
           msg.setText(body);

           // 邮件正文的内容
           msg.setHeader( X-Mailer ,  LOTONtechEmail );

           Transport.send(msg);//利用消息发送message
           System.out.println( Message sent OK. );

       } catch (Exception ex) {

           ex.printStackTrace();

       }

    }

 

    // 发送一封带有附件的邮件

    public static void send(String smtpServer, String to, String from,

           String subject, String body, String msgAttachment) {

       try {

           Properties props = System.getProperties();

           props.put( mail.smtp.host , smtpServer);

           Session session = Session.getDefaultInstance(props, null);

           Message msg = new MimeMessage(session);

           msg.setFrom(new InternetAddress(from));

           InternetAddress[] address = { new InternetAddress(to) };

           msg.setRecipients(Message.RecipientType.TO, address);

           msg.setSubject(subject);

           msg.setSentDate(new Date());

           msg.setHeader( X-Mailer ,  LOTONtechEmail );

           MimeBodyPart mbp1 = new MimeBodyPart();

           mbp1.setText(body);

           // 把前面定义的msgText中的文字设定为邮件正文的内容
           MimeBodyPart mbp2 = new MimeBodyPart();
           mbp2.setText(msgAttachment,  utf-8 );

           // 创建附件部分
           Multipart mp = new MimeMultipart();

           // 创建Multipart
           mp.addBodyPart(mbp1);

           mp.addBodyPart(mbp2);

           // 把前面定义的正文和附件都添加到Multipart中
           msg.setContent(mp);

           // 添加 Multipart到Message中
           Transport.send(msg);

           System.out.println( Message sent OK. );

       } catch (Exception ex) {

           ex.printStackTrace();

       }

    }

}

[JavaMail]2 身份验证

A、原理

Authenticator

Authenticator (Javax.mail.Authenticator):JavaMail利用Authenticator通过用户名和密码访问受保护的资源。对于JavaMail API来说,这些资源就是邮件服务器。

要使用Authenticator,先创建一个抽象类的子类(extends Authenticator),在子类中覆盖父类中的 getPasswordAuthentication() 方法,就可以实现以不同的方式来进行登录邮箱时的用户身份认证。JavaMail 中的这种设计是使用了策略模式(Strategy),具体的请参看相关文章。创建完成后,您必需向session注册Authenticator。然后,在需要认证的时候,就会通知Authenticator。

 

B、应用

下面例子,我们设计了一种简单的 SimpleAuthenticator 子类通过构造函数传入用户名和密码,而另一种 GUIAuthenticator 子类则使用 GUI 界面的形式进行身份认证,它可以使得程序在运行时弹出输入对话框来让用户提交用户名和密码。

package com.test;

 

import java.util.Date;

import java.util.Properties;

import java.util.StringTokenizer;

import javax.mail.Authenticator;

import javax.mail.PasswordAuthentication;

import javax.mail.Session;

import javax.mail.Transport;

import javax.mail.internet.InternetAddress;

import javax.mail.internet.MimeMessage;

import javax.mail.internet.MimeMessage.RecipientType;

import javax.swing.JOptionPane;

 

// 创建抽象类Authenticator的子类,SimpleAuthenticator通过构造函数传入身份验证信息 

class SimpleAuthenticator extends Authenticator {

    private String user;

    private String pwd;

 

    public SimpleAuthenticator(String user, String pwd) {

       this.user = user;

       this.pwd = pwd;

    }

 

    @Override

    protected PasswordAuthentication getPasswordAuthentication() {

       return new PasswordAuthentication(user, pwd);

    }

}

 

// 通过弹出输入对话框传入身份验证信息

class GUIAuthenticator extends Authenticator {

    @Override

    protected PasswordAuthentication getPasswordAuthentication() {

       String user;

       String pwd;

       // 弹出输入对话框

       String result = JOptionPane.showInputDialog( 请输入用户名和密码,以','隔开! );

       StringTokenizer st = new StringTokenizer(result,  , );

       user = st.nextToken();

       pwd = st.nextToken();

       return new PasswordAuthentication(user, pwd);

    }

}

 

public class UseAuthenticatorSender {

    private String smtpServer =  192.168.1.254 ;

    private String from =  lijy@xxxx.com ;

    private String to =  jizhou@xxx.com ;

    private String subject =  使用Authenticator子类进行用户身份认证 ;

    private String body =  使用Authenticator子类进行用户身份认证的测试! ;

 

    public void sendMails(Authenticator auth) throws Exception {

       // 设置协议、是否身份验证、服务器等信息
       Properties props = new Properties();

       props.setProperty( mail.transport.protocol ,  smtp );

       // 指定发送邮件协议
       props.setProperty( mail.smtp.auth ,  true );

       // 向SMTP服务器提交用户认证
       props.setProperty( mail.host , smtpServer);

       // SMTP服务器主机地址
       Session session = Session.getInstance(props, auth);

       // 通过传入的参数获得Authenticator子类对
       session.setDebug(true);

       // 调试模式
       MimeMessage msg = new MimeMessage(session);

       msg.setFrom(new InternetAddress(from));

       msg.setRecipient(RecipientType.BCC, new InternetAddress(to));

       msg.setSubject(subject);

       msg.setSentDate(new Date());

       msg.setText(body);

       msg.saveChanges();


       Transport.send(msg);

    }

 

    public static void main(String[] args) throws Exception {

       UseAuthenticatorSender sender = new UseAuthenticatorSender();

       // 这里体现了使用策略模式的好处,客户端可以选择使用

       // 具体的哪一种身份验证方式来提交信息

       // Authenticator auth = new SimpleAuthenticator( xxx ,  xxxx );

       Authenticator auth = new GUIAuthenticator();

       sender.sendMails(auth);

    }

}

[JavaMail]3 接收、处理邮件

A、原理

接收邮件可以应用协议(POP3或IMAP)。

A.1、接收邮件过程

参考下面例子中showMessages()

1.Store(Javax.mail.Store)

接收邮件和发送邮件很类似都要用到Session。但是在获得Session后,我们需要从Session中获取特定类型的Store,然后连接到Store,这里的Store代表了存储邮件的邮件服务器。在连接Store的过程中,极有可能需要用到用户名、密码或者Authenticator。

Store store = session.getStore( imap );

Store store = session.getStore( pop3 );

store.connect(host, username, password);

2.Folder(Javax.mail.Folder)

在连接到Store后,一个Folder对象即目录对象将通过Store的getFolder()方法被返回,我们可从这个Folder中读取邮件信息:

Folder folder = store.getFolder( INBOX );

folder.open(Folder.READ_ONLY);

上面的例子首先从Store中获得INBOX这个Folder(对于POP3协议只有一个名为INBOX的Folder有效),然后以只读(Folder.READ_ONLY)的方式打开Folder,

注意:对于POP3协议只有一个名为INBOX的Folder有效,而对于IMAP协议,我们可以访问多个Folder。

3.Message (Javax.mail.Message)

最后调用Folder的getMessages()方法得到目录中所有Message的数组。

Message message[] = folder.getMessages();

Folder的getMessages()方法时采取了很智能的方式:首先接收新邮件列表,然后再需要的时候(比如读取邮件内容)才从邮件服务器读取邮件内容。在读取邮件时,我们可以用Message类的getContent()方法接收邮件或是writeTo()方法将邮件保存,getContent()方法只接收邮件内容(不包含邮件头),而writeTo()方法将包括邮件头。

((MimeMessage)message).getContent();

4.关闭连接

在读取邮件内容后,别忘记了关闭Folder和Store。

folder.close(Boolean);

store.close();

传递给Folder.close()方法的boolean 类型参数表示是否在删除操作邮件后更新Folder。

A.2、查看邮件数、新邮件和未读邮件

参考下面例子中showFolderInfo()

想知道邮箱中共有多少邮件、有多少邮件读过和有多少邮件没有读过。

Folder对象提供了三个方法。GetMessageCount方法显示邮箱中总共有多少封信,getNewMessageCount显示邮箱中新邮件的封数,getUnreadMessageCount显示邮箱中未读邮件的封数。

注意:对于POP3协议,只支持GetMessageCount查询邮件总数。不支持判断邮件的未读和新邮件标记,只有自己进行判断操作了。

A.3、消息标识(删除邮件)

消息的删除涉及使用与消息相关的 Flags(标志)。不同 flag 对应不同的状态,有些由系统定义而有些则由用户定义。下面列出在内部类 Flags.Flag 中预定义的标志:

    * Flags.Flag.ANSWERED

    * Flags.Flag.DELETED

    * Flags.Flag.DRAFT

    * Flags.Flag.FLAGGED

    * Flags.Flag.RECENT

    * Flags.Flag.SEEN

    * Flags.Flag.USER

 

仅仅因为存在一个标志,并不意味着所有邮件服务器或供应商都支持这个标志。例如,除了删除消息标志外,POP 协议不再支持其它任何标志。检查是否存在新邮件,这也不是个POP任务,而是内建于邮件客户机的任务。为找出哪些标志能被支持,可以用 getPermanentFlags() 向 folder 提出要求。

消息标识的应用删除邮件

参考下面例子中deleteMessage()

要删除消息,您可以设置消息的 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() 检查。

A.4、复制或移动邮件

参考下面例子中moveMessage()

Folder类的copyMessages(Message[] msgs, Folder folder);方法可实现复制邮件的功能。参数msgs为你要复制的邮件数组。参数folder为你要复制的目的邮件箱。该操作是复制邮件,把原邮件删除,则实现移动邮件。

 

B、应用

package com.test;

 

import java.io.BufferedReader;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.util.Properties;

import javax.mail.Authenticator;

import javax.mail.Flags;

import javax.mail.Folder;

import javax.mail.Message;

import javax.mail.Multipart;

import javax.mail.Part;

import javax.mail.Session;

import javax.mail.Store;

import javax.mail.internet.InternetAddress;

 

public class TreatMessages {

    private String smtpServer =  192.168.1.254 ;

 

    // 连接Session

    private Session getSession() {

       Session session = null;

       try {

           Authenticator auth = new SimpleAuthenticator( xx ,  xx );

           // 身份验证,SimpleAuthenticator在UseAuthenticatorSender中定义。

           Properties props = new Properties();

           props.setProperty( mail.transport.protocol ,  smtp );

           props.setProperty( mail.smtp.auth ,  true );

           props.setProperty( mail.host , smtpServer);

           session = Session.getInstance(props, auth);

           // session.setDebug(true);

       } catch (Exception ex) {

           System.out.println(ex.toString());

       }

       return session;

    }

 

    // 显示所有邮件

    public void showMessages() {

       try {

           Session session = getSession();

           Store store = session.getStore( pop3 );

           store.connect();

           // 以pop3协议连接到Store。port:25

           Folder folder = null;

           folder = store.getDefaultFolder();

           if (folder == null)

              throw new Exception( No default folder );

           // 获取默认文件夹

           folder = folder.getFolder( INBOX );

           if (folder == null)

              throw new Exception( No POP3 INBOX );

           // 如果是收件箱

           folder.open(Folder.READ_WRITE);

           // 使用读写方式打开收件箱

           Message[] msgs = folder.getMessages();

           // 得到文件夹信息,获取邮件列表

           for (int msgNum = 0; msgNum < msgs.length; msgNum++) {

              printMessage(msgs[msgNum]);

           }

           // 显示所有邮件信息。

           folder.close(true);

           // 参数表示是否在删除操作邮件后更新Folder

           store.close();

           // 关闭store。

       } catch (Exception ex) {

           System.out.println(ex.toString());

       }

    }

 

    // 打印邮件信息

    public static void printMessage(Message message) {

       try {

           String from = ((InternetAddress) message.getFrom()[0])

                  .getPersonal();

           if (from == null)

from = ((InternetAddress) message.getFrom()[0]).getAddress();

           System.out.println( FROM:   + from);

           // 获得发送邮件地址

           String subject = message.getSubject();

           System.out.println( SUBJECT:   + subject);

           // 获取主题

           Part messagePart = message;

           Object content = messagePart.getContent();

           // 获取信息对象

           if (content instanceof Multipart) {

              messagePart = ((Multipart) content).getBodyPart(0);

              System.out.println( [ Multipart Message ] );

           }

           // 附件

           String contentType = messagePart.getContentType();

           System.out.println( CONTENT:  + contentType);

           // 获取content类型

           if (contentType.startsWith( text/plain )

                  || contentType.startsWith( text/html )) {

              InputStream is = messagePart.getInputStream();

              BufferedReader reader = new BufferedReader(

                     new InputStreamReader(is));

              String thisLine = reader.readLine();

              while (thisLine != null) {

                  System.out.println(thisLine);

                  thisLine = reader.readLine();

              }

           }

           // 如果邮件内容是纯文本或者是HTML,那么打印出信息

           System.out.println( ----------------------------- );

       } catch (Exception ex) {

           ex.printStackTrace();

       }

    }

 

    // 删除收件箱的第一封邮件

    public void deleteMessage() {

       try {

           Session session = getSession();

           Store store = session.getStore( pop3 );

           store.connect();

           Folder folder = null;

           folder = store.getDefaultFolder();

           if (folder == null)

              throw new Exception( No default folder );

           folder = folder.getFolder( INBOX );

           if (folder == null)

              throw new Exception( No POP3 INBOX );

           folder.open(Folder.READ_WRITE);

           Message[] msgs = folder.getMessages();

           Message message = msgs[0];

           // 获取第一封邮件

           message.setFlag(Flags.Flag.DELETED, true);

           if (message.isSet(Flags.Flag.DELETED))

              System.out.println( 这封信已被删除,请返回! );

           // 删除这一封邮件

           folder.close(true);

           // 参数表示是否在删除操作邮件后更新Folder

           store.close();

       } catch (Exception ex) {

           System.out.println(ex.toString());

       }

    }

 

// 以imap协议连接,显示邮箱状况

    public void showFolderInfo() {

       try {

           Session session = getSession();

           Store store = session.getStore( imap );

           // 以imap协议连接到Store,port:143。

// pop3不支持判断邮件的已读、未读和新邮件标记,只有自己进行判断操作。

           store.connect();

           Folder folder = null;

           folder = store.getDefaultFolder();

           if (folder == null)

               throw new Exception( No default folder );

           folder = folder.getFolder( INBOX );

           if (folder == null)

              throw new Exception( No POP3 INBOX );

           folder.open(Folder.READ_ONLY);

           // 以只读方式打开邮件夹

           int numberOfTotal = folder.getMessageCount();

           // 取得邮箱中总共有多少封信

           int numberOfUnread = folder.getUnreadMessageCount();

           // 取得邮箱中未读邮件

           int numberOfNew = folder.getNewMessageCount();

           // 取得邮箱中新邮件

           System.out.println( 您的邮箱中共有  + numberOfTotal

+  封邮件,其中有 + numberOfUnread +  封未读邮件 

+  ,有  + numberOfNew +  封新邮件 );

           folder.close(true);

           store.close();

       } catch (Exception ex) {

           System.out.println(ex.toString());

       }

    }

 

// 移动邮件

    public void moveMessage() {

       try {

           Session session = getSession();

           Store store = null;

           IMAPFolder folder = null;

           Folder to_folder = null;

           // 获取存储

           store = session.getStore( imap );

           // 连接邮箱服务器

           store.connect();

           // 获取收件箱文件夹

           folder = (IMAPFolder) store.getFolder( INBOX );

           // 以可读可写方式打开邮箱文件夹

           folder.open(Folder.READ_WRITE);

           to_folder = store.getFolder( Trash );

           // 为了简单起见,移动第1封邮件

           Message[] messages = folder.getMessages();

           Message[] needCopyMsgs = new Message[1];

           needCopyMsgs[0] = messages[0];        

           // 将获取的邮件对象复制到其他文件夹中

           folder.copyMessages(needCopyMsgs, to_folder);

           // 移动意味着要把收件箱中原有的邮件删除

           messages[0].setFlag(Flags.Flag.DELETED, true);

           // 如果文件夹不为空且已经打开就将其关闭

           if (folder != null && folder.isOpen()) {

              folder.close(true);

           }

           // 如果其他文件夹不为空着将其关闭

           if (to_folder != null && to_folder.isOpen()) {

              to_folder.close(true);

           }

           // 如果存储为空且已经打开就将其关闭

           if (store != null && store.isConnected()) {

              store.close();

           }

 

       } catch (Exception ex) {

           System.out.println(ex.toString());

       }

    }

 

    public static void main(String[] args) throws Exception {

       TreatMessages treat = new TreatMessages();

       treat.showFolderInfo();

    }

}

[JavaMail]4 处理附件

A、原理

邮件中的附件,不得不说一说Multipart类,Multipart类是Message类的子类,提供了在邮件中加入附加的实现方法。一个多部分邮件是一个内容类型(content-type)被设置为multipart的Message对象。Multipart类是一个容器类,包含Bodypart类型的对象。Bodypart对象是一个Part接口的实例,它既包括一个新的Multipart容器对象,又包括一个DataHandler对象。

A.1、邮件附件操作需要用到的类

Multipart、MimeMultpart

javax.mail.Multipart、javax.mail.Internet.MimeMultpart:一般保存电子邮件内容的容器是Multipart抽象类,它定义了增加和删除及获得电子邮件不同部分内容的方法。由于Multipart是抽象类,我们必须为它使用一个具体的子类,JavaMail API提供javax.mail.Internet.MimeMultpart类来使用MimeMessage对象。

         MimeMultipart multipart=new MimeMultipart();

注:我们使用MimeMultipart对象的一个方法是addBodyPart(),它在我们的电子邮件内容里添加BodyPart对象。消息可以有很多部分,一个BodyPart可以代表一个部分。

BodyPart 、MimeBodyPart

javax.mail.BodyPart、javax.mail.Internet.MimeBodyPart:MimeBodyPart是BodyPart具体用于mimeMessage的一个子类。MimeBodyPart对象代表一个MimeMessage对象内容的一部分。每个MimeBodyPart被认为有两部分:MIME类型和匹配这个类型的内容

MimeBodyPart mdp=new MimeBodyPart();

String text= Hello JavaMail! ;

mdp.setContent(text, text/plain );

//定义MIME类型为text/plain,并设置MimeBodyPart的内容

DataHandler

javax.activation.DataHandler:JavaMail API不限制信息只为文本,任何形式的信息都可能作为MimeMessage的一部分。除了文本信息,作为文件附件包含在电子邮件信息的一部分是很普遍的。JavaMail API通过使用DataHandler对象,提供一个允许我们包含非文本BodyPart对象的简便方法。

         DataHandler dh=new DataHandler(text,type);

mdp.setDatahandler(dh);

//mdp是一个MimeBodyPart对象

FileDataSource

javax.activation.FileDataSource:一个FileDataSource对象可以表示本地文件和服务器可以直接访问的资源。一个本地文件可以通过创建一个新的MimeBodyPart对象附在一个mimeMessage对象上。

MimeBodyPart mdp=new MimeBodyPart();

FileDataSource fds=new FileDataSource( c:/exam.txt );

mdp.setDataHandler(new DataHandler(fds)); //设置数据源

URLDataSource

javax.activation.URLDataSource:远程资源,URL不会指向它们,由一个URLDataSource对象表示。一个远程资源可以通过创建一个新mimeBodyPart对象附在一个mimeMessage对象上(同FileDataSource差不多)。

URLDataSource uds=new URLDataSource( http://www.cnjsp.com/logo.gif );

//与FileDataSource唯一不同的是数据源的设置

A.2、应用说明

发送三种不同类型的附件

参考sendAttachment()

信件内容和附件都作为一个BodyPart添加到Multipart中。再把Multipart添加到Message中。

三种不同类型的附件为:

1.直接将所设文本内容加到自定义文件中作为附件发送

2.用本地上的文件作为附件

3.用远程文件作为附件

把邮件中附件下载下来

参考getAttachment()

邮件Message包括Header和Body两部分,用message.getContent()从Message中获得邮件的Body部分,邮件的Body部分是一个Multipart对象,由一个或多个Part对象组成,再Multipart.getBodyPart(i)获取Part对象,进行判断过后下载其中的附件。

 

B、应用

package com.test;

 

import java.io.FileOutputStream;

import java.io.InputStream;

import java.net.URL;

import java.util.Date;

import java.util.Properties;

import javax.activation.DataHandler;

import javax.activation.FileDataSource;

import javax.activation.URLDataSource;

import javax.mail.Authenticator;

import javax.mail.BodyPart;

import javax.mail.Folder;

import javax.mail.Message;

import javax.mail.Multipart;

import javax.mail.Part;

import javax.mail.Session;

import javax.mail.Store;

import javax.mail.Transport;

import javax.mail.internet.InternetAddress;

import javax.mail.internet.MimeBodyPart;

import javax.mail.internet.MimeMessage;

import javax.mail.internet.MimeMultipart;

 

public class TreatAttachment {

    private String smtpServer =  192.168.1.254 ;

    private String filePath= C:/ ;

   

    // 连接Session

    private Session getSession() {

       Session session = null;

       try {

           Authenticator auth = new SimpleAuthenticator( x ,  x );

           // 身份验证,SimpleAuthenticator在UseAuthenticatorSender中定义。

           Properties props = new Properties();

           props.setProperty( mail.transport.protocol ,  smtp );

           props.setProperty( mail.smtp.auth ,  true );

           props.setProperty( mail.host , smtpServer);

           session = Session.getInstance(props, auth);

           // session.setDebug(true);

       } catch (Exception ex) {

           System.out.println(ex.toString());

       }

       return session;

    }

 

    public void getAttachment() {

       try {

           Session session = getSession();

           Store store = session.getStore( pop3 );

           store.connect();

           Folder folder = null;

           folder = store.getDefaultFolder();

           if (folder == null)

              throw new Exception( No default folder );

           folder = folder.getFolder( INBOX );

           if (folder == null)

              throw new Exception( No POP3 INBOX );

           folder.open(Folder.READ_WRITE);

           Message[] messages = folder.getMessages();

           int n = 0;

           Message message = messages[n];

           // 为了简单起见,我默认第1封信为有附件的邮件

           Multipart mp = (Multipart) message.getContent();

           // 获取邮件内容,放到Multipart中

           int partCount = mp.getCount();

           // 从Multipart获取BodyPart的数量

           for (int i = 0; i < partCount; i++) {

              Part part = mp.getBodyPart(i);

              //从Multipart获取BodyPart

              storeFile(part);

           }

           folder.close(true);

           store.close();

       } catch (Exception ex) {

           System.out.println(ex.toString());

       }

    }

 

    //保存附件

    public void storeFile(Part part){

       try {

           if (part.isMimeType( text/plain )){

              System.out.println( This is plain text  );

           }else if (part.isMimeType( multipart

           BodyPart mdp = new MimeBodyPart();

           // 新建一个存放信件内容的BodyPart对象

           mdp.setContent(tcontent,  text/html;charset=gb2312 );

           // 给BodyPart对象设置内容和格式/编码方式

           mm.addBodyPart(mdp);

           // 将含有信件内容的BodyPart加入到MimeMultipart对象中

 

          

           mdp = new MimeBodyPart();

           // 新建一个存放附件的BodyPart

           DataHandler dh = new DataHandler( JavaMail附件测试 ,

                   text/plain;charset=gb2312 );

           // 新建一个DataHandler对象,并设置其内容和格式/编码方式

           mdp.setFileName( xxf.txt );

           // 加上这句将作为附件发送,否则将作为信件的文本内容

           mdp.setDataHandler(dh);

           // 给BodyPart对象设置内容为DataHandler

           mm.addBodyPart(mdp);

 

          

           mdp = new MimeBodyPart();

           FileDataSource fds = new FileDataSource( c:/passwd.xls );

           dh = new DataHandler(fds);

           mdp.setFileName( passwd.xls );

// 可以和原文件名不一致

           mdp.setDataHandler(dh);

           mm.addBodyPart(mdp);

 

          

           mdp = new MimeBodyPart();

           URLDataSource ur = new URLDataSource(

                  new URL( http://xx/1_01.gif ));

           // 注:这里用的参数只能为URL对象,不能为URL字串,

//在前面类介绍时有误(请谅解),这里纠正一下.

           dh = new DataHandler(ur);

           mdp.setFileName( 1_01.gif );

           mdp.setDataHandler(dh);

           mm.addBodyPart(mdp);

 

           msg.setContent(mm);

           // 把mm作为消息对象的内容, 添加到Message中。

           msg.saveChanges();

           Transport.send(msg);

           System.out.println( Message sent OK. );

       } catch (Exception ex) {

           ex.printStackTrace();

       }

    }

 

    public static void main(String[] args) throws Exception {

       TreatAttachment treat = new TreatAttachment();

       treat.getAttachment();

    }

 

}

[JavaMail]5 常用类详解

 1.Properties(属性对象)

由于JavaMail需要和邮件服务器进行通信,这就要求程序提供许多诸如服务器地址、端口、用户名、密码等信息,JavaMail通过Properties对象封装这些属性西信息。如下面的代码封装了两个属性信息:

    Properties props = new Properties();

    props.put( mail.smtp.host ,  smtp.sina.com.cn );

    props.put( mail.smtp.auth ,  true );

针对不同的的邮件协议,JavaMail规定了服务提供者必须支持一系列属性,下表是针对SMTP协议的一些常见属性(属性值都以String类型进行设置,属性类型栏仅表示属性是如何被解析的):

 

属性名

 

 

属性类型

 

 

说明

 

 

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连接超时时间,单位为毫秒,默认为永不超时

 

其他几个协议也有类似的一系列属性,如POP3的mail.pop3.host、mail.pop3.port以及IMAP的mail.imap.host、mail.imap.port等。

更详细的信息请查看com.sun.mail.smtp、com.sun.mail.pop3和com.sun.mail.imap这三个包的Javadoc:http://java.sun.com/products/javamail/javadocs/index.html。

2.Session(会话对象)

Session是一个很容易被误解的类,这归咎于混淆视听的类名。千万不要以为这里的Session像HttpSession一样代表真实的交互会话,但创建Session对象时,并没有对应的物理连接,它只不过是一对配置信息的集合。Session的主要作用包括两个方面:

         1.接收各种配置属性信息:通过Properties对象设置的属性信息;

2.初始化JavaMail环境:根据JavaMail的配置文件,初始化JavaMail环境,以便通过Session对象创建其他重要类的实例。

所以,如果把Session更名为Configure也许更容易理解一些。

Session通过JavaMail配置文件以及程序中设置的Properties对象构建一个邮件处理环境,后续的处理将在Session基础上进行。Session拥有多个静态工厂方法用于创建Session实例。getInstance方法

1.static Session getDefaultInstance(Properties props, Authenticator authenticator):当JVM中已经存在默认的Session实例中,直接返回这个实例,否则创建一个新的Session实例,并将其作为JVM中默认Session实例。这个API很诡异,我们将对它进行详细的讲解。由于这个默认Session实例可以被同一个JVM所有的代码访问到,而Session中本身又可能包括密码、用户名等敏感信息在内的所有属性信息,所以后续调用也必须传入和第一次相同的Authenticator实例,否则将抛出java.lang.SecurityException异常。如果第一次调用时Authenticator入参为null,则后续调用通过null的Authenticator入参或直接使用getDefaultInstance(Properties props)即可返回这个默认的Session实例。值得一提的是,虽然后续调用也会传入Properties,但新属性并不会起作用,如果希望采用新的属性值,则可以通过getDefaultInstance(Properties props)创建一个新的Session实例达到目的。Authenticator在这里承当了两个功能:首先,对JVM中默认Session实例进行认证保护,后续调用执行getDefaultInstance(Properties props, Authenticator authenticator)方法时必须和第一次一样;其次,在具体和邮件服务器交互时,又作为认证的信息;

2.static Session getDefaultInstance(Properties props):返回JVM中默认的Session实例,如果第一次创建Session未指定Authenticator入参,后续调用可以使用该访问获取Session;

3.static Session getInstance(Properties props, Authenticator authenticator):创建一个新的Session实例,它不会在JVM中被作为默认实例共享;

4.static Session getInstance(Properties props):根据相关属性创建一个新的Session实例,未使用安全认证信息;

       Session是JavaMail提供者配置文件以及设置属性信息的“容器”,Session本身不会和邮件服务器进行任何的通信。所以在一般情况下,我们仅需要通过getDefaultInstance()获取一个共享的Session实例就可以了,下面的代码创建了一个Session实例:

                   Properties props = System.getProperties();

props.setProperty( mail.transport.protocol ,  smtp );              …

Session session = Session.getDefaultInstance(props);

注意:要观察传到邮件服务器上的邮件命令,请用 session.setDebug(true) 设置调试标志。

3.Transport和Store(传输和存储)

邮件操作只有发送或接收两种处理方式,JavaMail将这两种不同操作描述为传输(javax.mail.Transport)和存储(javax.mail.Store),传输对应邮件的发送,而存储对应邮件的接收。

Session提供了几个用于创建Transport和Store实例的方法,在具体讲解这些方法之前,我们事先了解一下Session创建Transport和Store的内部机制。我们知道提供者在javamail.providers配置文件中为每一种支持的邮件协议定义了实现类,Session根据协议类型(stmp、pop3等)和邮件操作方式(传输和存储)这两个信息就可以定位到一个实例类上。比如,指定stmp协议和transport类型后,Session就会使用com.sun.mail.smtp.SMTPTransport实现类创建一个Transport实例,而指定pop3协议和store类型时,则会使用com.sun.mail.pop3.POP3Store实例类创建一个Store实例。Session提供了多个重载的getTransport()和getStore()方法,这些方法将根据Session中Properties属性设置情况进行工作,影响这两套方法工作的属性包括:

 

属性名

 

 

说明

 

 

mail.transport.protocol

 

 

默认的邮件传输协议,例如,smtp

 

 

mail.store.protocol

 

 

默认的存储邮件协议,例如:pop3

 

 

mail.host

 

 

默认的邮件服务地址,例如:192.168.67.1

 

 

mail.user

 

 

默认的登陆用户名,例如:zapldy

 

下面,我们再回头来了解Session的getTransport()和getStore()的重载方法。

Transport的getTransport()方法

1.Transport getTransport():当Session实例设置了mail.transport.protocol属性时,该方法返回对应的Transport实例,否则抛出javax.mail.NoSuchProviderException。

2.Transport getTransport(String protocol):如果Session没有设置mail.transport.protocol属性,可以通过该方法返回指定类型的Transport,如transport = session.getTransport(“smtp”)。

如果Session中未包含Authenticator,以上两方法创建的Transport实例和邮件服务器交互时必须显示提供用户名/密码的认证信息。如果Authenticator非空,则可以在和邮件服务器交互时被作为认证信息使用。

除了以上两种提供认证信息的方式外,Session还可以使用以下的方法为Transport提供认证信息。

3.Transport getTransport(URLName url):用户可以通过URLName入参指定邮件协议、邮件服务器、端口、用户名和密码信息,请看下面的代码:

URLName urln = new URLName(“smtp”, “smtp.sina.com.cn”, 25, null, “masterspring2”, “spring”);

Transport transport = session.getTransport(urln);

/ * 这里,指定了邮件协议为smtp,邮件服务器是smtp.sina.com.cn,端口为25,用户名/

* 密码为masterspring2/spring。*/

消息发送的最后一部分是使用  Transport 类。这个类用协议指定的语言发送消息(通常是 SMTP)。它是抽象类,它的工作方式与 Session 有些类似。仅调用静态 send() 方法,就能使用类的缺省版本:

Transport.send(message);

或者,您也可以从针对您的协议的会话中获得一个特定的实例,传递用户名和密码(如果不必要就不传),发送消息,然后关闭连接。

message.saveChanges();

Transport transport = session.getTransport( smtp );

transport.connect(host, username, password);

transport.sendMessage(message, message.getAllRecipients());

transport.close();

后面这种方法在您要发送多条消息时最好,因为它能保持邮件服务器在消息间的活动状态。基本send()机制为每个方法的调用设置与服务器独立的连接。

Store方法

用 Session 获取消息与发送消息开始很相似。但是,在 session 得到后,很可能使用用户名和密码或使用 Authenticator 连接到一个 Store。类似于 Transport ,您告知 Store 使用什么协议:

// 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。

4.Message(消息对象)

一旦获得Session对象,就可以继续创建要发送的消息。这由Message类来完成。因为 Message是个抽象类,您必需用一个子类,多数情况下为javax.mail.internet.MimeMessage。MimeMessage是个能理解MIME类型和头的电子邮件消息,正如不同RFC中所定义的。虽然在某些头部域非ASCII字符也能被译码,但Message头只能被限制为用US-ASCII字符。

要创建一个 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 );

5.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 );

需要为消息的 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 = 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 没有提供电子邮件地址有效性核查机制。虽然通过编程,自己能够扫描有效字符(如 RFC 822 中定义的)或验证邮件交换(mail exchange,MX)记录,但这些功能不属于 JavaMail API。

[JavaMail]6 常见问题

 1、javamail在tomcat中找不到类库。

Javamail中tomcat中使用,报java.lang.NoClassDefFoundError: javax/mail/MessagingException的错误。找不到javamail的类库。把javamail类库文件activation.jar 以及 mail.jar 放到TOMCAT_HOME/common/lib下,应该就搞定了!

[JavaMail]7 详解Address和RFC 822

 A、名称解释

RFC 822

  电子邮件的标准格式 (RFC 822)

  除了由一个Internet用户传递给另一个用户的信息之外,电子邮件中还必须包含附加的服务信息。SMTP服务器利用这些信息来传递邮件,而客户端的邮件接收软件则利用这些信息来对邮件进行分类。

  每封邮件都有两个部分:信头和主体。

  信头部分的字段可分为两类。一类是由你的电子邮件程序产生的,另一类是邮件通过SMTP服务器时被加上的。在所有被SMTP服务器加上的字段中,对我们而言最重要的是Message-Id字段。这个字段是由你传向的SMTP服务器加上的。这是一个唯一的ID号。你可用这个号码作为邮件的编号。

  下表列出了可由用户的邮件程序控制的信头字段。这并不意味着所有的字段都是必须的。实际上可以忽略形成信头这一步骤而只发送正文。让你的SMTP服务器为你加上最起码的必需字段。

  信头字段 目的

  From 邮件作者

  Sender 发信人

  Reply-To 回邮地址

  To 收信人地址

  CC 抄送:另一个收信人地址

  BCC 密送:收信人地址,但其它收信人看不到这个收信人的地址。

  Subject 主题

  Comments 备注

  Keywords 关键字,用来进一步搜索邮件

  In-Reply-To 被当前邮件回复的邮件的ID

  References 几乎同In-Reply-To一样

  Encrypted 加密邮件的加密类型

  Date 发信日期

 

B、Address

Javamail中关于Address的类共有3个类。分别是:

Javax.mail.Address (抽象基础类)

javax.mail.internet.InternetAddress (继承于Address)

javax.mail.internet.NewsAddress

 

B.1、Javax.mail.Address

抽象方法

abstract String getType()

Return a type string that identifies this address type.

返回Address的类型。若InternetAddress则返回rfc822。

abstract String toString()

         Return a String representation of this address object.

         返回表述Address对象的String。

 

B.2、javax.mail.internet.InternetAddress

这个类表示一个使用RFC822(电子邮件的标准格式)的Internet电子邮件地址。标准的地址的语法格式为personal name<user@host.domain>。

属性

String address

Email地址

String encodedPersonal

The RFC 2047 encoded version of the personal name.

String personal

         地址名称

对象方法

String toString()

Convert this address into a RFC 822 / RFC 2047 encoded address.

把Address转换成一个RFC822/ RFC2047编码的String。

String toUnicodeString()

Returns a properly formatted address (RFC 822 syntax) of Unicode characters.

返回一个Unicode字符格式的地址(RFC822语法)。

静态方法

1.转换

static String toString(Address[] addresses)

Convert the given array of InternetAddress objects into a comma separated sequence of address strings. The resulting string contains only US-ASCII characters, and hence is mail-safe.把一个InternetAddress 数组转换成一个由逗号分隔的地址字符串String(符合RFC822/ RFC2047)。这个String只能包含US_ASCII码。

static String toString(Address[] addresses, int used)

Convert the given array of InternetAddress objects into a comma separated sequence of address strings. The resulting string contains only US-ASCII characters, and hence is mail-safe.

The 'used' parameter specifies the number of character positions already taken up in the field into which the resulting address sequence string is to be inserted. It is used to determine the line-break positions in the resulting address sequence string.

used参数用于指定要被插入字符串的字符位置数。

2.解析

static InternetAddress[] parse(String addresslist)

Parse the given comma separated sequence of addresses into InternetAddress objects.

把一个由逗号分隔的地址字符串系列解析成InternetAddress数组。地址必须遵循RFC822中的语法。

static InternetAddress[] parse(String addresslist, boolean strict)

Parse the given sequence of addresses into InternetAddress objects. If strict is false, simple email addresses separated by spaces are also allowed. If strict is true, many (but not all) of the RFC822 syntax rules are enforced. In particular, even if strict is true, addresses composed of simple names (with no  @domain  part) are allowed. Such  illegal  addresses are not uncommon in real messages.

把一个地址字符串系列解析成InternetAddress数组。若strict是false,由空格分隔的简单邮件地址也是允许的。若strict是true,许多(但不是全部)RFC822语法规则将被执行。即使strict是true,若地址不包含(@域名)部分也是允许的。

没有strict参数的通常用于解析用户输入的邮件地址字符串

static InternetAddress[] parseHeader(String addresslist, boolean strict)

Parse the given sequence of addresses into InternetAddress objects.

把一个地址字符串系列解析成InternetAddress数组。若strict是false,个人地址的完整语法规则都不用执行。若strict是true,许多(但不是全部)RFC822语法规则将被执行。

为了更好的支持消息中的无效地址。若strict是false,此方法执行比parse(“xx”,false)还要少的语法规则。若strict是true,此方法执行比parse(“xx”,true)更多的语法规则。

3.获取当前用户地址

static InternetAddress    getLocalAddress(Session session)

Return an InternetAddress object representing the current user.

[JavaMail]8 详解Message和MIME

 A.0、MIME

Multipurpose Internet Mail Extension(多功能Internet 邮件扩充服务)

它是一种多用途网际邮件扩充协议,在1992年最早应用于电子邮件系统,但后来也应用到浏览器。服务器会将它们发送的多媒体数据的类型告诉浏览器,而通知手段就是说明该多媒体数据的MIME类型,从而让浏览器知道接收到的信息哪些是MP3文件,哪些是Shockwave文件等等。服务器将MIME标志符放入传送的数据中来告诉浏览器使用哪种插件读取相关文件。

MIME能够支持非ASCII字符、二进制格式附件等多种格式的邮件消息。这个标准被定义在; RFC 2045,; RFC 2046,; RFC 2047,; RFC 2048,; RFC 2049等RFC中。 由RFC 822转变而来的RFC 2822,规定电子邮件标准并不允许在邮件消息中使用7位ASCII字符集以外的字符。正因如此,一些非英语字符消息和二进制文件,图像,声音等非文字消息都不能在电子邮件中传输。MIME规定了用于表示各种各样的数据类型的符号化方法。

MIME意为多功能Internet邮件扩展,它设计的最初目的是为了在发送电子邮件时附加多媒体数据,让邮件客户程序能根据其类型进行处理。然而当它被HTTP协议支持之后,它的意义就更为显著了。它使得HTTP传输的不仅是普通的文本,而变得丰富多彩。

由于MIME类型与文档的后缀相关,因此服务器使用文档的后缀来区分不同文件的MIME类型,服务器中必须定义文档后缀和MIME类型之间的对应关系。而客户程序从服务器上接收数据的时候,它只是从服务器接受数据流,并不了解文档的名字,因此服务器必须使用附加信息来告诉客户程序数据的MIME类型。服务器在发送真正的数据之前,就要先发送标志数据的MIME类型的信息,这个信息使用Content-type关键字进行定义,例如对于HTML文档,服务器将首先发送以下(Content-type: text/html)MIME标识信息,这个标识并不是真正的数据文件的一部分。

MIME利用了一个事实就是,RFC 822在消息体的内容中做了一点限制:唯一的限制就是只能使用简单的ASCII文本。所以,MIME信息由正常的Internet文本邮件组成,文本邮件拥有一些特别的符合RFC 822的信息头和格式化过的信息体(用ASCII 的子集来表示的附件)。这些MIME头给出了一种在邮件中表示附件的特别的方法。

A.1、MIME信息的剖析

  一个普通的文本邮件的信息包含一个头部分(To: From: Subject: 等等)和一个体部分(Hello Mr.,等等)。邮件的各个部分叫做MIME段,每段前也缀以一个特别的头。MIME邮件只是基于RFC 822邮件的一个扩展,然而它有着自己的RFC规范集。

头字段

  MIME头根据在邮件包中的位置,大体上分为MIME信息头和MIME段头。(译者:MIME信息头指整个邮件的头,而MIME段头只每个MIME段的头。)

MIME信息头

  0.MIME-Version:

  这个头提供了所用MIME的版本号。这个值习惯上为1.0。

  1.Content-Type:

它定义了数据的类型,以便数据能被适当的处理。有效的类型有:text,image,audio,video, applications,multipart和message。注意任何一个二进制附件都应该被叫做application/octet- stream。这个头的一些用例为:image/jpg, application/mswork,multipart/mixed,这只是很少的一部分。

2.Content-ID:

  如果Content-Type是message/external-body或multipart/alternative时,这个头就有用了,它超出了本文的范围。

3.Content-MD5

4.Content- Language

5.Content-Description:

  这是一个可选的头。它是任何信息段内容的自由文本描述。描述必须使用us-ascii码。

  6.Content-Disposition:

一个试验性的头,它用于给客户程序/MUA提供提示,来决定是否在行内显示附件或作为单独的附件。

  7.Content-Transfer-Encoding:

这是所有头中最重要的一个,因为它说明了对数据所执行的编码方式,客户/MUA 将用它对附件进行解码。对于每个附件,可以使用7bit,8bit,binary ,quoted-printable,base64和x-encodingname中的一种编码方式。

7bit

7bit这里指的是7位的ASCII编码方式。编码是用在US ASCII字符集上的常用的一种编码方式,也就是,保持它的原样。

8bit

8位元ASCII码。

binary

binary编码一般不用。

quoted printable

因为欧洲的一些文字和ASCII字符集中的某些字符有部分相同。如果邮件消息使用的是这些语言的话,于ASCII重叠的那些字符可以原样使用,ASCII字符集中不存在的字符采用形如“=??”的方法编码。这里“??”需要用将字符编码后的16进制数字来指定。采用quoted-printable编码的消息,长度不会变得太长,而且大部分都是ASCII中的字符,即使不通过解码也大致可以读懂消息的内容。

base64

base64是一种将二进制的01序列转化成ASCII字符的编码方法。编码后的文本或者二进制消息,就可以运用SMTP等只支持ASCII字符的协议传送了。Base64一般被认为会平均增加33%的报文长度,而且,经过编码的消息对于人类来说是不可读的。

x-encodingname

这个值是预留的扩展。

8.Date

发信日期

9.From

邮件作者

10.Sender

发信人

11.Reply-To

回邮地址

12. To CC BCC

To 收信人地址

  CC 抄送:另一个收信人地址

BCC 密送:收信人地址,但其它收信人看不到这个收信人的地址。

13.Subject

主题

14.Message-ID

MIME段头

  MIME段头(出现在实际的MIME附件部分的头),除了MIME-Version头,可以拥有以上任何头字段。如果一个MIME头是信息块的一部分,它将作用于整个信息体。例如,如果Content-Transfer-Encoding显示在信息(指整个信息)头中,它应用于整个信息体,但是如果它显示在一个MIME段里,它 只能 用于那个段中。

 

B、Message

javax.mail.Part (基础接口)

public interface Part

Part是Message和BodyParts的基础接口。Part一组由attribute和Content组成。

Attribute

JavaMail定义了一组标准属性,大多数现有的邮件服务器都支持。这些属性都有set和get方法存取。其他非标准属性用setHeader()和getHeader()存取。

Content

Part中的Content存在以下格式,DataHandler,input stream,Java object。

DataHandler通过getDataHandler()获取,DataHandler对象允许客户发现在content上的有效方法,然后实例化合适的组件来执行这些操作。

input stream通过getInputStream()获取,在取得input stream之前,所有邮件格式编码

已经被解析。

Java object通过getContent()获取,返回对象可能是一个多Multipart对象。

javax.mail.internet. MimePart (继承于Part)

public interface MimePart extends Part

添加对RFC822 RFC2045 MIME的支持。

javax.mail.Message (抽象基础类)

public abstract class Message implements Part

javax.mail.internet.MimeMessage (继承于Message)

         public class MimeMessage extends Message implements MimePart

 

B.1、javax.mail.Part

方法

boolean    isMimeType(String mimeType)

Is this Part of the specified MIME type? This method compares only the primaryType and subType.

判断Part是否是指定的MIME类型,此法方法只判断主类型和子类型。内容参数将被忽略。如:但用isMimeType( text/plain”);比较 text/plain; charset=foobar .时,将返回true。当子类型使用特殊字符”*”时,子类型的比较也将被忽略。

 

B.2、javax.mail.Message

Messages是一个抽象类,它实现接口Part,并定义了一些属性。Message可以从Folder取得或由MimeMessage创建。在Folder中的Message有一组flags来表明它在Folder中的状态。

属性

protected  boolean        expunged

True if this message has been expunged.

True表示message已经被除去。

protected  Folder  folder

The containing folder, if this message is obtained from a folder

若message由folder取得,则表示对应的folder。

protected  int         msgnum

The number of this message within its folder, or zero if the message was not retrieved from a folder.

表示message在folder中的位置,0表示message不在folder中。在文件中第一个邮件为1,依次递增。

protected  Session         session

The Session object for this Message

方法

操作msgnum属性的方法

对应邮件中的Form:邮件作者

int    getMessageNumber()

void  setMessageNumber(int msgnum)

B.2、javax.mail.internet.MimeMessage

这个类描述了一个MIME类型的email message,它实现了MimePart接口。客户想要创建一个MIME类型的message,必须先创建一个空的MimeMessage对象,再填充属性和容器。

属性

protected  byte[]   content

Byte array that holds the bytes of this Message's content.

message的容器,存储邮件正文和附件。

protected  InputStream         contentStream

If the data for this message was supplied by an InputStream that implements the SharedInputStream interface, contentStream is another such stream representing the content of this message.

protected  DataHandler        dh

The DataHandler object representing this Message's content.

protected  Flags    flags

The Flags for this message.

邮件的标记信息,如:被看过或被删除等。

protected  InternetHeaders headers

The InternetHeaders object that stores the header of this message.

存储message的head部分。

protected  boolean        modified

A flag indicating whether the message has been modified.

protected  boolean        saved

Does the saveChanges method need to be called on this message?

方法

1.       Content- Type

对应邮件头中的Content-Type:

String getContentType()

2.       Content-ID

对应邮件头中的Content-ID:

String getContentID()

        Returns the value of the  Content-ID  header field.

void  setContentID(String cid)

Set the  Content-ID  header field of this Message.

操作Content-ID属性的方法

3.       Content-MD5

对应邮件头中的Content-MD5:

String        getContentMD5()

void  setContentMD5(String md5)

4.       Content- Language

对应邮件头中的Content-Language:

String[]     getContentLanguage()

void  setContentLanguage(String[] languages)

5.       Content- Description

对应邮件头中的Content- Description:

String getDescription()

Returns the  Content-Description  header field of this Message.

void  setDescription(String description)

Set the  Content-Description  header field for this Message.

 void setDescription(String description, String charset)

Set the  Content-Description  header field for this Message.

6.       Content- Disposition

对应邮件头中的Content- Disposition:

String        getDisposition()

void  setDisposition(String disposition)

7.       Content- Transfer-Encoding

对应邮件头中的Content-Transfer-Encoding:

String getEncoding()

8.       Date

对应邮件头中的Date:发信日期

void  setSentDate(Date d)

Set the RFC 822  Date  header field.

Date         getSentDate()

Returns the value of the RFC 822  Date  field.

操作Date属性的方法

9.       Form

对应邮件头中的Form:邮件作者

void  addFrom(Address[] addresses)

Add the specified addresses to the existing  From  field.

Address[] getFrom()

Returns the value of the RFC 822  From  header fields.

void  setFrom()

Set the RFC 822  From  header field using the value of the InternetAddress.getLocalAddress method.

void  setFrom(Address address)

Set the RFC 822  From  header field.

操作Form属性的方法

10.   Sender

对应邮件中的Sender:发信人

void  setSender(Address address)

Set the RFC 822  Sender  header field.

Address getSender()

Returns the value of the RFC 822  Sender  header field.

操作Sender属性的方法

From和Sender

合法的信件头部必须包括  From:  行

合法的信件头部也许会包括  Sender:  行

如果信件即包括  From:  又包括  Sender: ,那么  Sender:  是发送者

如果信件包括  From:  但不包括  Sender: ,那么  From:  里面的第一个地址是发送者

如果信件不包括  From: ,那么这封信肯定不可能是 DomainKey 签名过的(包括有  Sender:  而无  From:  的情况)

11.   Reply-To

对应邮件中的Reply-To:回邮地址

void  set ReplyTo (Address address)

Address get ReplyTo ()

操作Reply-To属性的方法

12.   To CC BCC

对应邮件中的To:CC:BCC:

void  addRecipients(Message.RecipientType type, Address[] addresses)

Add the given addresses to the specified recipient type.

void  addRecipients(Message.RecipientType type, String addresses)

Add the given addresses to the specified recipient type.

Address[] getAllRecipients()

Get all the recipient addresses for the message.

Address[] getRecipients(Message.RecipientType type)

Returns the recepients specified by the type.

操作收件人属性的方法

13.   Subject

对应邮件头中的Subject:主题

void  setSubject(String subject)

Set the  Subject  header field.

void  setSubject(String subject, String charset)

Set the  Subject  header field.

String getSubject()

Returns the value of the  Subject  header field.

操作Subject属性的方法

编码规则

ncoded-word =  =?  charset  ?  encoding  ?  encoded-text  ?= 

charset:字符编码

encoding:

Q --- Quote Printable

B --- BASE64

U --- UUENCODE

例1: Subject: =?GB2312?Q?=C4=E3=BA=C3?=

例2: Subject: =?utf-7?B?WFgrWUNkU0swNE9kbjVPRVZiKy0z?=

14.   Message-ID

对应邮件头中的Message-ID:SMTP服务器加的唯一的ID号。可用这个号码作为邮件的编号。

String getMessageID()

Returns the value of the  Message-ID  header field.

取得Message-ID属性的方法

15.   操作Head的方法

String[]     getHeader(String name)

Get all the headers for this header_name.

获取指定名称的所有header。请注意,某些标题如果它们包含非US-ASCII字符则可能被编码为RFC 2047,这些应该被解码。

String        getHeader(String name, String delimiter)

Get all the headers for this header name, returned as a single String, with headers separated by the delimiter.

获取指定名称的所有header。返回一个由指定delimiter分隔的单一字符串。若delimiter是null,则只有第一个header被返回。

Enumeration    getAllHeaderLines()

Get all header lines as an Enumeration of Strings.

Enumeration    getAllHeaders()

Return all the headers from this Message as an enumeration of Header objects.

Enumeration    getMatchingHeaderLines(String[] names)

Get matching header lines as an Enumeration of Strings.

Enumeration    getMatchingHeaders(String[] names)

Return matching headers from this Message as an Enumeration of Header objects.

Enumeration    getNonMatchingHeaderLines(String[] names)

Get non-matching header lines as an Enumeration of Strings.

Enumeration    getNonMatchingHeaders(String[] names)

Return non-matching headers from this Message as an Enumeration of Header objects.

void  setHeader(String name, String value)

Set the value for this header_name.

void  addHeader(String name, String value)

Add this value to the existing values for this header_name.

void  addHeaderLine(String line)

Add a raw RFC 822 header-line.

void  removeHeader(String name)

Remove all headers with this name.

16.   取得邮件收到的时间

对应邮件头中第一行

Date         getReceivedDate()

Returns the Date on this message was received.

17.   操作邮件标记Flag的方法

Flags         getFlags()

Return a Flags object containing the flags for this message.

void  setFlags(Flags flag, boolean set)

Set the flags for this message.

boolean    isSet(Flags.Flag flag)

Check whether the flag specified in the flag argument is set in this message.

18.   取得邮件大小

int    getSize()

Return the size of the content of this message in bytes.

19.   回复

Message reply(boolean replyToAll)

Get a new Message suitable for a reply to this message.

返回一个Message用于回复这个邮件的。

20.   关联文件

String        getFileName()

Get the filename associated with this Message.

void  setFileName(String filename)

Set the filename associated with this part, if possible.

21.    

int    getLineCount()

Return the number of lines for the content of this message.

22.    

void  saveChanges()

Updates the appropriate header fields of this message to be consistent with the message's contents.

23.   操作Java Object类型的Content的方法

Object      getContent()

Return the content as a Java object.

InputStream    getInputStream()

Return a decoded input stream for this Message's  content .

void  setContent(Multipart mp)

This method sets the Message's content to a Multipart object.

void  setContent(Object o, String type)

A convenience method for setting this Message's content.

void  setText(String text)

Convenience method that sets the given String as this part's content, with a MIME type of  text/plain .

void  setText(String text, String charset)

Convenience method that sets the given String as this part's content, with a MIME type of  text/plain  and the specified charset.

void  setText(String text, String charset, String subtype)

Convenience method that sets the given String as this part's content, with a primary MIME type of  text  and the specified MIME subtype.

24.   操作DataHandler类型的Content的方法

DataHandler    getDataHandler()

Return a DataHandler for this Message's content.

void  setDataHandler(DataHandler dh)

This method provides the mechanism to set this part's content.

25.   操作Input Stream类型的Content的方法

InputStream getRawInputStream()

Return an InputStream to the raw data with any Content-Transfer-Encoding intact.

protected  void      parse(InputStream is)

Parse the InputStream setting the headers and content fields appropriately.

26.   输出attribute和content安全字节流

void  writeTo(OutputStream os)

Output the message as an RFC 822 format stream.

void  writeTo(OutputStream os, String[] ignoreList)

Output the message as an RFC 822 format stream, without specified headers.

 

C.1、常见的MIME类型

  超文本标记语言文本 .html text/html

  xml文档 .xml text/xml

  XHTML文档 .xhtml application/xhtml+xml

  普通文本 .txt text/plain

  RTF文本 .rtf application/rtf

  PDF文档 .pdf application/pdf

  Microsoft Word文件 .word application/msword

  PNG图像 .png image/png

  GIF图形 .gif image/gif

  JPEG图形 .jpeg,.jpg image/jpeg

  au声音文件 .au audio/basic

  MIDI音乐文件 mid,.midi audio/midi,audio/x-midi

  RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio

  MPEG文件 .mpg,.mpeg video/mpeg

  AVI文件 .avi video/x-msvideo

  GZIP文件 .gz application/x-gzip

  TAR文件 .tar application/x-tar

任意的二进制数据 application/octet-stream

C.2、MIME类型大全

格式前面为后辍名,后面为对应的MIME型(例如:rar application/x-rar-compressed 表示.RAR对应的是application/x-rar-compressed )

  application/vnd.lotus-1-2-3

  3gp video/3gpp

  aab application/x-authoware-bin

  aam application/x-authoware-map

  aas application/x-authoware-seg

  ai application/postscript

  aif audio/x-aiff

  aifc audio/x-aiff

  aiff audio/x-aiff

  als audio/X-Alpha5

  amc application/x-mpeg

  ani application/octet-stream

  asc text/plain

  asd application/astound

  asf video/x-ms-asf

  asn application/astound

  asp application/x-asap

  asx video/x-ms-asf

  au audio/basic

  avb application/octet-stream

  avi video/x-msvideo

  awb audio/amr-wb

  bcpio application/x-bcpio

  bin application/octet-stream

  bld application/bld

  bld2 application/bld2

  bmp application/x-MS-bmp

  bpk application/octet-stream

  bz2 application/x-bzip2

  cal image/x-cals

  ccn application/x-cnc

  cco application/x-cocoa

  cdf application/x-netcdf

  cgi magnus-internal/cgi

  chat application/x-chat

  class application/octet-stream

  clp application/x-msclip

  cmx application/x-cmx

  co application/x-cult3d-object

  cod image/cis-cod

  cpio application/x-cpio

  cpt application/mac-compactpro

  crd application/x-mscardfile

  csh application/x-csh

  csm chemical/x-csml

  csml chemical/x-csml

  css text/css

  cur application/octet-stream

  dcm x-lml/x-evm

  dcr application/x-director

  dcx image/x-dcx

  dhtml text/html

  dir application/x-director

  dll application/octet-stream

  dmg application/octet-stream

  dms application/octet-stream

  doc application/msword

  dot application/x-dot

  dvi application/x-dvi

  dwf drawing/x-dwf

  dwg application/x-autocad

  dxf application/x-autocad

  dxr application/x-director

  ebk application/x-expandedbook

  emb chemical/x-embl-dl-nucleotide

  embl chemical/x-embl-dl-nucleotide

  eps application/postscript

  epub application/epub+zip

  eri image/x-eri

  es audio/echospeech

  esl audio/echospeech

  etc application/x-earthtime

  etx text/x-setext

  evm x-lml/x-evm

  evy application/x-envoy

  exe application/octet-stream

  fh4 image/x-freehand

  fh5 image/x-freehand

  fhc image/x-freehand

  fif image/fif

  fm application/x-maker

  fpx image/x-fpx

  fvi video/isivideo

  gau chemical/x-gaussian-input

  gca application/x-gca-compressed

  gdb x-lml/x-gdb

  gif image/gif

  gps application/x-gps

  gtar application/x-gtar

  gz application/x-gzip

  hdf application/x-hdf

  hdm text/x-hdml

  hdml text/x-hdml

  hlp application/winhlp

  hqx application/mac-binhex40

  htm text/html

  html text/html

  hts text/html

  ice x-conference/x-cooltalk

  ico application/octet-stream

  ief image/ief

  ifm image/gif

  ifs image/ifs

  imy audio/melody

  ins application/x-NET-Install

  ips application/x-ipscript

  ipx application/x-ipix

  it audio/x-mod

  itz audio/x-mod

  ivr i-world/i-vrml

  j2k image/j2k

  jad text/vnd.sun.j2me.app-descriptor

  jam application/x-jam

  jar application/java-archive

  jnlp application/x-java-jnlp-file

  jpe image/jpeg

  jpeg image/jpeg

  jpg image/jpeg

  jpz image/jpeg

  js application/x-javascript

  jwc application/jwc

  kjx application/x-kjx

  lak x-lml/x-lak

  latex application/x-latex

  lcc application/fastman

  lcl application/x-digitalloca

  lcr application/x-digitalloca

  lgh application/lgh

  lha application/octet-stream

  lml x-lml/x-lml

  lmlpack x-lml/x-lmlpack

  lsf video/x-ms-asf

  lsx video/x-ms-asf

  lzh application/x-lzh

  m13 application/x-msmediaview

  m14 application/x-msmediaview

  m15 audio/x-mod

  m3u audio/x-mpegurl

  m3url audio/x-mpegurl

  ma1 audio/ma1

  ma2 audio/ma2

  ma3 audio/ma3

  ma5 audio/ma5

  man application/x-troff-man

  map magnus-internal/imagemap

  mbd application/mbedlet

  mct application/x-mascot

  mdb application/x-msaccess

  mdz audio/x-mod

  me application/x-troff-me

  mel text/x-vmel

  mi application/x-mif

  mid audio/midi

  midi audio/midi

  mif application/x-mif

  mil image/x-cals

  mio audio/x-mio

  mmf application/x-skt-lbs

  mng video/x-mng

  mny application/x-msmoney

  moc application/x-mocha

  mocha application/x-mocha

  mod audio/x-mod

  mof application/x-yumekara

  mol chemical/x-mdl-molfile

  mop chemical/x-mopac-input

  mov video/quicktime

  movie video/x-sgi-movie

  mp2 audio/x-mpeg

  mp3 audio/x-mpeg

  mp4 video/mp4

  mpc application/vnd.mpohun.certificate

  mpe video/mpeg

  mpeg video/mpeg

  mpg video/mpeg

  mpg4 video/mp4

  mpga audio/mpeg

  mpn application/vnd.mophun.application

  mpp application/vnd.ms-project

  mps application/x-mapserver

  mrl text/x-mrml

  mrm application/x-mrm

  ms application/x-troff-ms

  mts application/metastream

  mtx application/metastream

  mtz application/metastream

  mzv application/metastream

  nar application/zip

  nbmp image/nbmp

  nc application/x-netcdf

  ndb x-lml/x-ndb

  ndwn application/ndwn

  nif application/x-nif

  nmz application/x-scream

  nokia-op-logo image/vnd.nok-oplogo-color

  npx application/x-netfpx

  nsnd audio/nsnd

  nva application/x-neva1

  oda application/oda

  oom application/x-AtlasMate-Plugin

  pac audio/x-pac

  pae audio/x-epac

  pan application/x-pan

  pbm image/x-portable-bitmap

  pcx image/x-pcx

  pda image/x-pda

  pdb chemical/x-pdb

  pdf application/pdf

  pfr application/font-tdpfr

  pgm image/x-portable-graymap

  pict image/x-pict

  pm application/x-perl

  pmd application/x-pmd

  png image/png

  pnm image/x-portable-anymap

  pnz image/png

  pot application/vnd.ms-powerpoint

  ppm image/x-portable-pixmap

  pps application/vnd.ms-powerpoint

  ppt application/vnd.ms-powerpoint

  pqf application/x-cprplayer

  pqi application/cprplayer

  prc application/x-prc

  proxy application/x-ns-proxy-autoconfig

  ps application/postscript

  ptlk application/listenup

  pub application/x-mspublisher

  pvx video/x-pv-pvx

  qcp audio/vnd.qcelp

  qt video/quicktime

  qti image/x-quicktime

  qtif image/x-quicktime

  r3t text/vnd.rn-realtext3d

  ra audio/x-pn-realaudio

  ram audio/x-pn-realaudio

  rar application/octet-stream

  ras image/x-cmu-raster

  rdf application/rdf+xml

  rf image/vnd.rn-realflash

  rgb image/x-rgb

  rlf application/x-richlink

  rm audio/x-pn-realaudio

  rmf audio/x-rmf

  rmm audio/x-pn-realaudio

  rmvb audio/x-pn-realaudio

  rnx application/vnd.rn-realplayer

  roff application/x-troff

  rp image/vnd.rn-realpix

  rpm audio/x-pn-realaudio-plugin

  rt text/vnd.rn-realtext

  rte x-lml/x-gps

  rtf application/rtf

  rtg application/metastream

  rtx text/richtext

  rv video/vnd.rn-realvideo

  rwc application/x-rogerwilco

  s3m audio/x-mod

  s3z audio/x-mod

  sca application/x-supercard

  scd application/x-msschedule

  sdf application/e-score

  sea application/x-stuffit

  sgm text/x-sgml

  sgml text/x-sgml

  sh application/x-sh

  shar application/x-shar

  shtml magnus-internal/parsed-html

  shw application/presentations

  si6 image/si6

  si7 image/vnd.stiwap.sis

  si9 image/vnd.lgtwap.sis

  sis application/vnd.symbian.install

  sit application/x-stuffit

  skd application/x-Koan

  skm application/x-Koan

  skp application/x-Koan

  skt application/x-Koan

  slc application/x-salsa

  smd audio/x-smd

  smi application/smil

  smil application/smil

  smp application/studiom

  smz audio/x-smd

  snd audio/basic

  spc text/x-speech

  spl application/futuresplash

  spr application/x-sprite

  sprite application/x-sprite

  sdp application/sdp

  spt application/x-spt

  src application/x-wais-source

  stk application/hyperstudio

  stm audio/x-mod

  sv4cpio application/x-sv4cpio

  sv4crc application/x-sv4crc

  svf image/vnd

  svg image/svg-xml

  svh image/svh

  svr x-world/x-svr

  swf application/x-shockwave-flash

  swfl application/x-shockwave-flash

  t application/x-troff

  tad application/octet-stream

  talk text/x-speech

  tar application/x-tar

  taz application/x-tar

  tbp application/x-timbuktu

  tbt application/x-timbuktu

  tcl application/x-tcl

  tex application/x-tex

  texi application/x-texinfo

  texinfo application/x-texinfo

  tgz application/x-tar

  thm application/vnd.eri.thm

  tif image/tiff

  tiff image/tiff

  tki application/x-tkined

  tkined application/x-tkined

  toc application/toc

  toy image/toy

  tr application/x-troff

  trk x-lml/x-gps

  trm application/x-msterminal

  tsi audio/tsplayer

  tsp application/dsptype

  tsv text/tab-separated-values

  ttf application/octet-stream

  ttz application/t-time

  txt text/plain

  ult audio/x-mod

  ustar application/x-ustar

  uu application/x-uuencode

  uue application/x-uuencode

  vcd application/x-cdlink

  vcf text/x-vcard

  vdo video/vdo

  vib audio/vib

  viv video/vivo

  vivo video/vivo

  vmd application/vocaltec-media-desc

  vmf application/vocaltec-media-file

  vmi application/x-dreamcast-vms-info

  vms application/x-dreamcast-vms

  vox audio/voxware

  vqe audio/x-twinvq-plugin

  vqf audio/x-twinvq

  vql audio/x-twinvq

  vre x-world/x-vream

  vrml x-world/x-vrml

  vrt x-world/x-vrt

  vrw x-world/x-vream

  vts workbook/formulaone

  wav audio/x-wav

  wax audio/x-ms-wax

  wbmp image/vnd.wap.wbmp

  web application/vnd.xara

  wi image/wavelet

  wis application/x-InstallShield

  wm video/x-ms-wm

  wma audio/x-ms-wma

  wmd application/x-ms-wmd

  wmf application/x-msmetafile

  wml text/vnd.wap.wml

  wmlc application/vnd.wap.wmlc

  wmls text/vnd.wap.wmlscript

  wmlsc application/vnd.wap.wmlscriptc

  wmlscript text/vnd.wap.wmlscript

  wmv video/x-ms-wmv

  wmx video/x-ms-wmx

  wmz application/x-ms-wmz

  wpng image/x-up-wpng

  wpt x-lml/x-gps

  wri application/x-mswrite

  wrl x-world/x-vrml

  wrz x-world/x-vrml

  ws text/vnd.wap.wmlscript

  wsc application/vnd.wap.wmlscriptc

  wv video/wavelet

  wvx video/x-ms-wvx

  wxl application/x-wxl

  x-gzip application/x-gzip

  xar application/vnd.xara

  xbm image/x-xbitmap

  xdm application/x-xdma

  xdma application/x-xdma

  xdw application/vnd.fujixerox.docuworks

  xht application/xhtml+xml

  xhtm application/xhtml+xml

  xhtml application/xhtml+xml

  xla application/vnd.ms-excel

  xlc application/vnd.ms-excel

  xll application/x-excel

  xlm application/vnd.ms-excel

  xls application/vnd.ms-excel

  xlt application/vnd.ms-excel

  xlw application/vnd.ms-excel

  xm audio/x-mod

  xml text/xml

  xmz audio/x-mod

  xpi application/x-xpinstall

  xpm image/x-xpixmap

  xsit text/xml

  xsl text/xml

  xul text/xul

  xwd image/x-xwindowdump

  xyz chemical/x-pdb

  yz1 application/x-yz1

  z application/x-compress

  zac application/x-zaurus-zac

  zip application/zip

 

[JavaMail]9 详解Multipart和BodyPart

 A、简介

Message表示一个邮件,messgaes.getContent()返回一个Multipart对象。一个Multipart对象包含一个或多个BodyPart对象,来组成邮件的正文部分(包括附件)。

 

B、Multipart

javax.mail.Multipart

    public abstract class Multipart

Multipart是一个容器它转载多个body Part(正文、附件或内嵌资源)。Part的getContent()方法就返回一个Multipart对象。

javax.mail.internet.MimeMultipart

public class MimeMultipart extends Multipart

MimeMultipart是Multipart的实现类,默认类别是mixed。其他multipart子类型如:related和alternative可以通过new MimeMultipart(“alternative”);来实现。

 

B.0、Multipart的content-type

总体来说,MIME消息由消息头和消息体两大部分组成。现在我们关注的是MIME邮件,因此在以下的讨论中姑且称“消息”为“邮件”。

邮件头包含了发件人、收件人、主题、时间、MIME版本、邮件内容的类型等重要信息。每条信息称为一个域,由域名后加“: ”和信息内容构成,可以是一行,较长的也可以占用多行。域的首行必须“顶头”写,即左边不能有空白字符(空格和制表符);续行则必须以空白字符打头,且第一个空白字符不是信息本身固有的,解码时要过滤掉。

邮件体包含邮件的内容,它的类型由邮件头的“Content-Type”域指出。常见的简单类型有text/plain(纯文本)和text/html(超文本)。有时也会出现的multipart类型,是MIME邮件的精髓。邮件体被分为多个段,每个段又包含段头和段体两部分,这两部分之间也以空行分隔。常见的multipart类型有三种:multipart/mixed, multipart/related和multipart/alternative。

multipart/mixed:附件。

multipart/related:内嵌资源。

multipart/alternative:纯文本与超文本共存。

可以看出,如果在邮件中要添加附件,必须定义multipart/mixed段;如果存在内嵌资源,至少要定义multipart/related段;如果纯文本与超文本共存,至少要定义multipart/alternative段。什么是“至少”?举个例子说,如果只有纯文本与超文本正文,那么在邮件头中将类型扩大化,定义为multipart/related,甚至multipart/mixed,都是允许的。

multipart诸类型的共同特征是,在段头指定“boundary”参数字符串,段体内的每个子段以此串定界。所有的子段都以--=_”boundary行”开始,父段则以--=_”boundary行” --结束。段与段之间也以空行分隔。

前文,在邮件体是multipart类型的情况下,邮件体的开始部分(第一个--=_”boundary行”之前)可以有一些附加的文本行,相当于注释,解码时应忽略。段间也可以有一些附加的文本行,不会显示出来,如果有兴趣,不妨验证一下。

 

B.1、javax.mail.Multipart

属性

protected  String   contentType

This field specifies the content-type of this multipart object.

返回Multipart的content-type类型。类型包括 alternative ,  mixed ,  related ,  parallel ,  signed 等。

protected  Part      parent

The Part containing this Multipart, if known.

父Part,一般是message。

protected  Vector  parts

Vector of BodyPart objects.

方法

1.操作BodyPart

void  addBodyPart(BodyPart part)

Adds a Part to the multipart.

void  addBodyPart(BodyPart part, int index)

Adds a BodyPart at position index.

BodyPart getBodyPart(int index)

Get the specified Part.

boolean    removeBodyPart(BodyPart part)

Remove the specified part from the multipart message.

void  removeBodyPart(int index)

Remove the part at specified location (starting from 0).

2.操作父Part

Part getParent()

Return the Part that contains this Multipart object, or null if not known.

void  setParent(Part parent)

Set the parent of this Multipart to be the specified Part.

3.取得content-type

String        getContentType()

Return the content-type of this Multipart.

4.取得BodyPart数量

int    getCount()

Return the number of enclosed BodyPart objects.

 

B.2、javax.mail.internet.MimeMultipart

属性

protected  DataSource ds

The DataSource supplying our InputStream.

protected  boolean        parsed

Have we parsed the data from our InputStream yet? Defaults to true; set to false when our constructor is given a DataSource with an InputStream that we need to parse.

构造函数

MimeMultipart()

Default constructor.

MimeMultipart(DataSource ds)

Constructs a MimeMultipart object and its bodyparts from the given DataSource.

MimeMultipart(String subtype)

Construct a MimeMultipart object of the given subtype.

创建一个指定子类型的MimeMultipart对象。默认为mixed,你可设置related或alternative等。

方法

1. 操作BodyPart

void  addBodyPart(BodyPart part)

Adds a Part to the multipart.

void  addBodyPart(BodyPart part, int index)

Adds a BodyPart at position index.

BodyPart getBodyPart(int index)

Get the specified BodyPart.

BodyPart getBodyPart(String CID)

Get the MimeBodyPart referred to by the given ContentID (CID).

void  removeBodyPart(int index)

Remove the part at specified location (starting from 0).

2. 操作前文

String        getPreamble()

Get the preamble text, if any, that appears before the first body part of this multipart.

void  setPreamble(String preamble)

Set the preamble text to be included before the first body part.

3.设置子类型

void  setSubType(String subtype)

Set the subtype.

4.

boolean    isComplete()

Return true if the final boundary line for this multipart was seen.

 

C、BodyPart

javax.mail.Part

public interface Part

javax.mail.internet. MimePart

public interface MimePart extends Part

javax.mail.BodyPart

public abstract class BodyPart implements Part

BodyPart是一个包含在Multipart中的Part。它是一个Part也包含attribute和content。

javax.mail.internet.MimeBodyPart

public class MimeBodyPart extends BodyPart implements MimePart

MimeBodyPart是BodyPart的实现类。

javax.mail.internet.PreencodedMimeBodyPart

         public class PreencodedMimeBodyPart extends MimeBodyPart

 

C.1、javax.mail.BodyPart

属性

Multipart parent

The Multipart object containing this BodyPart, if known.

这是和message的区别所在,虽然都实现Part接口,但BodyPart是包含在Multipart中的。它的parent是(Multipart)message.getContent()。

 

C.2、javax.mail.internet.MimeBodyPart

属性

protected  byte[]   content

Byte array that holds the bytes of the content of this Part.

一个字节数组存放BodyPart内容的字节流。

protected  InputStream         contentStream

If the data for this body part was supplied by an InputStream that implements the SharedInputStream interface, contentStream is another such stream representing the content of this body part.

若BodyPart的数据提供一个InputStream,contentStream是另一种流代表BodyPart的内容。

protected  DataHandler        dh

The DataHandler object representing this Part's content.

代表BodyPart内容的DataHandler对象。

protected  InternetHeaders headers

The InternetHeaders object that stores all the headers of this body part.

InternetHeaders 对象存放所有BodyPart的标题。

构造函数

MimeBodyPart()

An empty MimeBodyPart object is created.

创建一个空的MimeBodyPart对象。

MimeBodyPart(InputStream is)

Constructs a MimeBodyPart by reading and parsing the data from the specified input stream.

MimeBodyPart(InternetHeaders headers, byte[] content)

Constructs a MimeBodyPart using the given header and content bytes.

方法

1.操作附件

DataHandler

DataHandler    getDataHandler()

Return a DataHandler for this body part's content.

void  setDataHandler(DataHandler dh)

This method provides the mechanism to set this body part's content.

2.操作附件名

void  setFileName(String filename)

Set the filename associated with this body part, if possible.

设置了附件名称则会在邮件BodyPart头中增加一行表示附件的代码Content-Disposition: attachment; filename=xxxx.xls

String        getFileName()

Get the filename associated with this body part.

获取Content-Disposition: attachment; filename=xxxx.xls中的filename。

3.操作正文

void  setText(String text)

Convenience method that sets the given String as this part's content, with a MIME type of  text/plain .

void  setText(String text, String charset)

Convenience method that sets the given String as this part's content, with a MIME type of  text/plain  and the specified charset.

void  setText(String text, String charset, String subtype)

Convenience method that sets the given String as this part's content, with a primary MIME type of  text  and the specified MIME subtype.

以上三个方法都是用于设置MimeBodyPart的内容(文本内容)的,不同之处在于是否设置指定的字符或指定的MIME类型。

 

 

范例

发送代码

MimeBodyPart mbp_body = ne w MimeBodyPart();

mbp_body.setText(mailMessage.getBody(),  UTF-8 );

//正文

MimeBodyPart mbp_attachment=new MimeBodyPart();

DataHandler dh=new DataHandler(new FileDataSource( C:\\xx.xls ));

mbp_attachment.setDataHandler(dh);

mbp_attachment.setFileName( xx.xls );

//附件

MimeMultipart mmp=new MimeMultipart();

mmp.addBodyPart(mbp_body);

mmp.addBodyPart(mbp_attachment);

mimeMessage.setContent(mmp);

接收代码

Object obj = message.getContent();

if (message.isMimeType( text/* )) {                  mailMsg.setBody(obj.toString());

} else if (message.isMimeType( multipart/* )) {

Multipart mp = (Multipart) obj;

    for (int i = 0; i < mp.getCount(); i++) {

Part part = mp.getBodyPart(i);

       if (part.getDisposition() != null

&& part.getDisposition().equals(Part.ATTACHMENT)) {

 

} else if (part.isMimeType( text/* )) {

              part.getContent().toString()

}

    }

}

[JavaMail]10 详解字符编码和MimeUtility,URLDecoder,URLEncoder

一、邮件中的编码

1. Message的header

Message中的header都是只能存放ASCII码的,当邮件中有非ASCII时,例如邮件的主题是中文时,我们可以把邮件的中文主题以UTF-8(当然也可以使用其它编码,如GB2312)规则来进行编码,并以指定格式的ASCII字符串来表示。

若邮件的主题是“中”,我们想用UTF-8编码。那么“中”字的UTF-8的编码是E4 B8 AD,就用特定格式的ASCII码来表示主题“中”,则是:Subject: =?UTF-8?Q?=E4=B8=AD?=(这个是RFC2047规范的格式)。

2.BodyPart的Header

BodyPart中的Header也是只能存放ASCII码的,例如邮件的有一个附件的文件名是中文时,我们可以把附件名进行编码,并以指定格式的ASCII字符串来表示,注意差别是这时候的ASCII字符串格式和前面不同。格式:UTF-8''中(这个是W3C规范的格式)。

为什么在使用一个邮件中使用两种格式,就不得而知了,可能是方便下载附件吧。

 

二、Message Header的编码和解码

A、编码规则

 =?  charset  ?  encoding  ?  encoded-text  ?= 

charset:字符编码

encoding:

Q --- Quote Printable

B --- BASE64

U --- UUENCODE

最常用的 Content-Transfer-Encoding 有 Base64 和 Quoted-Printable 两种。在对二进制文件或者中文文本进行转化时,Base64 得到的“字节串”比 Quoted-Printable 更短。在对英文文本进行转化时,Quoted-Printable 得到的“字节串”比 Base64 更短。

例1: Subject: =?GB2312?Q?=C4=E3=BA=C3?=

例2: Subject: =?utf-7?B?WFgrWUNkU0swNE9kbjVPRVZiKy0z?=

 

B、javax.mail.internet.MimeUtility

public class MimeUtility

这是一个工具类,提供各种MIME相关的功能。

该类有一组根据RFC2047规范来对MIME头进行编码和解码的方法。请注意,在一般情况下,这些方法并不需要被使用,如setSubject和setRecipients时。使用这些“高层次”方法时JavaMail会自动编码和解码。这些方法只有在使用setHeader及getHeader方法操作MIME头时才需要被使用。

RFC 822规定邮件头只能包含US-ASCII字符。当包含有非US-ASCII字符的邮件头必须进行编码以使邮件头只包含US-ASCII字符。基本上,这个过程涉及使用Base64或QP规则来编码某些字符。 RFC 2047中详细说明了这一点。

在JAVA中String是16为unicode字符。ASCII是Unicode的一个子集(占用范围0 - 127)。一个只包含ASCII字符的String是邮件安全的。若String含有非ASCII字符则必须进行编码。此步骤增加了一个额外的复杂性,是因为Unicode还不是一种广泛使用的字符集,有人可能首先想到把String的字符集编码转换成其它一种字符集编码,然后来进行传输。请注意,要获得邮件安全字符串的实际字节(例如,通过SMTP发送),必须做的是:

byte[] bytes = string.getBytes( iso-8859-1 );

假设MimeMessage、MimeBodyPart的setHeader和AddHeader方法给header赋的值是一个只包含US-ASCII字符的Unicode字符串。那么这些方法的调用者必须确保他们传递的值不包含非US-ASCII字符。这个类的方法帮忙做这些事情。

MimeMessage、MimeBodyPart的getHeader方法获取header的值时。这些值是按RFC 2047规范编码的,那么就必须解码为Unicode编码。这个类的方法帮忙做这些事情。

几个系统属性严格控制MIME规范的一致性。请注意,这些都不是session的属性,但必须设置为全局系统属性。

mail.mime.decodetext.strict属性控制MIME编码字符的解码。MIME规范要求,编码字符必须以一个空白分隔符为开始。一些邮件错误的包含了编码字符在一个词的中间。如果mail.mime.decodetext.strict系统属性设置为false,系统就会企图解码这些非法的编码字符。默认值是true。

mail.mime.encodeeol.strict属性控制非”text”类型的MIME Part的Content-Transfer-Encoding的选择。如果在mail.mime.encodeeol.strict的系统属性设置为“true”,必要时将使用这种编码。默认值是true。

mail.mime.charset系统属性用来指定默认的MIME字符集。通常情况下,默认的MIME字符集是来自默认的Java字符集,在file.encoding系统属性中指定。大多数应用程序将有没有必要明确地设置默认的MIME字符集。邮件message使用的默认的MIME字符集是不同于存放在系统中文件的字符集。

mail.mime.ignoreunknownencoding属性用来控制Content-Transfer-Encoding头中未知值,当递给解码方法,会导致异常。如果设置为“true”,未知的值被忽略和被假设为8bit编码。否则,未知值会导致以抛出MessagingException异常。

静态方法

1.解码

static InputStream  decode(InputStream is, String encoding)

Decode the given input stream.

static String     decodeText(String etext)

Decode  unstructured  headers, that is, headers that are defined as '*text' as per RFC 822.

解码根据RFC822定义为*text的“非结构化”头。

这个字符串使用RFC2047中第6.1章中指定的算法解码方式。如果字符集转换失败,则抛出一个UnsupportedEncodingException例外。如果String不是RFC 2047编码格式的头,则原样返回。

static String     decodeWord(String eword)

The string is parsed using the rules in RFC 2047 and RFC 2231 for parsing an  encoded-word .

使用RFC 2047和RFC 2231规则对一个编码字符串进行解码。如果解析失败,则抛出一个ParseException例外。否则,就传输解码,然后把编码转换成Unicode字符。如果字符集转换失败,则抛出一个UnsupportedEncodingException例外。

2.编码

static OutputStream        encode(OutputStream os, String encoding)

Wrap an encoder around the given output stream.

static OutputStream        encode(OutputStream os, String encoding, String filename)

Wrap an encoder around the given output stream.

static String     encodeText(String text)

Encode a RFC 822  text  token into mail-safe form as per RFC 2047.

static String     encodeText(String text, String charset, String encoding)

Encode a RFC 822  text  token into mail-safe form as per RFC 2047.

static String     encodeWord(String word)

Encode a RFC 822  word  token into mail-safe form as per RFC 2047.

static String     encodeWord(String word, String charset, String encoding)

Encode a RFC 822  word  token into mail-safe form as per RFC 2047.

3.获取encoding类型

static String     getEncoding(DataHandler dh)

Same as getEncoding(DataSource) except that instead of reading the data from an InputStream it uses the writeTo method to examine the data.

static String     getEncoding(DataSource ds)

Get the content-transfer-encoding that should be applied to the input stream of this datasource, to make it mailsafe.

3.获取系统字符集编码

static String     getDefaultJavaCharset()

Get the default charset corresponding to the system's current default locale.

4.

static String     javaCharset(String charset)

Convert a MIME charset name into a valid Java charset name.

static String     mimeCharset(String charset)

Convert a java charset into its MIME charset name.

static String     quote(String word, String specials)

A utility method to quote a word, if the word contains any characters from the specified 'specials' list.

 

三、BodyPart Header的编码和解码

A、编码规则

charset’ language’encoded-text

charset:字符编码

language:语言

language:编码后的ASCII字符串

例1:UTF-8''中

编码用单引号分成了三段,分别是字符集(utf8)、语言(空)和urlencode过的文件名

 

B、URLDecoder和URLEncoder

1.java.net.URLDecoder

public class URLDecoder

HTML 格式解码的实用工具类。该类包含了static方法decode(String s, String enc)可以将一个字符串从application/x-www-form-urlencoded MIME格式中解码。

假定已编码的字符串中只能是以下字符: a  到  z 、 A  到  Z 、 0  到  9  和  - 、 _ 、 .  以及  * 。允许有  %  字符,但是将它解释为特殊转义序列的开始。如:中。

转换中使用以下规则:

1.字母数字字符  a  到  z 、 A  到  Z  和  0  到  9  保持不变。

2.特殊字符  . 、 - 、 *  和  _  保持不变。

3.加号  +  转换为空格字符    。

4.将把  %xy  格式序列视为一个字节,其中 xy 为 8 位的两位十六进制表示形式(xy是16进制数,其中的一位表示一个byte)。然后,所有连续包含一个或多个这些字节序列的子字符串,将被其编码可生成这些连续字节的字符所代替。可以指定对这些字符进行解码的编码机制,或者如果未指定的话,则使用平台的默认编码机制。

该解码器处理非法字符串有两种可能的方法。一种方法是不管该非法字符,另一种方法是抛出 IllegalArgumentException 异常。解码器具体采用哪种方法取决于具体实现。

static String     decode(String s, String enc)

使用指定的编码机制对 application/x-www-form-urlencoded 字符串解码。

例子1:

String s=” 中”;

//中是“中”字UTF-8的编码的application/x-www-form-urlencoded MIME表示方式。

URLDecoder.decode(s,  UTF-8 );

//则指定用UTF-8编码来进行解码。

例子2:

String s= �� ;

URLDecoder.decode(s,  GB2312 );

//��是“中”字GB2312的编码的application/x-www-form-urlencoded MIME表示方式。则指定用GB2312编码来进行解码。

2.java.net.URLEncoder

public class URLEncoder

该转换过程正好与 URLEncoder 类使用的过程相反。

static String     encode(String s, String enc)

使用指定的编码机制将字符串转换为application/x-www-form-urlencoded格式。

 

C、特殊符号的编码和解码

1.空格

空格在邮件中存储或者在网页的URL中则是 。空格用URLEncoder.encode(“ “,”UTF-8”);来进行编码是会被转换为”+”。而在解码时 和+都被解码为空格。

2.+

+在邮件中存储仍然是+。那么对含有+的字符串进行解码时就会把+解码为空格,这样就和事实不符了。

3.%

%在邮件中存储仍然是%。编码和解码没有问题。

 

四、字符编码

    字符编码是计算机技术的基石,想要熟练使用计算机,就必须懂得字符编码的知识。不注意的人可能对这个不在意,但这些名词有时候实在让人迷惑,对想学习计算机知识的人来说,搞懂它也十分重要,我也是在学习中慢慢了解了一些这方面的知识。

 

一、ASCII码和非ASCII码

1. ASCII码

在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从0000000到11111111。

上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。

ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(十进制的32,用二进制表示就是00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。具体的可以到这个网页上去查下:http://www.nengcha.com/code/ascii/all/

 

2、非ASCII编码

英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。

但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0—127表示的符号是一样的,不一样的只是128—255的这一段。

至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如,简体中文常见的编码方式是GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示256x256=65536个符号。

 

一、Unicode和UTF-8

1.Unicode

正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。解释:同一个文本文件,假设内容是用英语写的,在英语编码的情况下,每个字符会和一个二进制数对应(如00101000类似),然后存到计算机中,这时把这个英语文件发给一个俄语国家的用户,计算机传输的是二进制流,即0101之类的数据,到了俄语用户这方,需要有它的俄语编码方式进行解码,把每个二进制流转为字符显示,由于俄语编码表中对每串二进制流数据的解释方式不同,同一个数据如00101000在英语中可能代表A,而在俄语中则代表B,这样就会产生乱码,这是我个人的理解。

GB2312编码、日文编码等也是非unicode编码,是要通过转换表(codepage)转换成unicode编码的,要不怎么显示出来呢?

可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是Unicode,就像它的名字都表示的,这是一种所有符号的编码。

Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字“严”。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表。

 

2. Unicode的问题

需要注意的是,Unicode只是一个符号集,只是一种规范、标准,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储在计算机上。

比如,汉字“严”的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

这里就有两个严重的问题,第一个问题是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

它们造成的结果是:1)出现了unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示unicode。2)unicode在很长一段时间内无法推广,直到互联网的出现。

 

3.UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8就是在互联网上使用最广的一种unicode的实现方式。其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一,它规定了字符如何在计算机中存储、传输等。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

 

下表总结了编码规则,字母x表示可用编码的位。

 

Unicode符号范围

 

 

UTF-8编码方式 (十六进制)

 

 

(二进制)

 

 

0000 0000-0000

 

 

007F

 

 

0xxxxxxx

 

 

0000 0080-0000

 

 

07FF

 

 

110xxxxx 10xxxxxx

 

 

0000 0800-0000

 

 

FFFF

 

 

1110xxxx 10xxxxxx 10xxxxxx

 

 

0001 0000-0010

 

 

FFFF

 

 

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

 

 下面,还是以汉字“严”为例,演示如何实现UTF-8编码。

已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是“11100100 10111000 10100101”,这是保存在计算机中的实际数据,转换成十六进制就是E4B8A5,转成十六进制的目的为了便于阅读。

 

4. Unicode与UTF-8之间的转换

通过上一节的例子,可以看到“严”的Unicode码是4E25,UTF-8编码是E4B8A5,两者是不一样的。它们之间的转换可以通过程序实现。

在Windows平台下,有一个最简单的转化方法,就是使用内置的记事本小程序Notepad.exe。打开文件后,点击“文件”菜单中的“另存为”命令,会跳出一个对话框,在最底部有一个“编码”的下拉条。

里面有四个选项:ANSI,Unicode,Unicode big endian 和 UTF-8。

1)ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。

2)Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。这个选项用的little endian格式。

3)Unicode big endian编码与上一个选项相对应。我在下一节会解释little endian和big endian的涵义。

4)UTF-8编码,也就是上一节谈到的编码方法。

选择完”编码方式“后,点击”保存“按钮,文件的编码方式就立刻转换好了。

 

5. Little endian和Big endian

上一节已经提到,Unicode码可以采用UCS-2格式直接存储。以汉字”严“为例,Unicode码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

Unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。

如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

 

6. 实例

下面,举一个实例。

打开”记事本“程序Notepad.exe,新建一个文本文件,内容就是一个”严“字,依次采用ANSI,Unicode,Unicode big endian 和 UTF-8编码方式保存。

然后,用文本编辑软件UltraEdit中的”十六进制功能“,观察该文件的内部编码方式。

1)ANSI:文件的编码就是两个字节“D1 CF”,这正是“严”的GB2312编码,这也暗示GB2312是采用大头方式存储的。

2)Unicode:编码是四个字节“FF FE 25 4E”,其中“FF FE”表明是小头方式存储,真正的编码是4E25。

3)Unicode big endian:编码是四个字节“FE FF 4E 25”,其中“FE FF”表明是大头方式存储。

 

4)UTF-8:编码是六个字节“EF BB BF E4 B8 A5”,前三个字节“EF BB BF”表示这是UTF-8编码,后三个“E4B8A5”就是“严”的具体编码,它的存储顺序与编码顺序是一致的。

 

7.解决的问题:

一、如何在中文系统中运行非Unicode编码程序?

有很多意大利文版(除英文版)学习软件、百科全书等软件在中文系统上会出现乱码,解决方法:

WindowsXP内核是Unicode编码,支持多语种,对于Unicode编码的应用程序会正常显示原文(因为windows核心是用unicode代码写的,所以不存在问题),但是,很多程序不是用Unicode编码写的,这时WindowsXP系统可以指定以特定的编码运行非Unicode编码程序,中文版WindowsXP默认的是“简体中文GB2312”。你只需在控制面板--〉区域和语言选项--〉高级--〉为非Unicode程序的语言选择“意大利语”,即可正确运行意大利文版的游戏程序。分析:我理解的流程是这样:程序------>意大利语编码(转换表codepage)------>解释成unicode识别的编码(通过指定的转换表将非 Unicode 的字符编码转换为同一字符对应的系统内部使用的 Unicode 编码)------>被系统翻译成意大利文(因为每个unicode编码对应了相应的意大利文字),便可以正常显示了。

 

三、ISO-8859-1

ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。

ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。欧元符号出现的比较晚,没有被收录在ISO-8859-1当中。

因为ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。换言之,把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性。ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。

Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。

 

三、GB2312、GB13000、GB18030、GBK和BIG

1.GB2312

GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。基本集共收入汉字6763个和非汉字图形字符682个,通行于中国大陆。新加坡等地也使用此编码。

2.GBK

GBK即汉字内码扩展规范,K为扩展的汉语拼音中“扩”字的声母。英文全称Chinese Internal Code Specification。GBK编码标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库。

3.GB13000

GB13000 全称:国家标准GB13000.1:1993《信息技术 通用多八位编码字符集(UCS)第一部分:体系结构与基本多文种平面》,此标准等同采用国际标准ISO/IEC 10646.1:1993《信息技术 通用多八位编码字符集(UCS)第一部分:体系结构与基本多文种平面》。

4.GB18030

国家标准GB18030-2000《信息交换用汉字编码字符集基本集的扩充》是我国继GB2312-1980和GB13000-1993之后最重要的汉字编码标准,是我国计算机系统必须遵循的基础性标准之一。 目前,GB18030有两个版本:GB18030-2000和GB18030-2005。GB18030-2000是GBK的取代版本,它的主要特点是在GBK基础上增加了CJK统一汉字扩充A的汉字。GB18030-2005的主要特点是在GB18030-2000基础上增加了CJK统一汉字扩充B的汉字。

5.BIG

BIG-5码是通行于台湾、香港地区的一个繁体字编码方案,俗称“大五码”。地区标准号为:CNS11643,这就是人们讲的BIG-5码。

 

二、消除网页乱码?

网页乱码是浏览器对HTML网页解释时形成的,如果网页制作时编码为繁体big5,浏览器却以编码gb2312显示该网页,就会出现乱码,因此只要你在浏览器中也以繁体big5显示该网页,就会消除乱码。打个比方有些像字典,繁体字得用繁体字典来查看,简体字得用简体字典来查看,不然你看不懂。

 

【解决办法】:在浏览器中选择“编码”菜单,事先为浏览器安装多语言支持包(例如在安装IE时要安装多语言支持包),这样当浏览网页出现乱码时,即可手工更改查看此网页的编码方式,在浏览器中选择菜单栏下的“查看”/“编码”/“自动选择”/简体中文(GB2312),如为繁体中文则选择“查看”/“编码”/“自动选择”/繁体中文(BIG5),其他语言依此类推,便可消除网页乱码现象。 分析:因为繁体big5编码后的文件,每个文字对应一个二进制流(假设是1212对应繁这个字),当我们以编码gb2312显示该网页时,gb2312编码会到表里去找1212(二进制流不会变的)对应谁,肯定不再是繁这个字了,当然显示的就不再是那个繁字了,也就会出现乱码了。这样理解简单些,其实中间还要转换成同一字符对应的系统内部使用的 Unicode 编码,然后通过系统底层unicode编码还原成相应字符显示出来。

[JavaMail]11 详解附件和DataHandler、DataSource

 A、邮件中的附件

附件是邮件消息的相关资源,如通常不包含在消息正文里文本文件、电子表格或图像等。可以用 JavaMail API 将资源 attach(附加) 到您的消息上,就可以在收到消息时得到。

附件的发送:

发送附件非常像转发消息。您建立各部分以组成完整消息。完成第一部件,即消息正文后,您添加其它部件,其中每个 DataHandler 都代表附件,而不是转发消息情况下的共享处理程序。如果从文件中读附件,附件的数据源是 FileDataSource。而如果从 URL 中读时,附件的数据源是 URLDataSource。一旦存在 DataSource,只要先把它传递给 DataHandler 构造器,最后再用 setDataHandler() 把它附加到 BodyPart。假定您要保留附件的原始文件名,最终要做的是用 BodyPart 的 setFileName() 方法设置与附件相关的文件名。

附件的获取:

从消息中获取附件比发送它们棘手些,因为 MIME 没有简单的关于附件的概念。当消息包含附件时,消息的内容是个 Multipart 对象。接着,您需要处理每个 Part,获取主要内容和附件。标有从 part.getDisposition() 获得的 Part.ATTACHMENT 配置(disposition)的部件(Part)无疑就是附件。但是,没有配置(以及一个非文本 MIME 类型)和带 Part.INLINE 配置的部件也可能是附件。当配置要么是 Part.ATTACHMENT,要么是 Part.INLINE 时,这个消息部件的内容就能被保存。只要用 getFileName() 和 getInputStream() 就能分别得到原始文件名和输入流。

 

B、相关的类

B.1、javax.activation.DataHandler

public class DataHandler implements Transferable

DataHandler 类为在多种不同源和格式下可用的数据提供一致的接口。它使用 DataContentHandler 管理简单流到字符串的转换以及相关操作。它提供对能够操作数据的命令的访问。使用 CommandMap 可以找到这些命令。

构造函数

DataHandler(DataSource ds)

创建引用指定 DataSource 的 DataHandler 实例。

DataHandler(Object obj, String mimeType)

创建表示此 MIME 类型对象的 DataHandler 实例。

DataHandler(URL url)

创建引用 URL 的 DataHandler 实例。

 

B.2、javax.activation.DataSource

public interface DataSource

DataSource 接口为 JavaBeans Activation Framework 提供任意数据集合的抽象。它提供该数据的类型,并在适当的时候以 InputStream 和 OutputStream 的形式提供对该数据的访问。

 

B.3、javax.activation.FileDataSource

public class FileDataSource implements DataSource

FileDataSource 类实现一个封装文件的简单 DataSource 对象。它通过 FileTypeMap 对象提供数据分类服务。

FileDataSource 类将文件的数据分类委托给一个从 FileTypeMap 类子类化的对象。setFileTypeMap 方法可用于为 FileDataSource 实例显示地设置 FileTypeMap。如果没有设置任何 FileTypeMap,则 FileDataSource 将调用 FileTypeMap 的 getDefaultFileTypeMap 方法获取系统的默认 FileTypeMap。

构造函数

FileDataSource(File file)

根据 File 对象创建 FileDataSource。

FileDataSource(String name)

根据指定的路径名创建 FileDataSource。

 

B.4、javax.activation.URLDataSource

public class URLDataSource implements DataSource

URLDataSource 类提供一个对象,此对象将 URL 对象包装在 DataSource 接口中。URLDataSource 简化了 JavaBeans Activation Framework 中 URL 描述的数据处理方法,因为此类可用于创建新的 DataHandler。注:当用 URL 构造 DataHandler 对象时,DataHandler 对象在内部创建一个 URLDataSource。

 

范例1:

发送一个有正文和附件的邮件,这时Content-Type: multipart/mixed;

BodyPart bp1=new MimeBodyPart();

bp1.setText(mailMessage.getBody());

          

BodyPart bodyPart=new MimeBodyPart();

DataSource dataSource=new FileDataSource( C:\\xxx.xls );

DataHandler dataHandler=new DataHandler(dataSource);

bodyPart.setDataHandler(dataHandler);

bodyPart.setFileName( xxx.xls );

          

Multipart multipart=new MimeMultipart();

multipart.addBodyPart(bp1);

multipart.addBodyPart(bodyPart);

 

范例2:

发送一个有html正文和内嵌资源的邮件,这时Content-Type: multipart/related;

String htmlText =  <H1>Hello</H1> 

+  <img src=\ cid:memememe\ > ;

BodyPart bp1 = new MimeBodyPart();

bp1.setContent(htmlText,  text/html );

 

BodyPart bodyPart = new MimeBodyPart();

DataSource dataSource = new FileDataSource( C:\\1.jpg );

DataHandler dataHandler = new DataHandler(dataSource);

bodyPart.setDataHandler(dataHandler);

bodyPart.setHeader( Content-ID , memememe );

//内嵌资源和html正文中cid:memememe关联

          

MimeMultipart multipart = new MimeMultipart( related );

//创建一个related类型的MimeMultipart

multipart.addBodyPart(bp1);

multipart.addBodyPart(bodyPart);

[JavaMail]12 详解Folder

javax.mail.Folder

public abstract class Folder

com.sun.mail.imap.IMAPFolder

public class IMAPFolder extends Folder implements UIDFolder, ResponseHandler

com.sun.mail.pop3.POP3Folder

public class POP3Folder extends Folder

 

javax.mail.Folder

Folder是一个抽象类表示邮件信息的文件夹。子类实现不同协议的具体类。Folder可以包含Message或Folder或两者同时包括。从而提供一个树状结构,树的根root是Store的default folder。(请注意,有些Folder的实现可能不允许在同一Folder中既有Message也有Folder)。

Folder名称的解释是依赖于实现。在层次结构中不同层次Folder的full name由层次分隔符(linux中一般是/,windows中是\\)分隔组成。

Folder的full name不区分大小写,它是相对于Store的default folder的全路径名。INBOX是指在此服务器上用户的主文件夹。并非所有Store将提供INBOX Folder,并不是所有用户在任何时候都将有一个INBOX Folder。

从Store中获取的一个Folder对象并不需要Store在后端实际存在。exists方法用于测试Folder是否实际存在。create方法用于创建一个Folder。

Folder最初是关闭状态的。某些方法,在这种状态下是有效的。在具体的方法文档中可注意这一点。Folder通过open方法打开。open,delete,rename都可以在close状态下使用。

获取Folder的方法是调用Store,Folder,Session对象的getFolder方法或者调用Folder对象的list和listSubscribed方法。通过上述方法返回的Folder对象不是有Store存储的。因此多次调用获取Folder对象的方法将产生多个Folder对象。

Folder中的Message对象是存放在Folder中的。因此多次调用getMessage方法将产生相同的Message对象。

访问Folder对象中Message对象时,Folder必须open。

请注意,在一个会话中若Folder执行除去操作那么一个消息的message number可能改变。使用message number表示message的应该注意这一点。并应准备处理这种情况(可能是冲洗掉现有的message number引用并重新装载)。由于这种复杂性,促使用户使用message对象来表示消息,而不是使用message number来表示消息。

 

com.sun.mail.imap.IMAPFolder

这个类实现了一个IMAP Folder。

方法

boolean create(int type)

Create this folder, with the specified type.

创建指定类型的Folder。

boolean delete(boolean recurse)

Delete this folder.

         删除Folder。参数recurse为true,删除整个文件夹。为false,则有子文件夹则不删除。

com.sun.mail.pop3.POP3Folder

POP3 Folder只能是INBOX。

[JavaMail]13 详解Service和SSL

javax.mail.Service

      javax.mail.Store

          com.sun.mail.imap.IMAPStore

              com.sun.mail.imap.IMAPSSLStore

          com.sun.mail.pop3.POP3Store

              com.sun.mail.pop3.POP3SSLStore

     javax.mail.Transport

          com.sun.mail.smtp.SMTPTransport

              com.sun.mail.smtp.SMTPSSLTransport

 

javax.mail.Service

public abstract class Service

Service一个抽象类,它包含通讯服务的常见功能,如存储和传输功能。

Service是从Session创建,它使用URLName命名。Service必须先连接,才可以使用。连接事件被发送,以反映其连接状态。

 

javax.mail.Store

public abstract class Store extends Service

一个抽象类,消息存储模型和它的访问协议,用于存储和检索Message。子类提供实际的实现。

请注意,存储扩展服务类,它提供了许多常用的方法命名Store,连接Store和监听 Store的事件。

 

com.sun.mail.imap.IMAPStore

public class IMAPStore extends Store implements QuotaAwareStore, ResponseHandler

这个类提供了访问到IMAP邮件Store。

需要使用IMAP特定功能的应用程序可能会把一个Store对象转换为一个IMAPStore对象,并使用这个类的方法。 getQuota和setQuota方法支持的IMAP的Quota延长。更多信息,请参阅的RFC2087。

警告:这一类独特的API应该被认为是实验性的。他们可能会改变未来的方式是使用目前的API的应用程序不兼容。

 

com.sun.mail.imap.IMAPSSLStore

public class IMAPSSLStore extends IMAPStore

这个类提供了访问通过SSL的IMAP邮件Store。

 

com.sun.mail.pop3.POP3Store

public class POP3Store extends Store

POP3邮件Store。包含只有一个文件夹,INBOX。

 

com.sun.mail.pop3.POP3SSLStore

public class POP3SSLStore extends POP3Store

一个使用SSL 的POP3消息Store。

 

javax.mail.Transport

public abstract class Transport extends Service

一个抽象类,消息传输模型。子类提供实际的实现。

需要注意的是Transport继承于Service,它提供了许多常用方法用于命名Transport,连接Transport,并监听Transport的事件。

 

com.sun.mail.smtp.SMTPTransport

public class SMTPTransport extends Transport

这个类实现了抽象类Transport,使用SMTP提交和传输邮件。

SMTP协议提供的进一步信息,请参阅com.sun.mail.smtp包的文档。

本类包括许多protected方法,让子类来扩展这个类,并添加支持非标准的SMTP命令。issueCommand()和sendCommand()方法可以用于发送简单的SMTP命令。其他方法,如mailForm()和data()方法可以被重载用于在当前SMTP命令之前或之后插入新的命令。例如,一个子类可以做到在发送DATA命令之前发送XACT命令:

        protected OutputStream data() throws MessagingException {

            if (supportsExtension( XACCOUNTING ))

                issueCommand( XACT , 25);

            return super.data();

        }

             

com.sun.mail.smtp.SMTPSSLTransport

public class SMTPSSLTransport extends SMTPTransport

这个类实现抽象类Transport,它通过SSL的SMTP邮件提交和运输。

 

名词解释

SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。

SSL (Secure Socket Layer)

  为Netscape所研发,用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络上之传输过程中不会被截取及qie听。目前一般通用之规格为40 bit之安全标准,美国则已推出128 bit之更高安全标准,但限制出境。只要3.0版本以上之I.E.或Netscape浏览器即可支持SSL。

  当前版本为3.0。它已被广泛地用于Web浏览器与服务器之间的身份认证和加密数据传输。

  SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层:SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。

  SSL协议提供的服务主要有:

  1)认证用户和服务器,确保数据发送到正确的客户机和服务器;

  2)加密数据以防止数据中途被窃取;

  3)维护数据的完整性,确保数据在传输过程中不被改变。

  SSL协议的工作流程:

服务器认证阶段:

1)客户端向服务器发送一个开始信息“Hello”以便开始一个新的会话连接;

2)服务器根据客户的信息确定是否需要生成新的主密钥,如需要则服务器在响应客户的“Hello”信息时将包含生成主密钥所需的信息;

3)客户根据收到的服务器响应信息,产生一个主密钥,并用服务器的公开密钥加密后传给服务器;

4)服务器恢复该主密钥,并返回给客户一个用主密钥认证的信息,以此让客户认证服务器。

  用户认证阶段:在此之前,服务器已经通过了客户认证,这一阶段主要完成对客户的认证。经认证的服务器发送一个提问给客户,客户则返回(数字)签名后的提问和其公开密钥,从而向服务器提供认证。

  从SSL 协议所提供的服务及其工作流程可以看出,SSL协议运行的基础是商家对消费者信息保密的承诺,这就有利于商家而不利于消费者。在电子商务初级阶段,由于运作电子商务的企业大多是信誉较高的大公司,因此这问题还没有充分暴露出来。但随着电子商务的发展,各中小型公司也参与进来,这样在电子支付过程中的单一认证问题就越来越突出。虽然在SSL3.0中通过数字签名和数字证书可实现浏览器和Web服务器双方的身份验证,但是SSL协议仍存在一些问题,比如,只能提供交易中客户与服务器间的双方认证,在涉及多方的电子交易中,SSL协议并不能协调各方间的安全传输和信任关系。在这种情况下,Visa和 MasterCard两大信用卡公组织制定了SET协议,为网上信用卡支付提供了全球性的标准。

HTTPS  

HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议。

  它是由Netscape开发并内置于其浏览器中,用于对数据进行压缩和解压操作,并返回网络上传送回的结果。HTTPS实际上应用了Netscape的完全套接字层(SSL)作为HTTP应用层的子层。(HTTPS使用端口443,而不是象HTTP那样使用端口80来和TCP/IP进行通信。)SSL使用40 位关键字作为RC4流加密算法,这对于商业信息的加密是合适的。HTTPS和SSL支持使用X.509数字认证,如果需要的话用户可以确认发送者是谁。。

  https是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,https的安全基础是SSL,因此加密的详细内容请看SSL。

  它是一个URI scheme(抽象标识符体系),句法类同http:体系。用于安全的HTTP数据传输。https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。这个系统的最初研发由网景公司进行,提供了身份验证与加密通讯方法,现在它被广泛用于万维网上安全敏感的通讯,例如交易支付方面。

  限制

  它的安全保护依赖浏览器的正确实现以及服务器软件、实际加密算法的支持.

  一种常见的误解是“银行用户在线使用https:就能充分彻底保障他们的银行卡号不被偷窃。”实际上,与服务器的加密连接中能保护银行卡号的部分,只有用户到服务器之间的连接及服务器自身。并不能绝对确保服务器自己是安全的,这点甚至已被攻击者利用,常见例子是模仿银行域名的钓鱼攻击。少数罕见攻击在网站传输客户数据时发生,攻击者尝试qie听数据于传输中。

  商业网站被人们期望迅速尽早引入新的特殊处理程序到金融网关,仅保留传输码(transaction number)。不过他们常常存储银行卡号在同一个数据库里。那些数据库和服务器少数情况有可能被未授权用户攻击和损害。

[JavaMail]14 详解查询和SearchTerm

一、查找邮件

在 JavaMail 中查找邮件,不用调用 Folder.getMessages() 方法把邮件夹中的所有邮件都返回,然后再在Message[]中进行搜索。而是可以根据给定的一些条件过滤搜索出我们想要的邮件,之后再对进行获得的邮件进行操作。

要使用搜索过滤功能,必须用到 java.mail.search 包中的 SearchTerm 抽象类。在这个包中,我们可以使用其他具有不同组合关系的子类和具有不同搜索条件的类来进行操作。

1、逻辑组合关系的子类有:AndTerm 类、OrTerm 类、NotTerm 类、ComparisonTerm 类,它们都是 SearchTerm抽象类的具体子类;

2、具体搜索条件的类有:DateTerm 类、BodyTerm 类、HeaderTerm 类,这几个都是抽象类,具体应用时应该由其对应的子类来实现。

 

范例1

一个简单的例子

Message[] msgs = null;

try {

    Folder folder = getFolder(user, folderName);

    folder.open(Folder.READ_ONLY);

SearchTerm st = new AndTerm(new FromStringTerm( x@x.x ),    new SubjectTerm( xx ));

    msgs = folder.search(st);

} catch (MessagingException e) {

}

 

A、SearchTerm基础抽象类

javax.mail.search.SearchTerm

public abstract class SearchTerm implements Serializable

搜索条件表示为树的搜索方面,形成了一个搜索表达式的解析树。

代表这个类搜索条件。这是一个抽象类的子类实现特定的匹配方法。

搜索条件是序列化的,它允许存储在会话之间的搜索词。

 

 

AndTerm

 

 

This class implements the logical AND operator on individual SearchTerms.

这个类实现了逻辑上AND运算。

 

 

NotTerm

 

 

This class implements the logical NEGATION operator.

这个类实现了逻辑上NOT运算。

 

 

OrTerm

 

 

This class implements the logical OR operator on individual SearchTerms.

这个类实现了逻辑上OR运算。

 

 

ComparisonTerm

 

 

This class models the comparison operator.

这个类实现比较运算。

 

 

AddressTerm

 

 

This class implements Message Address comparisons.

这个类实现了邮件地址比较。

 

 

BodyTerm

 

 

This class implements searches on a message body.

这个类实现了对邮件正文的搜索。

 

 

DateTerm

 

 

This class implements comparisons for Dates

这个类实现日期的比较

 

 

FlagTerm

 

 

This class implements comparisons for Message Flags.

这个类实现了邮件标志的比较。

 

 

FromStringTerm

 

 

This class implements string comparisons for the From Address header.

这个类实现了From地址头的字符串比较。

 

 

FromTerm

 

 

This class implements comparisons for the From Address header.

这个类实现了From Address的比较。

 

 

HeaderTerm

 

 

This class implements comparisons for Message headers.

这个类实现了消息头进行比较。

 

 

IntegerComparisonTerm

 

 

This class implements comparisons for integers.

这个类实现对整数进行比较。

 

 

MessageIDTerm

 

 

This term models the RFC822  MessageId  - a message-id for Internet messages that is supposed to be unique per message.

这个类实现了MessageId进行比较。

 

 

MessageNumberTerm

 

 

This class implements comparisons for Message numbers.

这个类实现了Message numbers进行比较。

 

 

ReceivedDateTerm

 

 

This class implements comparisons for the Message Received date

这个类实现了接受时间进行比较。

 

 

RecipientStringTerm

 

 

This class implements string comparisons for the Recipient Address headers.

这个类实现了收件人进行比较。

 

 

RecipientTerm

 

 

This class implements comparisons for the Recipient Address headers.

这个类实现了收件人Address进行比较。

 

 

SentDateTerm

 

 

This class implements comparisons for the Message SentDate.

这个类实现了发送时间进行比较。

 

 

SizeTerm

 

 

This class implements comparisons for Message sizes.

这个类实现了邮件大小进行比较。

 

 

StringTerm

 

 

This class implements the match method for Strings.

这个类实现字符串匹配方法。

 

 

SubjectTerm

 

 

This class implements comparisons for the message Subject header.

这个类实现消息标题头进行比较。

 

 

[JavaMail]15 详解邮件标志和Flags

 javax.mail.Flags

public class Flags implements Cloneable, Serializable

Flags描述了一个message的一组Flag。Flag包括系统预订Flag和用户自定义Flag。

系统预订Flag由内部类Flags.Flag表示。用户自定义Flag由一个区分大小写String来表示。

大多数Folder实现会支持这组系统自定义。Folder的getPermanentFlags返回所有支持的Flag。

 

javax.mail.Flags.Flag

public static final class Flags.Flag

静态属性

static Flags.Flag       ANSWERED

          This message has been answered.

static Flags.Flag       DELETED

          This message is marked deleted.

static Flags.Flag       DRAFT

          This message is a draft.

static Flags.Flag       FLAGGED

          This message is flagged.

static Flags.Flag       RECENT

          This message is recent.

static Flags.Flag       SEEN

          This message is seen.

static Flags.Flag       USER

          A special flag that indicates that this folder supports user defined flags.

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值