发现以后就得多写博客,自己的表达能力还是不行,很多东西自己明白,但是写出来却比较有难度,如何表达的通俗易懂就更是难上加难了,以后得多写,提高自己~~
本文是一个简单的收取邮件的例子。
主要功能是:从服务器收取邮件,然后对邮件进行解析,解析出邮件的发件人、主题、内容、附件等。
使用的类库:JavaMail1.4.7,Apache的commons email1.3.1,另外还有javamail需要依赖jar包:activation.jar
实现过程如下:
1、定义一个简单的邮件收取类,作用连接邮件服务器,然后收取inbox里的邮件,返回Message[]
package com.athena.mail.receiver; import java.util.Properties; import javax.mail.Authenticator; import javax.mail.Folder; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.NoSuchProviderException; import javax.mail.Session; import javax.mail.Store; /** * 简单的邮件接收类 * * @author athena * */ public class SimpleMailReceiver { /** * 收取收件箱里的邮件 * * @param props * 为邮件连接所需的必要属性 * @param authenticator * 用户验证器 * @return Message数组(邮件数组) */ public static Message[] fetchInbox(Properties props, Authenticator authenticator) { return fetchInbox(props, authenticator, null); } /** * 收取收件箱里的邮件 * * @param props * 收取收件箱里的邮件 * @param authenticator * 用户验证器 * @param protocol * 使用的收取邮件协议,有两个值"pop3"或者"imap" * @return Message数组(邮件数组) */ public static Message[] fetchInbox(Properties props, Authenticator authenticator, String protocol) { Message[] messages = null; Session session = Session.getDefaultInstance(props, authenticator); // session.setDebug(true); Store store = null; Folder folder = null; try { store = protocol == null || protocol.trim().length() == 0 ? session.getStore() : session.getStore(protocol); store.connect(); folder = store.getFolder("INBOX");// 获取收件箱 folder.open(Folder.READ_ONLY); // 以只读方式打开 messages = folder.getMessages(); } catch (NoSuchProviderException e) { e.printStackTrace(); } catch (MessagingException e) { e.printStackTrace(); } return messages; } }2、定义一个邮件解析类,用来解析上面返回的Message[]
package com.athena.mail.receiver; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.util.List; import javax.activation.DataSource; import javax.mail.Address; import javax.mail.Folder; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Store; import javax.mail.internet.MimeMessage; import org.apache.commons.mail.util.MimeMessageParser; /** * 邮件解析类 * * @author athena * */ public class MessageParser { /** * 邮件附件存放位置 */ private static final String folder = "D:\\upload"; private static void parse(Message message) { try { MimeMessageParser parser = new MimeMessageParser((MimeMessage) message).parse(); String from = parser.getFrom(); // 获取发件人地址 List<Address> cc = parser.getCc();// 获取抄送人地址 List<Address> to = parser.getTo(); // 获取收件人地址 String replyTo = parser.getReplyTo();// 获取回复邮件时的收件人 String subject = parser.getSubject(); // 获取邮件主题 String htmlContent = parser.getHtmlContent(); // 获取Html内容 String plainContent = parser.getPlainContent(); // 获取纯文本邮件内容(注:有些邮件不支持html) System.out.println(subject); List<DataSource> attachments = parser.getAttachmentList(); // 获取附件,并写入磁盘 for (DataSource ds : attachments) { BufferedOutputStream outStream = null; BufferedInputStream ins = null; try { String fileName = folder + File.separator + ds.getName(); outStream = new BufferedOutputStream(new FileOutputStream(fileName)); ins = new BufferedInputStream(ds.getInputStream()); byte[] data = new byte[2048]; int length = -1; while ((length = ins.read(data)) != -1) { outStream.write(data, 0, length); } outStream.flush(); System.out.println("附件:" + fileName); } finally { if (ins != null) { ins.close(); } if (outStream != null) { outStream.close(); } } } } catch (Exception e) { e.printStackTrace(); } } public static void parse(Message... messages) { if (messages == null || messages.length == 0) { System.out.println("没有任何邮件"); } else { for (Message m : messages) { parse(m); } // 最后关闭连接 if (messages[0] != null) { Folder folder = messages[0].getFolder(); if (folder != null) { try { Store store = folder.getStore(); folder.close(false);// 参数false表示对邮件的修改不传送到服务器上 if (store != null) { store.close(); } } catch (MessagingException e) { // ignore } } } } } }
3、可以看到我在第1步的SimpleMailReceiver的方法fetchInbox方法的参数,其中一个是Properties,一个是Authenticator,做个邮件开发的都知道,这里不做解释。
为了方便用户使用,我为多个邮件服务器的一些基本信息进行了封装,如下:
package com.athena.mail.props; import java.util.Properties; /** * 服务器种类:提供了网易和腾讯的企业邮箱(这两种已经测试通过),和谷歌(测试未通过) 后期有需要可以扩展 * * @author athena */ public enum HostType { NETEASE { @Override public Properties getProperties() { Properties defaults = new Properties(); defaults.put("mail.pop3.host", "pop.163.com"); defaults.put("mail.imap.host", "imap.163.com"); defaults.put("mail.store.protocol", "pop3"); // 默认使用pop3收取邮件 return defaults; } }, TENCENT { @Override public Properties getProperties() { Properties defaults = new Properties(); defaults.put("mail.pop3.host", "pop.exmail.qq.com"); defaults.put("mail.imap.host", "imap.exmail.qq.com"); defaults.put("mail.store.protocol", "pop3"); // 默认使用pop3收取邮件 return defaults; } }, GMAIL { @Override public Properties getProperties() { Properties defaults = new Properties(); defaults.put("mail.pop3.host", "pop.gmail.com"); defaults.put("mail.pop3.port", "995"); defaults.put("mail.imap.host", "imap.gmail.com"); defaults.put("mail.imap.port", "465"); defaults.put("mail.store.protocol", "pop3"); // 默认使用pop3收取邮件 return defaults; } }; public abstract Properties getProperties(); }上面类的主要作用是方便用户使用,由于不同邮件服务器使用的地址以及参数都有所不同,而这些信息不会经常变化,所以就无需让用户操作了,用户使用的时候只需要获取她需要的服务器对象即可。
4、对Authenticator也进行了简单封装
package com.athena.mail.props; import javax.mail.Authenticator; import javax.mail.PasswordAuthentication; /** * 该类用来生成Authenticator * * @author athena * */ public final class AuthenticatorGenerator { /** * 根据用户名和密码,生成Authenticator * * @param userName * @param password * @return */ public static Authenticator getAuthenticator(final String userName, final String password) { return new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(userName, password); } }; } }
最后是一个简单的测试类:
package com.athena.mail.client; import com.athena.mail.props.AuthenticatorGenerator; import com.athena.mail.props.HostType; import com.athena.mail.receiver.MessageParser; import com.athena.mail.receiver.SimpleMailReceiver; /** * 邮件测试类 * * @author athena * */ public class MailTest { public static void main(String[] args) { MessageParser.parse(SimpleMailReceiver.fetchInbox(HostType.NETEASE.getProperties(), AuthenticatorGenerator.getAuthenticator("youraccount", "yourpassword"))); } }
后记:
本来对于Properties的封装我采用的继承Properties的方式,如下:
package com.athena.mail.props; import java.util.Properties; public class NeteaseProperties extends Properties { private static final long serialVersionUID = -6623862312603756003L; { defaults = new Properties(); defaults.put("mail.pop3.host", "pop.163.com"); defaults.put("mail.imap.host", "imap.163.com"); defaults.put("mail.store.protocol", "pop3"); // 默认使用pop3收取邮件 } }
即通过在子类中添加一个非静态初始化块(当然,在子类的构造函数中也可以),将Properties类的成员变量defaults进行实例化(Properties将put进去的值都放在defaults变量中)并赋给相应的值。但考虑到如果有很多邮箱的话,类的数量就增加了,而且这样的一种扩展方式也不是很好(原因我也不知道,就是感觉不太好),所以就该成了上面的枚举的方式