第18章 Java Mail

Java Mail是提供给开发者处理电子邮件相关的编程接口。它是Sun发布的用来处理E-mail的API。它可以方便地执行一些常用的邮件传输。我们可以基于Java Mail开发出类似于Microsoft Outlook的应用程序。常用的发送邮件的协议是SMTP,接收邮件的协议是POP3,几乎所有的邮件服务器都采用这两个协议。在使用Java Mail时,还要使用另一标准扩展:JAF (JavaBean Activation Framework)。

实例176 发送邮件

SMTP(Simple Mail Transfer Protocol)协议是目前最流行的发送电子邮件的协议,Java Mail API能以SMTP协议发送电子邮件,虽然Java Mail是Sun的API之一,但它目前还没有被加在标准的Java开发工具包中(JDK),这就意味着你在使用前必须另外下载JavaMail文件。Java Mail文件包括mail.jar和activation.jar,将这两个jar包复制到工程的ClassPath中即可。本实例将演示如何使用Java Mail API发送简单的SMTP协议邮件,如文本邮件、HTML邮件。

技术要点

使用Java Mail,以SMTP协议发送电子邮件的技术要点如下:

• Session类:Session类定义了一个基本的邮件会话。通过该会话可让别的工作顺利执行。可以通过Session类的getDefaultInstance()方法获取Session对象,Session对象利用Java.util.Properties对象获取诸如邮件服务器、用户名、密码等信息,以及其他可在整个应用程序中共享的信息。

• Message类:由于Message是一个抽象类,所以可以使用javax.mail.internet. MimeMessage这个子类,该类是使用MIME类型、MIME信息头的邮箱信息。信息头只能使用US-ASCII字符,而非ASCII字符将通过编码转换为ASCII的方式使用。为了建立一个MimeMessage对象,必须将Session对象作为MimeMessage构造方法的参数传入:

MimeMessage message = new MimeMessage(session);

• Address类:由于Address类也是一个抽象类,所以只能使用javax.mail.internet. InternetAddress这个子类。创建Address对象的形式如:Address address = new InternetAddress(""),其中需要传入一个代表邮件地址的字符串作为参数。

• Authenticator类:Java Mail API可以利用Authenticator通过用户名和密码访问邮件服务器。Authenticator是抽象类,所以只能使用继承该抽象类的子类对象,并且必须重写返回类型为PasswordAuthentication的getPasswordAuthentication()方法。子类对象创建后,需要向Session注册Authenticator,使Session能够了解在认证时该使用哪个类。

• Transport类:此类的主要作用是发送信息,由于Transport类是一个抽象类,所以可以调用Transport的send静态方法发送邮件,参数为一个Message对象,如:Transport. send(message);

实现步骤

(1)新建一个类名为Send_Mail.java。

(2)代码如下所示:

Send_Mail.java处理邮件发送信息,具体代码如下:

package chp18;
import java.util.Date;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
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 Send_Mail {
    //以文本格式发送邮件,mailSender:待发送的邮件信息
    public static boolean Mail_Text(Mail_SendProper mailSender) {
          MailAttorney attorney = null;
          if (mailSender.isIsvalidate()) {                //判断是否需要身份认证
                attorney = new MailAttorney(mailSender.getUserName(),
    //如果需要身份认证,则创建一个密码验证器
                            mailSender.getPassword());
          }
          //根据邮件会话属性和密码验证器构造一个发送邮件的session
          Session sendMailSession = Session.getInstance(mailSender
                    .getProperties(), attorney);
          try {
                Message mailMessage = new MimeMessage(sendMailSession);
              //根据session创建一个邮件消息
              Address from = new InternetAddress(mailSender.getSendAddress());
              //创建邮件发送者地址
              mailMessage.setFrom(from);                  //设置邮件消息的发送者
              //创建邮件的接收者地址,并设置到邮件消息中
              Address to = new InternetAddress(mailSender.getReceiveAddress());
              mailMessage.setRecipient(Message.RecipientType.TO, to);
              mailMessage.setSubject(mailSender.getSubject());
                                                         //设置邮件消息的主题
              mailMessage.setSentDate(new Date());       //设置邮件消息发送的时间
              String mailContent = mailSender.getContent();
                                                   //获取Mail_SendProper类中封装的内容
              mailMessage.setText(mailContent);          //设置邮件消息的主要内容
              Transport.send(mailMessage);               //发送邮件
              return true;
          } catch (MessagingException ex) {
              ex.printStackTrace();
          }
          return false;
      }
      //以HTML格式发送邮件,mailSender:待发送的邮件信息
      public static boolean Html_Mail(Mail_SendProper mailSender) {
          MailAttorney attorney = null;
          if (mailSender.isIsvalidate()) {       //判断是否需要身份认证
              attorney = new MailAttorney(mailSender.getUserName(), mailSender
                        .getPassword());   //如果需要身份认证,则创建一个密码验证器
          }
          Session sendMailSession = Session.getInstance(mailSender
                    .getProperties(), attorney);
                    //根据邮件会话属性和密码验证器构造一个发送邮件的session
          try {
              Message mailMessage = new MimeMessage(sendMailSession);
                                                        //根据session创建一个邮件消息
              Address from = new InternetAddress(mailSender.getSendAddress());
                                                        //创建邮件发送者地址
              mailMessage.setFrom(from);                //设置邮件消息的发送者的地址
              Address to = new InternetAddress(mailSender.getReceiveAddress());
              //创建邮件的接收者地址,并设置到邮件消息中
              mailMessage.setRecipient(Message.RecipientType.TO, to);
              //Message.RecipientType.TO属性表示接收者的类型为TO
              mailMessage.setSubject(mailSender.getSubject()); //设置邮件消息的主题
              mailMessage.setSentDate(new Date());     //设置邮件消息发送的时间
              Multipart mainPart = new MimeMultipart();
              //MimeMultipart类是一个容器类,包含MimeBodyPart类型的对象
              BodyPart html = new MimeBodyPart();      //创建一个包含HTML内容的MimeBodyPart
              html.setContent(mailSender.getContent(), "text/html; charset=GBK");
                                                        //设置HTML内容
              mainPart.addBodyPart(html);
              mailMessage.setContent(mainPart);         //将MimeMultipart对象设置为邮件内容
              Transport.send(mailMessage);              //发送邮件
              return true;
          } catch (MessagingException ex) {
              ex.printStackTrace();
          }
          return false;
      }
      public static void main(String[] args) {
          //创建Mail_SendProper类的对象,用于获取邮件的基本信息
          Mail_SendProper mailSender = new Mail_SendProper();
          mailSender.setHost("smtp.sina.com.cn");
          mailSender.setPort("25");
          mailSender.setIsvalidate(true);
          mailSender.setUserName("**********"); //请填写正确的且存在的用户名
          mailSender.setPassword("*********");  //请填写正确的且存在的密码
          mailSender.setSendAddress("**********@sina.com");
                                                //请填写正确的且存在的发送人地址
        mailSender.setReceiveAddress("*********@sina.com");
                                                //请填写正确的且存在的接收人地址
        mailSender.setSubject("我的邮件测试");
        mailSender.setContent("我的邮件测试 My First Mail\n\rMy test mail\n\r 测试成功");
        Send_Mali.Mail_Text(mailSender);        //以文本格式发送邮件
        Send_Mali.Html_Mail(mailSender);        //以HTML格式发送邮件
    }
}

Mail_SendProper.java是发送邮件需要使用的基本信息,具体代码如下:

package chp18;
import java.util.Properties;
public class Mail_SendProper {
//发送邮件的服务器的IP和端口
    private String Host;
    private String Port = "25";
    private String SendAddress;                  //邮件发送者的地址
    private String ReceiveAddress;               //邮件接收者的地址
    //登录邮件发送服务器的用户名和密码
    private String userName;
    private String password;
    private boolean isvalidate = true;           //是否需要身份验证
private String subject; //邮件主题 private String content; //邮件的文本内容 private String[] attachFileNames; //邮件附件的文件名 //获得邮件会话属性 public Properties getProperties(){ Properties p = new Properties(); p.put("mail.smtp.host", this.Host); p.put("mail.smtp.port", this.Port); p.put("mail.smtp.auth", isvalidate ? "true" : "false"); return p; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getHost() { return Host; } public void setHost(String host) { Host = host; } public boolean isIsvalidate() { return isvalidate; } public void setIsvalidate(boolean isvalidate) { this.isvalidate = isvalidate; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPort() { return Port; } public void setPort(String port) { Port = port; } public String getReceiveAddress() { return ReceiveAddress; } public void setReceiveAddress(String receiveAddress) { ReceiveAddress = receiveAddress; } public String getSendAddress() { return SendAddress; } public void setSendAddress(String sendAddress) { SendAddress = sendAddress; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; }
}

MailAttorney.java是邮件身份认证器,在发送邮件时使用。具体代码如下:

package chp18;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
public class MailAttorney extends Authenticator{
//登录发送邮件服务器的用户名和密码
    private String userName;
    private String password;
    public MailAttorney (String userName, String password){
          this.userName = userName;
          this.password = password;
    }
    //覆盖父类的该方法,获得密码认证器
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(userName, password);
    }
        public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}

