需求:客户不定期将数据以excle文件发送到我司企业邮箱,我们要做的是用定时任务从邮箱拿到数据存到数据库,实现数据对接。
问题:在现在常用的两种协议pop3和imap中,都不符合开发:
- pop3协议没有办法判断邮件是否已读,如果使用pop3,每次都拿到全部数据,导致数据重复。常见的解决方法就是,每个邮件服务器会给每个邮件设置一个唯一的uid,客户端将这个uid保存,用来判断是不是已读,这也是现在常见客户端如firefox使用pop3的办法。
- imap协议可以判断和设置邮件已读,但是他读取邮件的速度非常慢,如果附件的占的储存比较大,会需要非常久的时间才能见附件下载下来(亲测1.5M 大小的文件,下载了5分钟)
因为暂时没有找到更好的方法,所以只能使用者两种,而根据需求,客户发来的数据不会很大,所以使用imap协议
- 获取邮件的信息
public static void downLoadDate(String file) throws Exception {
Properties props = new Properties();
props.setProperty("mail.store.protocol", protocol);
props.setProperty("mail.imap.host", host);
Session session = Session.getDefaultInstance(props);
Store store = session.getStore(protocol);
store.connect(account, password);
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
// 全部邮件数
Message[] messages = folder.getMessages();
for (int i = 0; i < messages.length; i++) {
Message message = messages[i];
// 如果是未读邮件,就下载下来,并设置为已读
Flags flags = message.getFlags();
System.out.println(flags.contains(Flags.Flag.SEEN));
System.out.println(Flags.Flag.SEEN);
if (flags.contains(Flags.Flag.SEEN)){
System.out.println("这是一封已读邮件");
} else {
System.out.println("未读邮件");
saveAttachment(message, file); //保存附件
message.setFlag(Flags.Flag.SEEN, true);
}
// 删除邮件
// message.setFlag(Flags.Flag.DELETED, true);
// 标记为已读
//pop3没有判断邮件是否为已读的功能,要使用Imap才可以
/*Flags flags = message.getFlags();
if (flags.contains(Flags.Flag.SEEN))
System.out.println("这是一封已读邮件");
else {
System.out.println("未读邮件");
message.setFlag(Flags.Flag.SEEN, true);
}*/
//获取所有的Header,头信息
// Enumeration headers = message.getAllHeaders();
// System.out.println("----------------------allHeaders-----------------------------");
/* while (headers.hasMoreElements()) {
Header header = (Header)headers.nextElement();
System.out.println(header.getName()+" ======= "+header.getValue());
}*/
/*
//解析邮件内容
Object content = message.getContent();
if (content instanceof MimeMultipart) {
MimeMultipart multipart = (MimeMultipart) content;
parseMultipart(multipart);
}
System.out
.println("========================================================");
System.out
.println("========================================================");*/
}
folder.close(true);
store.close();
}- 保存附件,需要解码
/**
* 保存附件
*/
public static void saveAttachment(Part part, String destDir) throws Exception {
if (part.isMimeType("multipart/*")) {
Multipart multipart = (Multipart) part.getContent(); //复杂体邮件
//复杂体邮件包含多个邮件体
int partCount = multipart.getCount();
for (int i = 0; i < partCount; i++) {
//获得复杂体邮件中其中一个邮件体
BodyPart bodyPart = multipart.getBodyPart(i);
//某一个邮件体也有可能是由多个邮件体组成的复杂体
String disp = bodyPart.getDisposition();
if (disp != null && (disp.equalsIgnoreCase(Part.ATTACHMENT) || disp.equalsIgnoreCase(Part.INLINE))) {
InputStream is = bodyPart.getInputStream();
saveFile(is, destDir, decodeText(bodyPart.getFileName()));
} else if (bodyPart.isMimeType("multipart/*")) {
saveAttachment(bodyPart, destDir);
} else {
String contentType = bodyPart.getContentType();
if (contentType.indexOf("name") != -1 || contentType.indexOf("application") != -1) {
saveFile(bodyPart.getInputStream(), destDir, decodeText(bodyPart.getFileName()));
}
}
}
} else if (part.isMimeType("message/rfc822")) {
saveAttachment((Part) part.getContent(), destDir);
}
}
/**
* 保存文件
*/
private static void saveFile(InputStream is, String destDir, String fileName) throws Exception {
BufferedInputStream bis = new BufferedInputStream(is);
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(new File(destDir + fileName)));
int len = -1;
while ((len = bis.read()) != -1) {
bos.write(len);
bos.flush();
}
bos.close();
bis.close();
}
/**
* 文本解码
* @param encodeText 解码MimeUtility.encodeText(String text)方法编码后的文本
*/
public static String decodeText(String encodeText) throws UnsupportedEncodingException {
if (encodeText == null || "".equals(encodeText)) {
return "";
} else {
return MimeUtility.decodeText(encodeText);
}
}实属无奈才使用这种方式,求一种更好的解决方法