第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=" 发送 " > <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页面,就可以对邮件进行发送或其他操作。