(3)运行结果可以到接收邮箱中查看,HTML格式的邮件如图18-1所示。

文本格式的邮件如图18-2所示。

图18-1 Html格式邮件

图18-2 文本格式邮件

源程序解读

1. Mail_SendProper类

该类定义了发送邮件时需要的信息,包括SMTP邮件发送服务器的IP地址和端口、邮件发送者和接收者的邮件地址、是否需要身份验证、身份验证时的用户名和密码、邮件的主题和文本内容,以及邮件附件的文件名。

getProperties()方法的作用是获得邮件会话属性,将邮件会话属性保存到一个java.util. Properties对象中,mail.smtp.host属性表示SMTP服务器的地址(IP地址或者域名);mail.smtp.port属性表示SMTP服务器的端口;mail.smtp.auth属性表示登录SMTP服务器时是否需要身份认证,true表示需要身份验证反之则不需要。

2. MailAttorney类

定义了邮件身份认证器,继承Authenticator抽象类。

重写了父类的getPasswordAuthentication方法,将登录SMTP服务器的用户名和密码构造成一个PasswordAuthentication对象返回。当发送邮件需要身份认证时,将会调用该方法。

3. Send_Mail类

该类以SMTP协议发送简单邮件,包括文本邮件和HTML邮件。

(1)Mail_Text方法发送文本邮件,参数为Mail_SendProper对象。

根据Mail_SendProper的isIsvalidate方法判断是否需要身份认证,如果需要身份认证,则用用户名和密码构造一个MailAttorney对象。调用Session的getInstance方法获得一个邮件会话,例如:Session.getInstance(mailSender.getProperties(), attorney);第一个参数指定了邮件会话属性,第二个参数指定了邮件身份认证器。根据session创建一个邮件消息,用它来存储邮件内容,将邮件发送者的地址封装成InternetAddress对象。

• 调用MailMessage.setFrom()方法设置邮件发送者,将邮件接收者的地址封装成InternetAddress对象,

• 调用MailMessage.setRecipient方法设置邮件接收者,Message.RecipientType.TO常量表示该接收者是收件人。

• 通过MailMessage.setSubject()设置邮件的主题。

• 通过MailMessage.setSentDate()设置邮件的发送时间。

• 通过MailMessage.setText()设置邮件的文本内容。

• 通过Transport.send()发送邮件。

(2)Html_Mail()方法发送HTML邮件,参数为Mail_SendProper对象。除了在设置邮件内容时与发送文本邮件不同以外,其他步骤与发送文本邮件一样。

给MimeMessage设置HTML内容时,需要使用MimeMultipart类,一封MIME邮件的内容是一个MimeMultipart对象,而一个MimeMultipart可以包含多个MimeBodyPart,一个MimeBodyPart存放一个子内容,如一段HTML代码、一个文件等。

调用MimeBodyPart的setContent方法设置邮件的子内容,它的第一个参数指定了邮件子内容,第二个参数指定了邮件内容的格式,“text/html; charset=GBK”表示以HTML格式编辑邮件子内容,而且字符编码是GBK,支持中文。调用MimeMultipart的addBodyPart方法把子内容添加到MimeMultipart中,最后调用MimeMessage的setContent方法把MimeMultipart设置为邮件的内容,调用Transport的send静态方法发送邮件。

实例177 发送附件邮件

实例177实现了用SMTP发送文本邮件和HTML邮件,但是在发送邮件的时候,往往会以附件的形式发送。本实例将演示如何使用Java Mail API发送带有附件的邮件(附件可以是任何形式的文件,而且数量没有限制)。

技术要点

发送带附件的邮件的技术要点如下:

• 发送带附件的邮件时必须使用MimeMultipart类和MimeBodyPart类。MimeMultipart类是Multipart抽象类的子类,也是一个容器类,包含MimeBodyPart类型的对象。MimeBodyPart类表示MIME正文部分,可以存储HTML子内容,也可以存储二进制数据,如图片。

• MimeMultipart类的addBodyPart(BodyPart part)方法将BodyPart添加到Multipart中。

• MimeBodyPart的setDataHandler方法将给定的 DataHandler 对象设置为此AttachmentPart对象的数据处理程序。然后通过FileDataSource的构造方法将文件的File对象作为参数创建文件数据源FileDataSource对象,最后通过DataHandler的构造方法,将FileDataSource对象作为参数,创建DataHandler对象,这样就可以把文件内容设置到邮件消息中,便形成了邮件的附件。

• MimeBodyPart的setFileName方法给附件设置文件名。

实现步骤

(1)新建一个类名为Send_Attachments.java。

(2)代码如下所示:(本示例中调用了上面程序中的MailAttorney.java和Mail_SendProper.java)

package chp18;
import java.io.File;
import java.util.Date;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.BodyPart;
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;
import javax.mail.internet.MimeUtility;
//发送带附件的邮件
public class Send_Attachments {
    public static boolean Send_Mail(Mail_SendProper mailSender) {
          MailAttorney authenticator = null;
          if (mailSender.isIsvalidate()) {       //判断是否需要身份认证
                authenticator = new MailAttorney(mailSender.getUserName(),
                          mailSender.getPassword());//如果需要身份认证,则创建一个密码验证器
          }
          Session sendMailSession = Session.getInstance(mailSender
                    .getProperties(), authenticator);
                      //根据邮件发送的属性和密码验证器构造一个发送邮件的session
          try {
Message mailMessage = new MimeMessage(sendMailSession); //根据session创建一个邮件消息 Address from = new InternetAddress(mailSender.getSendAddress()); //创建邮件的发送者地址 mailMessage.setFrom(from); //设置邮件消息的发送者地址 Address to = new InternetAddress(mailSender.getReceiveAddress()); //创建邮件的接收者地址 mailMessage.setRecipient(Message.RecipientType.TO,to); //设置邮件消息的接收者地址 mailMessage.setSubject(mailSender.getSubject()); //设置邮件消息的主题 mailMessage.setSentDate(new Date()); //设置邮件消息发送的时间 Multipart mainPart = new MimeMultipart(); //MimeMultipart类是一个容器类,包含MimeBodyPart类型的对象 BodyPart html = new MimeBodyPart(); //创建一个包含HTML内容的MimeBodyPart html.setContent(mailSender.getContent(), "text/html; charset=GBK"); //设置HTML内容 mainPart.addBodyPart(html); String[] attachFileNames = mailSender.getAttachFileNames(); //为邮件添加附件 if (attachFileNames != null && attachFileNames.length > 0) { MimeBodyPart attachment = null; //存放邮件附件的MimeBodyPart File file = null; for (int i = 0; i < attachFileNames.length; i++) { attachment = new MimeBodyPart(); file = new File(attachFileNames[i]); //根据附件文件创建文件数据源 FileDataSource fds = new FileDataSource(file); attachment.setDataHandler(new DataHandler(fds)); attachment.setFileName(MimeUtility.encodeWord(file.getName(),"GBK",null)); //为附件设置文件名 mainPart.addBodyPart(attachment); } } mailMessage.setContent(mainPart); //将MimeMultipart对象设置为邮件内容 Transport.send(mailMessage); //发送邮件 return true; } catch (Exception e) { e.printStackTrace(); return false; } }
public static void main(String[] args) { //创建邮件信息 Mail_SendProper mailSender = new Mail_SendProper(); mailSender.setHost("smtp.sina.com.cn"); mailSender.setPort("25"); mailSender.setIsvalidate(true); mailSender.setUserName("******"); mailSender.setPassword("******"); mailSender.setSendAddress("******@sina.com"); mailSender.setReceiveAddress("******@sina.com"); mailSender.setSubject("带附件的邮件测试"); mailSender.setContent("我一共上传了2个附件,注意查收一下\n\rThere are two Annex,Attention to find \n\r 测试成功"); String[] fileNames = new String[2]; fileNames[0] = "D:/abc/close.jpg"; fileNames[1] = "D:/abc/第2章001.doc"; mailSender.setAttachFileNames(fileNames); Send_Attachments. Send_Mail (mailSender); } }

(3)运行结果如图18-3所示。

图18-3 带附件的邮件

源程序解读

Send_Mail()构造方法发送带附件的邮件,参数为Mail_SendProper对象,通过Mail_SendProper对象来判断是否需要身份认证。

发送附件邮件与发送普通邮件一样,首先构造邮件会话Session,然后根据Session创建一个MimeMessage对象并设置相关的信息,如发送者地址、接收者地址、主题、发送时间和文本内容等。

MimeBodyPart保存附件的步骤如下:

(1)构造File对象。

(2)将File构造成FileDataSource对象。

(3)将FileDataSource对象作为参数构造DataHandler对象。

(4)调用MimeBodyPart的setDataHandler方法把附件添加到MimeBodyPart中。

(5)调用MimeBodyPart的setFileName()方法为附件设置文件名。

(6)调用MimeUtility的encodeWord()方法将文件名用GBK字符集进行编码。目的是使文件名可以支持中文。

(7)调用MimeMultipart的addBodyPart()方法把构建好的MimeBodyPart对象保存到邮件消息中。

(8)调用MimeMessage的setContent()方法把MimeMultipart设为邮件内容。

实例178 一对多的发送方式

利用Java Mail API不仅能实现普通的邮件发送,同时还能实现同时给多人发送邮件的功能。本实例将演示如何将邮件抄送实现一对多的发送方式。

技术要点

用Java Mail API发送邮件实现一对多的发送方式的技术要点如下。

MimeMessage的setRecipients((Message.RecipientType type, String addresses)方法将指定的接收方类型设置为给定的地址。如果地址参数addresses为null,则移除相应的接收方字段。Message.RecipientType常量如下所示:

• Message. RecipientType.TO常量表示收件人类型是邮件接收者。

• Message.RecipientType.CC常量表示收件人类型是抄送者。

• Message.RecipientType.BCC常量表示收件人的类型是密送者。

实现步骤

(1)新建一个类名为OneToMany_sender.java。

(2)代码如下所示:

package chp18;
import java.util.Date;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
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 OneToMany_sender {
    public static boolean sendMailOneToMany(OneToMany_senderInfo Info) {
          MailAttorney authenticator = null;
          if (Info.isIsvalidate()) {      //是否进行身份验证
              authenticator = new MailAttorney(Info.getUserName(), Info
                        .getPassword());
          }
          Session sendMailSession = Session.getInstance(Info.getProperties(),
                    authenticator); //根据邮件会话属性和密码验证器构造一个发送邮件的session
          try {
              Message mailMessage = new MimeMessage(sendMailSession);
              Address from = new InternetAddress(Info.getSendAddress());
                                         //创建邮件发送者地址
              mailMessage.setFrom(from); //创建邮件的接收者地址,并设置到邮件消息中
              Address[] ad = null;       //定义Address型数组,用来存放每个接收者的地址
              String[] receivers = Info.getReceive(); //获得定义好的地址
              if (receivers != null) {
                    ad = new InternetAddress[receivers.length];//为每个邮件接收者创建一个地址
                    for (int i = 0; i < receivers.length; i++) {
                            ad[i] = new InternetAddress(receivers[i]);
                  }
              } else {
                    ad = new InternetAddress[1]; //如果进行一对多发送,则发送给默认的接收者
                    ad[0] = new InternetAddress(Info.getReceiveAddress());
              }
              mailMessage.setRecipients(Message.RecipientType.TO, ad);
                                              //将所有接收者地址都添加到邮件接收者属性中
              mailMessage.setSubject("一对多邮件发送测试");
              mailMessage.setSentDate(new Date());
                                              //设置邮件内容
              Multipart mainPart = new MimeMultipart();
              BodyPart html = new MimeBodyPart();
              html.setContent("我同时发给了三个人\n\r他们收到了吗?", "text/html; charset=GBK");
              mainPart.addBodyPart(html);
              mailMessage.setContent(mainPart);
              Transport.send(mailMessage);                                   //发送邮件
              return true;
          } catch (MessagingException ex) {
              ex.printStackTrace();
          }
          return false;
    }
    //发送带抄送的邮件
          public static boolean send_Cc(OneToMany_senderInfo Info) {
          MailAttorney authenticator = null;
          if (Info.isIsvalidate()) {
                authenticator = new MailAttorney(Info.getUserName(), Info
                            .getPassword());
          }
          Session sendMailSession = Session.getInstance(Info.getProperties(),
                    authenticator);
          try {
              Message mailMessage = new MimeMessage(sendMailSession);
              Address from = new InternetAddress(Info.getSendAddress());
                                              //创建邮件发送者地址
              mailMessage.setFrom(from);
              Address to = new InternetAddress(Info.getReceiveAddress());
                                              //创建邮件的接收者地址,并设置到邮件消息中
              mailMessage.setRecipient(Message.RecipientType.TO, to);
              String[] cc = Info.getCcs();          //获取抄送者信息
              if (cc != null) {
                        Address[] ccAdresses = new InternetAddress[cc.length];
                                              //为每个邮件接收者创建一个地址
                        for (int i = 0; i < cc.length; i++) {
                              ccAdresses[i] = new InternetAddress(cc[i]);
                  }
                  mailMessage.setRecipients(Message.RecipientType.CC, ccAdresses);
                                              //将抄送者信息设置到邮件信息中
              }
              mailMessage.setSubject("抄送的邮件测试");
              mailMessage.setSentDate(new Date());
                                              //设置邮件内容
              Multipart mainPart = new MimeMultipart();
              BodyPart html = new MimeBodyPart();
              html.setContent("发送带抄送的邮件\n\r 测试成功", "text/html; charset=GBK");
              mainPart.addBodyPart(html);
              mailMessage.setContent(mainPart);
              Transport.send(mailMessage);                         //发送邮件
              return true;
          } catch (MessagingException ex) {
              ex.printStackTrace();
          }
          return false;
    }
    public static void main(String[] args) {
    //创建Mail_SendProper类的对象,用于获取邮件的基本信息
        OneToMany_senderInfo mailSender = new OneToMany_senderInfo();
        mailSender.setHost("smtp.sina.com.cn");
        mailSender.setPort("25");
        mailSender.setIsvalidate(true);
        mailSender.setUserName("******");
        mailSender.setPassword("******");
        mailSender.setSendAddress("******@sina.com");
        mailSender.setReceiveAddress("******@sina.com");
        String[]rec = newString[] {"******@sina.com", "******@163.com","******@sina.com" };
        String[] cc = rec;
        mailSender.setReceive(rec);
        mailSender.setCcs(cc);
        OneToMany_sender.sendMailOneToMany(mailSender);
        OneToMany_sender.send_Cc(mailSender);
    }
    //发送多接收者类型邮件的基本信息
    public static class OneToMany_senderInfo extends Mail_SendProper {
        private String[] rec;   //定义String数组,用来存放邮件的接收者
        private String[] cc;    //定义String数组,用来存放邮件的抄送者
        public String[] getCcs() {
              return cc;
        }
        public void setCcs(String[] cc) {
              this.cc = cc;
        }
        public String[] getReceive() {
              return rec;
        }
        public void setReceive(String[] rec) {
              this.rec = rec;
        }
    }
}

(3)运行结果:多个接收者的页面如图18-4所示。

(4)多个抄送者的页面如图18-5所示。

图18-4 多接收者

图18-5 多个抄送者

源程序解读

1. OneToMany_senderInfo类

该内部类定义了发送多收件人类型的邮件的基本信息,继承Mail_SendProper,能保存邮件接收者的地址列表和邮件抄送者的地址列表。例如:

private String[] rec;    //定义String数组,用来存放邮件的接收者
private String[] cc;     //定义String数组,用来存放邮件的抄送者

2. OneToMany_sender类

(1)sendMailOneToMany()方法发送邮件给多个接收者,参数为OneToMany_senderInfo对象。发送邮件的过程与实例176和177相同,故在此就不再做详细的讲解了。本实例的重点在于对邮件的收件人的设置,从OneToMany_senderInfo中获取接收者的地址列表,将每个地址都构造成InternetAddress对象,然后保存到InternetAddress数组中,调用MimeMessage的setRecipients方法,设置邮件的收件人,指定了收件人的类型为Message.RecipientType.TO,收件人的地址列表为InternetAddress数组。

(2)send_Cc()方法的主要功能是实现发送邮件给多个抄送者,参数为OneToMany_senderInfo对象。操作与sendMailOneToMany()方法相似,但是在设置邮件的收件人时,将指定收件人的类型改为Message.RecipientType.CC。

实例179 接收邮件

POP3(Post Office Protocol version 3)是一种常用的网络协议,POP3是邮局通信协定的第三个版本,是互联网上的一种通信协定,主要功能是用来传送电子邮件,从远程服务器的信箱里收取电子邮件。例如,当我们寄信给另外一个人时,对方当时多半不会在线上,所以邮件服务器必须为收信者保存这封信,直到收信者来检查这封信件。当收信人收信的时候,必须通过POP3通信协定,才能取得邮件。本实例将演示如何利用POP3接收邮件。

技术要点

用Java Mail API以POP3协议接收邮件的技术在点如下:

• Store类:该类代表了存储邮件的邮件服务器,用于存储和获取消息。

• Folder类:该类用于描述邮件的分级组织,如收件箱。通过Store的getFolder()方法可以创建一个Folder对象。

• Folder的open方法打开此Folder。此方法仅对可以包含Message并处于关闭状态的Folder有效。

• Folder的close方法关闭此Folder,此方法只对已打开的Folder对象有效。

• Folder的getMessages(int start,int end)方法获取从start到end消息编号范围内(包括start和end)Message对象。值得注意的是,消息编号从1而不是从0开始。

• Folder的getNewMessageCount方法获取此Folder中消息的总数,即新邮件的数量。

• Folder的getUnreadMessageCount方法获取此Folder中未读消息的总数,即未读邮件的数量。•MimeMessage的getFrom方法获得邮件的发件人地址列表。返回值类型为InternetAddress数组。

• MimeMessage的getRecipients方法获得邮件的收件人地址列表。返回值类型为InternetAddress数组。

• InternetAddress的getAddress方法获得邮件地址,InternetAddress的getPersonal方法获得邮件地址的个人信息。

• MimeMessage的getSubject方法获得邮件的主题。

• MimeMessage的getSentDate方法获得邮件的发送日期。

• MimeMessage的getMessageID方法获得邮件的ID(表示邮件)。

• 通过MimeMessage的getContent方法获得邮件的内容,如果邮件是MIME邮件,那么得到的是一个Multipart的对象;如果是普通的文本邮件,那么得到的是BodyPart对象。当BodyPart的MimeType类型为“multipart/ *”时,表示它是一个Multipart。

• 当一个BodyPart的disposition属性等于Part.ATTACHMENT或者Part.INLINE常量时,表示它带有附件。

实现步骤

(1)新建一个类名为Receive_Mail.java。

(2)代码如下所示。

Receive_Mail.java处理邮件接收信息,具体代码如下:

package chp18;
import java.io.*;
import java.util.Date;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
public class Receive_Mail {
    private R_MailInfo R_Info;                             //收邮件的参数配置
    private Store store;                                   //与邮件服务器连接后得到的邮箱
    private Folder folder;                                 //收件箱
    private Message[] mess;                                //收件箱中的邮件消息
    private Message C_Message;                             //当前正在处理的邮件消息
    private String C_FileName;                             //当前正在处理的文件名称
    private Session session;                               //创建与邮件服务器的会话
    String file_path = "";                                 //定义保存后的文本文件的地址
    public Receive_Mail(R_MailInfo R_Info) {               //构造方法
          this.R_Info = R_Info;
    }
                                                           //收邮件
    public void M_receiveMail() throws Exception {
          if (this.R_Info == null) {
                  throw new Exception("请载入接收邮件的参数!");
          }
          if (this.connectToServer()) {                    //连接到服务器
                if (this.openInBoxFolder()) {              //打开收件箱
                        this.getAllMail();                 //获取所有邮件
                        this.closeConnection();
              } else {
                        throw new Exception("*****进入收件夹失败!*****");
              }
          } else {
                throw new Exception("*****邮件服务器连接失败!*****");
          }
    }
                                                           //登录邮件服务器
    private boolean connectToServer() {
        MailAttorney authenticator = null;
        if (this.R_Info.isIsvalidate()) {                  //判断是否需要身份认证
                                                      //如果需要身份认证,则创建一个密码验证器
              authenticator = new MailAttorney(this.R_Info.getUserName(),
                        this.R_Info.getPassword());
        }
        session = Session.getInstance(this.R_Info.getProperties(),
                    authenticator);                        //创建session
        try {
              this.store = session.getStore(this.R_Info.getProtocal());//创建store
        } catch (NoSuchProviderException e) {
              System.out.println("连接服务器失败!");
              return false;
        }
        System.out.println("正在连接服务器,请稍候⋯⋯");
        try {
              this.store.connect();                        //建立连接
        } catch (MessagingException e) {
              System.out.println("连接服务器失败!");
              return false;
        }
        System.out.println("连接服务器成功");
        return true;
    }
                                                           //打开收件夹
    private boolean openInBoxFolder() {
        try {
              this.folder = store.getFolder("INBOX");
              folder.open(Folder.READ_WRITE);              //设置文件夹的状态为可读写
              Message[] massge = folder.getMessages();     //获得此文件夹中的所有信息
              for (int i = 0; i < massge.length; i++) {
                        massge[i].setFlag(Flags.Flag.DELETED,
              true);    //标记此邮件的flag标志对象的DELETED位为true,可以在读完邮件后直接删除该附件
                  try {
                        handle_Multipart(massge[i]);
                  } catch (Exception e) {
                        e.printStackTrace();
                  }
                  System.out
                            .println("********************************************************");
              }
              return true;
        } catch (MessagingException e) {
                System.err.println("收件夹信息获取失败!");
        }
        return false;
    }
    private void handle_Multipart(Message massge) {
        try {
            handle(massge);
            String disposition;
            BodyPart part;
            Multipart mp = (Multipart) massge.getContent();
            int mpCount = mp.getCount();
            //获得此邮件中附件的个数
            for (int m = 0; m < mpCount; m++) {
                    part = mp.getBodyPart(m);
                    disposition = part.getDisposition();
                    if (disposition != null && disposition.equals(Part.ATTACHMENT)) {
                        M_saveAnnex(part);
                  } else {
                        System.out.println(part.getContent());
                  }
            }
        } catch (Exception e) {
        }
    }
    private void M_saveAnnex(BodyPart part) {          //保存附件
        String fileName;
        try {
              fileName = getFileName(part);            //获得附件的名称
              System.out.println("有附件: " + fileName);
              InputStream in = part.getInputStream();
              FileOutputStream writer = new FileOutputStream(new File(
                          "F:\\attachments\\" + fileName));     //创建文件输出流
              System.out.println("保存路径为: " + "F:\\attachments\\" + fileName);
              byte[] b = new byte[255];
              int length = 0;
              while ((length = in.read(b)) != -1) {
                  writer.write(b);                     //将流写入指定的文件
            }
            writer.close();
            in.close();
        } catch (Exception e) {
        }
    }
    private void handle(Message massge) throws Exception {
        System.out.println("邮件主题:" + massge.getSubject());
        System.out.println("发送日期:" + massge.getSentDate());
        System.out.println("发送地址:" + massge.getFrom()[0]);
    }
    //断开与邮件服务器的连接
    private boolean closeConnection() {
        try {
              if (this.folder.isOpen()) {
                    this.folder.close(true);
            }
            this.store.close();
            System.out.println("成功关闭与邮件服务器的连接!");
              return true;
          } catch (Exception e) {
              System.out.println("关闭和邮件服务器之间连接时出错!");
          }
          return false;
    }
    //获取mess中的所有邮件
    private void getAllMail() throws MessagingException {
    //从邮件文件夹获取邮件信息
          this.mess = this.folder.getMessages();
          System.out.println("总的邮件数目:" + mess.length);
          System.out.println("新邮件数目:" + this.getNewMessageCount());
          System.out.println("未读邮件数目:" + this.getUnreadMessageCount());
          //将要下载的邮件的数量
          int mailArrayLength = this.getMessageCount();
          System.out.println("一共有邮件" + mailArrayLength + "封");
          int successCounter = 0;
          int errorCounter = 0;
          for (int index = 0; index < mailArrayLength; index++) {
              try {
                    this.C_Message = (mess[index]);     //根据消息编号获取消息
                    System.out.println("正在获取第" + (index + 1) + "封邮件......");
                    M_showMail(this.C_Message);         //显示该消息的基本信息
                    getMail();                                        //获取当前message
                    System.out.println("成功获取第" + (index + 1) + "封邮件");
                    successCounter++;
              } catch (Throwable e) {
                  errorCounter++;
                  System.err.println("下载第" + (index + 1) + "封邮件时出错");
              }
          }
          System.out.println("------------------");
          System.out.println("成功下载了" + successCounter + "封邮件");
          System.out.println("失败下载了" + errorCounter + "封邮件");
          System.out.println("------------------");
    }
    //显示邮件的基本信息
    private void M_showMail(Message message) throws Exception {
          System.out.println("发件人:" + this.getFrom());
          System.out.println("收件人:" + this.getTOAddress());
          System.out.println("抄送人:" + this.getCCAddress());
          System.out.println("密送人:" + this.getBCCAddress());
          System.out.println("主 题:" + this.getSubject());
          System.out.println("日 期::" + this.getSentDate());
          System.out.print("是新邮件?");
          System.out.println(this.isNew() ? "是" : "不是");
          System.out.print("要求回执?");
          System.out.println(this.getReplySign() ? "是" : "不是");
          System.out.print("包含附件?");
          System.out.println(this.isContainAttach() ? "包含" : "不包含");
          System.out.println("------------------------------");
    }
    //获得邮件的收件人,抄送和密送的地址和姓名,根据所传递的参数的不同,"to"表示收件人,"cc"
表示抄送人地址,"bcc"表示密送人地址
    private String getTOAddress() throws Exception {
        return getMailAddress("TO", this.C_Message);
    }
    private String getCCAddress() throws Exception {
        return getMailAddress("CC", this.C_Message);
    }
    private String getBCCAddress() throws Exception {
        return getMailAddress("BCC", this.C_Message);
    }
    //获得邮件地址,type表示类型,如收件人、抄送人、密送人,mimeMessage表示邮件消息
    private String getMailAddress(String type, Message mimeMessage)
              throws Exception {
        String mailaddr = "";
        String addtype = type.toUpperCase();
        InternetAddress[] address = null;
        if (addtype.equals("TO") || addtype.equals("CC")
                  || addtype.equals("BCC")) {
              if (addtype.equals("TO")) {
                    address = (InternetAddress[]) mimeMessage
                              .getRecipients(Message.RecipientType.TO);
              } else if (addtype.equals("CC")) {
                  address = (InternetAddress[]) mimeMessage
                              .getRecipients(Message.RecipientType.CC);
              } else {
                    address = (InternetAddress[]) mimeMessage
                              .getRecipients(Message.RecipientType.BCC);
              }
              if (address != null) {
                    for (int i = 0; i < address.length; i++) {
                          //先获取邮件地址
                          String email = address[i].getAddress();
                          if (email == null) {
                                  email = "";
                        } else {
                                  email = MimeUtility.decodeText(email);
                        }
                        //再取得个人描述信息
                        String personal = address[i].getPersonal();
                        if (personal == null) {
                              personal = "";
                        } else {
                              personal = MimeUtility.decodeText(personal);
                        }
                        //将个人描述信息与邮件地址连起来
                        String compositeto = personal + "<" + email + ">";
                        //多个地址时,用逗号分开
                        mailaddr += "," + compositeto;
                  }
                  mailaddr = mailaddr.substring(1);
              }
        } else {
              throw new Exception("错误的地址类型!!");
        }
        return mailaddr;
    }
    //获得发件人的地址和姓名
    private String getFrom() throws Exception {
        return getFrom(this.C_Message);
    }
    private String getFrom(Message mimeMessage) throws Exception {
        InternetAddress[] address = (InternetAddress[]) mimeMessage.getFrom();
        //获得发件人的邮箱
        String from = address[0].getAddress();
        if (from == null) {
              from = "";
        }
        //获得发件人的描述信息
        String personal = address[0].getPersonal();
        if (personal == null) {
                personal = "";
        }
        //拼成发件人完整信息
        String fromaddr = personal + "<" + from + ">";
        return fromaddr;
    }
    //获取mess中message的数量
    private int getMessageCount() {
          return this.mess.length;
    }
    //获得收件箱中新邮件的数量
    private int getNewMessageCount() throws MessagingException {
        return this.folder.getNewMessageCount();
    }
    //获得收件箱中未读邮件的数量
    private int getUnreadMessageCount() throws MessagingException {
        return this.folder.getUnreadMessageCount();
    }
    //获得邮件主题
    private String getSubject() throws MessagingException {
        return getSubject(this.C_Message);
    }
    private String getSubject(Message mimeMessage) throws MessagingException {
        String subject = "";
        try {
        //将邮件主题解码
              subject = MimeUtility.decodeText(mimeMessage.getSubject());
              if (subject == null) {
                    subject = "";
              }
        } catch (Exception exce) {
        }
        return subject;
    }
    //获得邮件发送日期
    private Date getSentDate() throws Exception {
        return getSentDate(this.C_Message);
    }
    private Date getSentDate(Message mimeMessage) throws Exception {
        return mimeMessage.getSentDate();
    }
    //判断此邮件是否需要回执,如果需要回执返回true,否则返回false
    private boolean getReplySign() throws MessagingException {
        return getReplySign(this.C_Message);
    }
    private boolean getReplySign(Message mimeMessage) throws MessagingException {
        boolean replysign = false;
        String needreply[] = mimeMessage
                    .getHeader("Disposition-Notification-To");
        if (needreply != null) {
              replysign = true;
        }
        return replysign;
    }
    private String getMessageId(Message mimeMessage) throws MessagingException {
        return ((MimeMessage) mimeMessage).getMessageID();
    }
    //判断此邮件是否已读,如果未读返回false,反之返回true
    private boolean isNew() throws MessagingException {
        return isNew(this.C_Message);
    }
    private boolean isNew(Message mimeMessage) throws MessagingException {
        boolean isnew = false;
        Flags flags = mimeMessage.getFlags();
        Flags.Flag[] flag = flags.getSystemFlags();
        for (int i = 0; i < flag.length; i++) {
              if (flag[i] == Flags.Flag.SEEN) {
                      isnew = true;
                      break;
            }
        }
        return isnew;
    }
    //判断此邮件是否包含附件
    private boolean isContainAttach() throws Exception {
        return isContainAttach(this.C_Message);
    }
    private boolean isContainAttach(Part part) throws Exception {
        boolean attachflag = false;
        if (part.isMimeType("multipart/*")) {
            //如果邮件体包含多部分
              Multipart mp = (Multipart) part.getContent();
              //遍历每部分
              for (int i = 0; i < mp.getCount(); i++) {
                    //获得每部分的主体
                    BodyPart bodyPart = mp.getBodyPart(i);
                    String disposition = bodyPart.getDisposition();
                    if ((disposition != null)
                                  && ((disposition.equals(Part.ATTACHMENT)) || (disposition
                                            .equals(Part.INLINE)))) {
                        attachflag = true;
                  } else if (bodyPart.isMimeType("multipart/*")) {
                          attachflag = isContainAttach((Part) bodyPart);
                  } else {
                          String contype = bodyPart.getContentType();
                          if (contype.toLowerCase().indexOf("application") != -1) {
                                  attachflag = true;
                        }
                        if (contype.toLowerCase().indexOf("name") != -1) {
                              attachflag = true;
                        }
                  }
              }
          } else if (part.isMimeType("message/rfc822")) {
              attachflag = isContainAttach((Part) part.getContent());
          }
          return attachflag;
    }
    //获得当前邮件
    private void getMail() throws Exception {
          try {
              this.saveMessageAsFile(C_Message);
              this.parseMessage(C_Message);
          } catch (Exception e) {
              throw new Exception("未知错误");
          }
    }
    //保存邮件源文件
    private void saveMessageAsFile(Message message) {
          try {
              //将邮件的ID中尖括号中的部分作为邮件的文件名
              String oriFileName = getInfoBetweenBrackets(this.getMessageId(
                        message).toString());
              //设置文件后缀名。若是附件则设法取得其文件后缀名作为将要保存文件的后缀名
              //若是正文部分则用.htm做后缀名
              String emlName = oriFileName;
              String fileNameWidthExtension = this.R_Info.getMail_path()
                          + oriFileName + this.R_Info.getEmailFileFormat();
              File storeFile = new File(fileNameWidthExtension);
              for (int i = 0; storeFile.exists(); i++) {
                    emlName = oriFileName + i;
                    fileNameWidthExtension = this.R_Info.getMail_path() + emlName
                            + this.R_Info.getEmailFileFormat();
                  storeFile = new File(fileNameWidthExtension);
              }
              this.C_FileName = emlName;
              System.out.println("邮件消息的存储路径: " + fileNameWidthExtension);
              //将邮件消息的内容写入ByteArrayOutputStream流中
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              message.writeTo(baos);
              StringReader in = new StringReader(baos.toString());//读取邮件消息流中的数据
              saveFile(fileNameWidthExtension, in);             //存储到文件
        } catch (MessagingException e) {
        } catch (Exception e) {
        }
    }
                                                                //解析邮件
    private void parseMessage(Message message) throws IOException,
                MessagingException {
        Object content = message.getContent();
                                                                //处理多部分邮件
        if (content instanceof Multipart) {
                handleMultipart((Multipart) content);
        } else {
                handlePart(message);
        }
    }
                                                                //解析Multipart
    private void handleMultipart(Multipart multipart)
                throws MessagingException, IOException {
        for (int i = 0, n = multipart.getCount() - 1; i < n; i++) {
                handlePart(multipart.getBodyPart(i));
        }
    }
                                                                //解析指定part,从中提取文件
    private void handlePart(Part part) throws MessagingException, IOException {
        String disposition = part.getDisposition();
        String contentType = part.getContentType();
        String fileNameWidthExtension = "";
                                                                //获得邮件的内容输入流
        InputStreamReader sbis = new InputStreamReader(part.getInputStream());
                                                                //没有附件的情况
        if (disposition == null) {
              if ((contentType.length() >= 10)
                            && (contentType.toLowerCase().substring(0, 10)
                                .equals("text/plain"))) {
                  fileNameWidthExtension = this.R_Info.getAtt_path()
                            + this.C_FileName + ".txt";
              } else if ((contentType.length() >= 9) //Check if html
                            && (contentType.toLowerCase().substring(0, 9)
                                .equals("text/html"))) {
                  fileNameWidthExtension = this.R_Info.getAtt_path()
                            + this.C_FileName + ".html";
              } else if ((contentType.length() >= 9) //Check if html
                            && (contentType.toLowerCase().substring(0, 9)
                                  .equals("image/gif"))) {
                  fileNameWidthExtension = this.R_Info.getAtt_path()
                            + this.C_FileName + ".gif";
              } else if ((contentType.length() >= 11)
                            && contentType.toLowerCase().substring(0, 11).equals(
                                  "multipart/*")) {
                  handleMultipart((Multipart) part.getContent());
              } else {
                  fileNameWidthExtension = this.R_Info.getAtt_path()
                            + this.C_FileName + ".txt";
              }
                                                                //存储内容文件
              file_path = this.R_Info.getAtt_path() + this.C_FileName
                          + ".txt";
              file_path = file_path.replace("\\", "");
              System.out.println("保存邮件内容到:" + fileNameWidthExtension);
              saveFile(fileNameWidthExtension, sbis);
              System.out.println("邮件内容为:");
              System.out.println(ReadFile() + "\n\n");
          }
    }
    private String getFileName(Part part) throws MessagingException,//获取附件名称
                UnsupportedEncodingException {
          String fileName = part.getFileName();
          fileName = MimeUtility.decodeText(fileName);
          String name = fileName;
          if (fileName != null) {
                  int index = fileName.lastIndexOf("/");
                  if (index != -1) {
                          name = fileName.substring(index + 1);
              }
          }
          return name;
    }
    //保存文件内容,filename: 文件名,input:输入流
    private void saveFile(String fileName, Reader input) throws IOException {
    //为了防止文件名重名,在重名的文件名后面添上数字
          File file = new File(fileName);
          //先取得文件名的后缀
          int lastDot = fileName.lastIndexOf(".");
          String extension = fileName.substring(lastDot);
          fileName = fileName.substring(0, lastDot);
          for (int i = 0; file.exists(); i++) {
                file = new File(fileName + i + extension); //如果文件重名,则添加i
          }
          //从输入流中读取数据,写入文件输出流
          FileWriter fos = new FileWriter(file);
          BufferedWriter bos = new BufferedWriter(fos);
          BufferedReader bis = new BufferedReader(input);
        int aByte;
        while ((aByte = bis.read()) != -1) {
            bos.write(aByte);
        }
        //关闭流
        bos.flush();
        bos.close();
        bis.close();
    }
        //读取文件内容
    public String ReadFile() {
        File file = new File(file_path);
        StringBuffer str = new StringBuffer();
        try {
              FileInputStream fi = new FileInputStream(file);
              byte[] by = new byte[(int) file.length()];
              int length = 0;
              while ((length = fi.read(by)) != -1) {
                    str.append(new String(by, 0, length));
            }
        } catch (FileNotFoundException e) {
        } catch (IOException e) {
        }
        return str.toString();
    }
    //获得尖括号之间的字符
    private String getInfoBetweenBrackets(String str) throws Exception {
        int i, j;                                    //用于标识字符串中的"<"和">"的位置
        if (str == null) {
                  str = "error";
                  return str;
        }
        i = str.lastIndexOf("<");
        j = str.lastIndexOf(">");
        if (i != -1 && j != -1) {
                str = str.substring(i + 1, j);
        }
        return str;
    }
    public static void main(String[] args) throws Exception {
        R_MailInfo Info = new R_MailInfo();
        Info.setHost("pop.163.com");
        Info.setPort("110");
        Info.setIsvalidate(true);
        Info.setUserName("******");
        Info.setPassword("******");
        Info.setAtt_path("F:/temp/mail/");
        Info.setMail_path("F:/temp/mail/");
        Receive_Mail receiver = new Receive_Mail(Info);
        receiver.M_receiveMail();
    }
}

R_MailInfo.java设置接收邮件的基本信息,具体代码如下:

package chp18;
import java.io.File;
import java.util.Properties;
public class R_MailInfo {
    //邮件服务器的IP、端口和协议
    private String Host;
    private String Port = "110";
    private String protocal = "pop3";
    //登录邮件服务器的用户名和密码
    private String userName;
    private String password;
    //保存邮件的路径
    private String att_path = "F:/temp/";
    private String mail_path = "F:/temp/";
    private String emailFileFormat = ".eml";
    //是否需要身份验证
    private boolean Isvalidate = true;
    / 获得邮件会话属性
    public Properties getProperties(){
          Properties p = new Properties();
          p.put("mail.pop3.host", this.Host);
          p.put("mail.pop3.port", this.Port);
          p.put("mail.pop3.auth", Isvalidate ? "true" : "false");
          return p;
    }
    public String getAtt_path() {
          return att_path;
    }
    public void setAtt_path(String att_path) {
          if (!att_path.endsWith(File.separator)){
                att_path = att_path + File.separator;
          }
          this.att_path = att_path;
    }
    public String getEmailFileFormat() {
          return emailFileFormat;
    }
    public void setEmailFileFormat(String emailFileFormat) {
          if (!emailFileFormat.startsWith(".")){
                emailFileFormat = "." + emailFileFormat;
          }
          this.emailFileFormat = emailFileFormat;
    }
    public String getHost() {
          return Host;
    }
    public void setHost(String host) {
          Host = host;
    }
    public boolean isIsvalidate() {
        return Isvalidate;
    }
    public void setIsvalidate(boolean isvalidate) {
        Isvalidate = isvalidate;
    }
    public String getMail_path() {
        return mail_path;
    }
    public void setMail_path(String mail_path) {
        if (!mail_path.endsWith(File.separator)){
                mail_path = mail_path + File.separator;
        }
        this.mail_path = mail_path;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getPort() {
        return Port;
    }
    public void setPort(String port) {
        Port = port;
    }
    public String getProtocal() {
        return protocal;
    }
    public void setProtocal(String protocal) {
        this.protocal = protocal;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}

(3)运行结果的初始页面如图18-6所示。

(4)对邮件进行保存的页面如图18-7所示。

(5)登录Outlook查看文件的页面如图18-8所示。

(6)下载附件的页面如图18-9所示。

(7)第二次运行结果如图18-10所示。

图18-6 Eclipse的输出结果

图18-7 邮件的保存

图18-8 用Outlook查看*.eml文件

图18-9 附件的下载

图18-10 第二次运行的结果

源程序解读

1. MailReceiverInfo类

该类定义了收邮件时的信息,包括邮件服务器的地址、端口、协议名、是否需要身份验证、验证时的用户名和密码、附件的存储路径、邮件的存储路径、邮件文件的后缀名。

• getProperties方法返回邮件会话属性,将邮件会话属性保存到一个java.util.Properties对象中。mail.pop3.host属性表示POP3服务器的地址(IP地址或者域名),mail.pop3.port属性表示POP3服务器的端口,mail.pop3.auth属性表示登录POP3服务器时是否进行身份验证。

2. MailReceiver类

(1)receiveAllMail方法用于接收所有邮件。

• 调用connectToServer方法连接POP3服务器。

• 调用openInBoxFolder方法打开收件箱。

• 调用getAllMail方法获取收件箱中的所有邮件。

• 调用closeConnection方法关闭连接。

(2)connectToServer方法连接POP3服务器。

• 根据邮件会话属性和身份验证器创建一个Session对象。

• 由Session对象的getStore方法创建一个Store对象,参数为POP3。

• 调用Store的connect方法连接到POP服务器上。

(3)openInBoxFolder方法打开Store上的收件箱。

• 调用Store的getFolder方法获得收件箱的Folder,参数为INBOX。

• 调用Folder的open方法打开收件箱,参数为Folder.READ_ONLY,表示以只读的方式打开。

(4)closeConnection方法关闭与POP3服务器的连接。

• 调用Folder的close方法关闭收件箱。

• 调用Store的close方法关闭连接。

(5)getAllMail方法获得收件箱中的所有邮件。(包括已读和未读)

• Folder的getMessages方法获得收件箱所有的邮件,返回值类型为Message[]。

• 调用showMailBasicInfo方法显示邮件的基本信息。包括发件人信息、接收者地址、抄送者地址、密送者地址、主题、发送时间、是否为新邮件、是否需要回执、是否包含附件。

• 调用getMail方法获取邮件。记录成功处理的邮件数和处理失败的邮件数。

(6)isContainAttach方法判断邮件是否包含附件。

• 调用getContent方法获得Multipart对象。

• 调用Multipart的getBodyPart方法获得邮件的BodyPart,如果BodyPart的disposition等于Part.ATTACHMENT或者Part.INLINE常量,表示它包含附件;如果BodyPart本身也是一个MIME的,则递归调用isContainAttach方法判断它是否包含附件;如果disposition为null,则获取BodyPart的contentType,如果contentType包含application或者name,也认为它包含附件。

(7)getMail方法获取邮件。

(8)saveMessageAsFile方法保存邮件本身。将邮件ID的尖括号部分当作邮件的文件名,根据邮件文件的存储路径和后缀名,构造邮件文件的存储路径。

• 调用Message的writeTo方法将邮件的内容写入到输出流中。

• 调用saveFile方法把输出流中的数据保存到文件。

(9)parseMessage方法分析邮件。

• 调用getContent方法获得邮件的内容,如果是MIME邮件,则邮件内容的类型为Multipart。

• 调用handleMultipart处理邮件,在handleMultipart方法中,依次处理Multipart包含的BodyPart,如果不是MIME邮件,则调用handlePart方法处理邮件。

• handlePart方法处理一个BodyPart。通过它的getInputStream方法获得BodyPart的输入流。判断BodyPart的disposition属性是否为null,若是,则表示它是普通的邮件。

• 根据contentType判断它的类型:text/plain表示文本邮件,保存到txt文件;text/html表示HTML邮件,保存到html文件;image/gif表示图片邮件,保存到gif文件;如果是其他类型,则保存到txt文件。调用saveFile方法将BodyPart的输入流保存到本地。

实例180 删除邮件

本实例实现邮件的接收,并选择接收的邮件是否删除,如果选择是,将删掉所选择的邮件。首先在Eclipse中运行该程序,将所有收到的邮件列出来,大家会看到共有3封邮件,再次启动该程序,输入Y删除其中的两封邮件,大家会看到邮件只剩下1封。

技术要点

删除邮件的技术要点如下:

• SetFlag()方法的运用,设Flags.Flag.DELETED标志。

• Java.mail API的使用技巧。

• Folder的设置为Folder.READ_WRITE。

• folder.close(true);的作用。

实现步骤

(1)新建一个类名为Delete_Mail.java。

(2)代码如下所示:

package chp18;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Properties;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Store;
public class Delete_Mail {
    static String username = "******";
    static String password = "******";
    static String host = "pop.163.com";
    static String port = "110";
    public static void main(String args[]) throws Exception {
        Properties props = new Properties();           //获取系统属性
        //设置 mail server
        props.put("mail.pop3.host", host);
        props.put("mail.pop3.port", port);
        props.put("mail.pop3.auth", "true");
        //是否通过验证,true表示需要进行身份验证;false表示不需要进行身份验证
        Session session = Session.getDefaultInstance(props); //获取Session
        Store store = session.getStore("pop3");       //获取Store
        store.connect(host, username, password);
        Folder folder = store.getFolder("INBOX");     //获取 INBOX 文件夹
        folder.open(Folder.READ_WRITE);               //文件夹设置为可读写
        Message message[] = folder.getMessages();     //获取该文件夹下的所有消息
        System.out.println("收件夹中共有" + message.length + " 封邮件");
        for (int i = 0, n = message.length; i < n; i++) {
                System.out.print("第" + (i + 1) + "封邮件: ");
                System.out.println("发件人:" + message[i].getFrom()[0]);
                System.out.println("日期:" + message[i].getSentDate());
                System.out.println("主题:" + message[i].getSubject());
                System.out.println("你确定要删除此消息吗? [Y to delete][O to Over]");
                BufferedReader reader = new BufferedReader(new InputStreamReader
                          (System.in));
                String line = reader.readLine();
                if ("Y".equals(line)) {
                        message[i].setFlag(Flags.Flag.DELETED, true);
                    //注意邮件将被直接删除,而不是保留在服务器的垃圾箱中
              } else if ("O".equals(line)) {
                  break;
              } else {
                  continue;
              }
        }
        //关闭连接
        folder.close(true);          //当folder关闭时,标志为DELETED的邮件将会被删除
        store.close();
        System.out.println("此收件夹中剩有" + getNewConnect() + " 封邮件");
    }
        //创建一个新的连接,用于显示删除邮件后的个数
    public static int getNewConnect() throws Exception {
        Properties props1 = new Properties();          //获取系统属性
        //设置 mail server
        props1.put("mail.pop3.host", host);
        props1.put("mail.pop3.port", port);
        props1.put("mail.pop3.auth", "true");
        //是否通过验证,true表示需要进行身份验证;false表示不需要进行身份验证
        Session session1 = Session.getDefaultInstance(props1); //获取Session
        Store store1 = session1.getStore("pop3");      //获取Store
        store1.connect("pop.163.com", username, password);
        Folder folder1 = store1.getFolder("INBOX");    //获取 INBOX 文件夹
        folder1.open(Folder.READ_WRITE);               //文件夹设置为可读写
        Message mess[] = folder1.getMessages();        //获取该文件夹下的所有消息
        return mess.length;
    }
}

(3)运行结果如图18-11所示。

图18-11 输出结果

源程序解读

(1)通过Session创建Store对象,通过Store对象的getFolder创建Folder对象,并将文件夹设置为可读写状态。

(2)通过Folder对象的getMessages()获取此文件夹下的所有消息并返回一个Message数组,数组的长度也就是消息的个数。

(3)使用for循环将Message数组中每个消息中的信息列出。例如:

• getFrom()[0]:获取发件人信息。

• getSentDate():获取日期信息。

• getSubject():获取主题信息。

(4)如果确定将哪条消息删除掉,则通过Message的setFlag()将Flags.Flag.DELETED的状态标识置为true。

(5)关闭连接folder.close(true)。当folder关闭时,标志为DELETED的邮件将会被删除。

(6)getNewConnect()方法的作用是创建一个新的连接,用于显示删除邮件后的个数,即返回Message的数组长度。

实例181 利用Java API发送E-mail

在地址栏中,发送邮件的JSP页面,输入邮件服务器、用户名、用户密码、邮件主题、收件人、发送人、邮件内容、附件,然后单击“发送”按钮,邮件就会通过邮件服务器发送邮件,最后就可以看到邮件发送成功。

技术要点

利用Java API发送E-mail的技术要点如下:

• 设置邮件服务器。

• FileDataSource()方法的使用。

• 类包Java.mail的作用。

实现步骤

(1)新建一个类名为JSPSendMail.java。

(2)代码如下所示。

JSPSendMail.java是用于处理邮件发送的核心,具体代码如下:

package chp18;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.activation.URLDataSource;
import javax.mail.BodyPart;
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;
import javax.mail.internet.MimeUtility;
public class JSPSendMail {
    public static String TEXT = "text/plain;charset=gb2312";
    public static String HTML = "text/html;charset=gb2312";
    private String host;         //邮件服务器
    private String user;         //用户名
    private String pass;         //用户密码
    private String from;         //发信人
    private String to;           //收信人
    private String cc;           //Carbon Copy, 抄送邮件给某人
    private String bc;           //bcc Blind Carbon Copy,隐蔽副本 隐蔽抄送给某人
    private String subject;      //邮件主题
    private BodyPart body;       //邮件内容
    private boolean needAuth;    //是否需要认证
    private List attaches;       //邮件附件
    /** 构造方法 */
    public JSPSendMail() {
          needAuth = true;
          attaches = new ArrayList();
    }
    /** 构造方法 */
    public JSPSendMail(String host) {
          needAuth = true;
          attaches = new ArrayList();
          this.host = host;
    }
    /** 构造方法 */
    public JSPSendMail(String host, String user, String pass) {
          needAuth = true;
          attaches = new ArrayList();
          this.host = host;
          this.user = user;
          this.pass = pass;
    }
    public static void main(String[] args) {
          new JSPSendMail();
    }
    //设置邮件服务器的基本信息
    public void setNeedAuth(boolean needAuth) {
        this.needAuth = needAuth;
    }
    public void setFrom(String from) {
        this.from = from;
    }
    public void setTo(String to) {
        this.to = to;
    }
    public String getPass() {
        return pass;
    }
    public String getUser() {
        return user;
    }
    public void setPass(String string) {
        pass = string;
    }
    public void setUser(String string) {
        user = string;
    }
    public String getFrom() {
        return from;
    }
    public String getHost() {
        return host;
    }
    public boolean isNeedAuth() {
        return needAuth;
    }
    public String getSubject() {
        return subject;
    }
    public void setHost(String string) {
        host = string;
    }
    public void setBlindTo(String bc) {
        this.bc = bc;
    }
    public void setCopyTo(String cc) {
        this.cc = cc;
    }
    public void setSubject(String subject) {
        this.subject = subject;
    }
    /** 设置邮件内容的形式 */
    public void setBody(String string, String contentType) {
        try {
              body = new MimeBodyPart();
              DataHandler dh = new DataHandler(string, contentType);
              body.setDataHandler(dh);
        } catch (Exception exception) {
        }
    }
    /** 设置邮件的内容的格式为文本格式 */
    public void setBodyAsText(String string) {
        setBody(string, TEXT);
    }
    /** 设置邮件的内容的格式为HTML格式 */
    public void setBodyAsHTML(String string) {
        setBody(string, HTML);
    }
    /** 从文件中自动导入邮件内容 */
    public void setBodyFromFile(String filename) {
        try {
              BodyPart mdp = new MimeBodyPart();
              FileDataSource fds = new FileDataSource(filename);
              DataHandler dh = new DataHandler(fds);
              mdp.setDataHandler(dh);
              attaches.add(mdp);
        } catch (Exception exception) {
        }
    }
    /** 从一个URL中导入邮件的内容 */
    public void setBodyFromUrl(String url) {
        try {
              BodyPart mdp = new MimeBodyPart();
              URLDataSource ur = new URLDataSource(new URL(url));
              DataHandler dh = new DataHandler(ur);
              mdp.setDataHandler(dh);
              attaches.add(mdp);
        } catch (Exception exception) {
        }
    }
    /** 将String中的内容存放入文件showname,并将这个文件作为附件发送给收件人,其中str 为
邮件的内容,name 显示的是文件的名字 */
    public void addAttachFromString(String str, String name) {
        try {
              BodyPart mdp = new MimeBodyPart();
              DataHandler dh = new DataHandler(str, TEXT);
              mdp.setFileName(MimeUtility.encodeWord(name, "gb2312", null));
              mdp.setDataHandler(dh);
              attaches.add(mdp);
        } catch (Exception exception) {
        }
    }
    /** 邮件附件重命名 */
    public void addAttachFromFile(String filename, String showname) {
        try {
              BodyPart mdp = new MimeBodyPart();
              FileDataSource fds = new FileDataSource(filename);
              DataHandler dh = new DataHandler(fds);
              mdp.setFileName(MimeUtility.encodeWord(showname, "gb2312", null));
              mdp.setDataHandler(dh);
              attaches.add(mdp);
        } catch (Exception exception) {
        }
    }
    /** url地址重名 */
    public void addAttachFromUrl(String url, String showname) {
        try {
              BodyPart mdp = new MimeBodyPart();
              URLDataSource ur = new URLDataSource(new URL(url));
              DataHandler dh = new DataHandler(ur);
              mdp.setFileName(MimeUtility.encodeWord(showname, "gb2312", null));
              mdp.setDataHandler(dh);
              attaches.add(mdp);
        } catch (Exception exception) {
        }
    }
    /** 发送邮件 */
    public void send() throws Exception {
        try {
              Properties props = new Properties();
              if (host != null && !host.trim().equals(""))
                    props.put("mail.smtp.host", host);
              else
                throw new Exception("没有指定发送邮件服务器");
              if (needAuth)
                    props.put("mail.smtp.auth", "true");
              Session s = Session.getInstance(props, null);
              MimeMessage massage = new MimeMessage(s);
                                                                //设置邮件主题
              massage.setSubject(subject);
                                                                //设置邮件发送时间
              massage.setSentDate(new Date());
                                                                //指定发件人
              if (from != null)
                    massage.addFrom(InternetAddress.parse(from));
              else
                  throw new Exception("没有指定发件人");
              //指定收件人
              if (to != null)
                    massage.addRecipients(javax.mail.Message.RecipientType.TO,
                            InternetAddress.parse(to));
              else
                  throw new Exception("没有指定收件人地址");
              //指定抄送给谁
              if (cc != null)
                    massage.addRecipients(javax.mail.Message.RecipientType.CC,
                            InternetAddress.parse(cc));
              //指定隐藏抄送给谁
              if (bc != null)
                  massage.addRecipients(javax.mail.Message.RecipientType.BCC,
                            InternetAddress.parse(bc));
              Multipart mt = new MimeMultipart();
              //设置邮件的附件
              if (body != null)
                    mt.addBodyPart(body);
              for (int i = 0; i < attaches.size(); i++) {
                    BodyPart part = (BodyPart) attaches.get(i);
                    mt.addBodyPart(part);
              }
              massage.setContent(mt);                               //设置邮件的内容
              massage.saveChanges();                                //保存所有改变
              Transport transport = s.getTransport("smtp");         //创建邮件服务器
              transport.connect(host, user, pass);                  //连接邮件服务器
              transport.sendMessage(massage, massage.getAllRecipients());//发送信息
              transport.close();                                    //关闭邮件传输
          } catch (Exception e) {
              throw new Exception("发送邮件失败:", e);
          }
    }
}

S_mail.jsp用于显示邮件发送信息的页面,代码如下:

<%@ page contentType="text/html;charset=gb2312" language="java"%>
<%@ page import="chp18-* ,java.util.Date"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
    <head>
          <title>发送邮件</title>
          <meta name="copyright" content="邮件发送">
          <meta name="Keywords" content="jsp,servlet,mail">
          <meta name="Description" content="发送邮件">
          <meta http-equiv="content-type" content="text/html; charset=gb2312">
    </head>
    <body>
          <%
              String mess = "";
              //从request中获取表单中的内容
              String host = request.getParameter("host");
              String user = request.getParameter("user");
              String password = request.getParameter("password");
              String subject = request.getParameter("subject");
              String to = request.getParameter("to");
              String from = request.getParameter("from");
              String bodyashtml = request.getParameter("bodyashtml");
              String attachfile = request.getParameter("attachfile");
              Date date = new Date();                      //创建Date对象,获取当前时间
              if(attachfile==null||attachfile.equals("")){ //判断该邮件是否带有附件
                              mess="不带附件";
                    }else{
                              mess="带附件";
                          }
                //内容的输出,展现在IE浏览器上
                out.println("<br><font color=#FF33CC ><B>主题:</B></font><font
color=#FF5809>" + subject+"</font>");
                out.println("<br><font color=#FF33CC ><B>发件人:</B></font><font
color=#FF5809>" + from+"</font>");
                out.println("<br><font color=#FF33CC ><B>收件人:</B></font><font
color=#FF5809>" + to+"</font>");
                out.println("<br><font color=#FF33CC ><B>发送日期:</B></font><font
color=#FF5809>" +date+"</font>");
                out.println("<br><font color=#FF33CC ><B>内容:</B></font><font
color=#FF5809>" + bodyashtml+"</font>");
                out.println("<br><font color=#FF33CC ><B>附件:</B></font><font
color=#FF5809>" + mess+"</font>");
                out.println("<br>");
                try {
                      JSPSendMail jsm = new JSPSendMail();   //创建JSPSendMail类对象
                      //将获取的信息传递给JSPSendMail类
                      jsm.setHost(host);
                      jsm.setUser(user);
                      jsm.setPass(password);
                      jsm.setSubject(subject);
                      jsm.setTo(to);
                      jsm.setFrom(from);
                      jsm.setBodyAsHTML(bodyashtml);
                      jsm.addAttachFromFile(attachfile, "index.txt");
                      jsm.send();
                      out.println("<br><fontsize=15color=#FF33CC >恭喜,恭喜,发送成功!!!</font>");
                      //打印出相应的信息
                } catch (Exception e) {
                    out.println("<br>" + e.getMessage());
                    out.println("<br><font size=15 color=#808040 >邮件发送失败!!!</font>");
                }
          %>
      </body>
</html>

T_mail.jsp用于JSP页面测试,代码如下:

<%@ page contentType="text/html;charset=gb2312" language="java" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
    <title>邮件测试</title>
    <meta name="copyright" content="邮件发送">
    <meta name="Keywords" content="jsp,servlet,mail">
    <meta name="Description" content="邮件测试">
    <meta http-equiv="content-type" content="text/html; charset=gb2312">
</head>
<body>
<form method="post" action="S_mail.jsp">
        <table border="1" bordercolor="#A6A6D2" bgcolor="#FFE6D9" cellpadding="0"
cellspacing="3" align="center" width="50%" height="50%">
            <tr>
                  <th>邮件服务器</th><td><input type="text" name="host" size="35"
value="smtp.sina.com.cn"></td>
            </tr>
            <tr>
                  <th>用户名</th><td><input type="text" name="user" size="35"
value="username"></td>
            </tr>
            <tr>
                  <th>密码</th><td><input type="password" name="password"
size="39" value="usepassword"></td>
            </tr>
            <tr>
                  <th>邮件主题</th><td><input type="text" name="subject" size="35"
value="QQ"></td>
            </tr>
            <tr>
                  <th>收件人</th><td><input type="text" name="to" size="35"
value="usename@sina.com"></td>
            </tr>
            <tr>
                  <th>发送人</th><td><input type="text" name="from" size="35"
value="usename @sina.com"></td>
            </tr>
            <tr>
                  <th>邮件内容</th><td><input type="text" name="bodyashtml"
size="35" value="QQWEERRRRR"></td>
            </tr>
            <tr>
                  <th>附件</th><td><input type="text" name="attachfile" size="35"
value="d:\\abc\\001.doc"></td>
            </tr>
            <tr>
                  <td colspan="2" align="center" ><input type="submit" name="submit"
value=" 发送 " >&nbsp;&nbsp;<input type="reset" name="reset" value=" 重置 " ></td>
            </tr>
        </table>
</form>
<center><p><font size="14" color="#00EC00"><B>正在发送,请稍候</B></font></p></center>
</body>
</html>

(3)运行结果:第一次运行该程序出现的是准备发送邮件的页面,如图18-12所示。

(4)单击“发送”按钮后,出现正在发送邮件页面,如图18-13所示。

(5)若发送成功,则会提示成功发送的页面,如图18-14所示。

(6)登录新浪页面,查看邮件页面,如图18-15所示。

图18-12 T_mail.jsp页面

图18-13 连接服务器

图18-14 S_mail.jsp页面

图18-15 新浪邮箱页面

源程序解读

(1)邮件服务器身份验证,通过设置mail.smtp.auth的值为true来解决。

(2)通过多种方式添加附件,将本地磁盘上的文件作为附件。并且在本地文件中可以上传相应的图片或其他文件,但是要注意文件的大小不能太大,最好不要超过1MB,如果文件过大,可能会引起服务器运行过慢,从而导致文件发送失败,所以选择小一点的文件为宜。

(3)在JSP页面中设定了多个属性,根据邮件的内容而有所不同,如用户名、密码、邮件服务器等。最后运行Tomcat之后,再运行JSP页面,就可以对邮件进行发送或其他操作。