搜索网上各个案例,总结的一套比较全面且行之有效的方法。供大家参考使用!
使用javax.mail自动读取邮件,并下载解析附件,IMAP/POP3协议等!
直接上代码如下:
package ***
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.mail.Address;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;
import javax.mail.search.AndTerm;
import javax.mail.search.ComparisonTerm;
import javax.mail.search.FromStringTerm;
import javax.mail.search.SearchTerm;
import javax.mail.search.SentDateTerm;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
*/
@Component
public class BlacklistCodeTask {
private static Logger logger = LoggerFactory.getLogger(BlacklistCodeTask.class);
@Autowired
private blacklistService blacklistService;
// 邮箱附件保存路径
private static String FILE_SAVE_PATH = ConfigProperties.getProperties("blacklist.emailFilePath");
// 读取的发件人
private static String fromEmail = ConfigProperties.getProperties("blacklist.fromEmail");
// 收件服务器
private static String hostServer = ConfigProperties.getProperties("blacklist.hostServer");
private static String protocol = ConfigProperties.getProperties("blacklist.protocol");
private static String port = ConfigProperties.getProperties("blacklist.port");
private static String username = ConfigProperties.getProperties("blacklist.username");
private static String password = ConfigProperties.getProperties("blacklist.password");
// 执行日期标识
String dateTimeFlag;
// 附件名称关键词
private static String FILE_NAME_FLAG1 = "加黑***明细";
private static String FILE_NAME_FLAG2 = "加黑";
// Runtime.getRuntime().availableProcessors()
public static ExecutorService threadPool = Executors.newFixedThreadPool(1);
/**
* 定时任务获取前一天邮件,并解析保存黑端口号码
*/
public void acquireXinAnEmails() {
try {
// 1. 设置连接信息, 生成一个 Session
// 获取连接
Session session;
if ("pop3".equalsIgnoreCase(protocol)) {
session = Session.getInstance(getPOP3());
// session = Session.getDefaultInstance(getPOP3());
} else {
// session = Session.getDefaultInstance(getIMAP());
session = Session.getInstance(getIMAP());
}
session.setDebug(false);
// 2. 获取Store, 并连接到服务器
Store store = session.getStore(protocol);
store.connect(hostServer, username, password); // POP3服务器的登陆认证
//
Folder defaultFolder = store.getDefaultFolder();// 默认父目录
if (defaultFolder == null) {
logger.error("服务器不可用! hostServer:{}", hostServer);
return;
}
//
Folder folder = defaultFolder.getFolder("INBOX");// 获取收件箱
folder.open(Folder.READ_WRITE);// 可读邮件,可以删邮件的模式打开目录
// 取出来邮件数
logger.info("folder urlName: {}, 共有邮件: {}封, UnreadMessages: {}, NewMessages: {}...", folder.getURLName().toString(),
folder.getMessageCount(), folder.getUnreadMessageCount(), folder.getNewMessageCount());
//
dateTimeFlag = DateTimeUtil.formatDateTime(new Date(), DateTimeUtil.DATA_FORMAT_yyyyMMdd);
searchMails(folder);
// 7. 关闭 Folder 会真正删除邮件, false 不删除
folder.close(false);
// 8. 关闭 store, 断开网络连接
store.close();
} catch (NoSuchProviderException e) {
logger.error(e.getMessage(), e);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
// // 统一处理下载好的的Excel文件
// dealAndGetBlacklist();
}
/**
* 获取POP3收信配置 995
*
* @return
*/
private Properties getPOP3() {
Properties props = new Properties();
props.setProperty("mail.transport.protocol", protocol);
props.setProperty("mail.pop3.host", hostServer); // 按需要更改
props.setProperty("mail.pop3.port", port);
// SSL安全连接参数
props.setProperty("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.setProperty("mail.pop3.socketFactory.fallback", "false");
props.setProperty("mail.pop3.socketFactory.port", port);
// 解决DecodingException: BASE64Decoder: but only got 0 before padding character (=)
props.setProperty("mail.mime.base64.ignoreerrors", "true");
return props;
}
/**
* 获取IMAP收信配置 993
*
* @return
*/
private Properties getIMAP() {
Properties props = new Properties();
props.setProperty("mail.transport.protocol", protocol);
props.setProperty("mail.imap.host", hostServer); // 按需要更改
props.setProperty("mail.imap.port", port);
// SSL安全连接参数
props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.setProperty("mail.imap.socketFactory.fallback", "false");
props.setProperty("mail.imap.socketFactory.port", port);
props.setProperty("mail.mime.base64.ignoreerrors", "true");
return props;
}
/**
* 创建搜索条件,并获取邮件...第二天凌晨10分之后执行,查询前一天零点到今天零点的数据
*
* @param folder
* @throws Exception
*/
private void searchMails(Folder folder) throws Exception {
//建立搜索条件继承自SearchTerm,像根据发件人,主题搜索,邮件标记FlagTerm等,
// FlagTerm ft = new FlagTerm(new Flags(Flags.Flag.SEEN), false); //false代表未读,true代表已读
// 搜索昨天收到的的所有邮件
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, -1);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
Date start = calendar.getTime();
calendar.setTime(new Date());
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
Date end = calendar.getTime();
SearchTerm comparisonTermGe = new SentDateTerm(ComparisonTerm.GE, start);
SearchTerm comparisonTermLe = new SentDateTerm(ComparisonTerm.LE, end);
FromStringTerm fromStringTerm = new FromStringTerm(fromEmail);
SearchTerm andTerm = new AndTerm(new SearchTerm[]{comparisonTermGe, comparisonTermLe, fromStringTerm});
logger.info("SearchTerm start: {}, end: {}, fromEmail: {}", DateTimeUtil.formatDateTime(start, DateTimeUtil.DATA_FORMAT_yyyy_MM_dd_HH_mm_ss),
DateTimeUtil.formatDateTime(end, DateTimeUtil.DATA_FORMAT_yyyy_MM_dd_HH_mm_ss), fromEmail);
//
Message[] messages = folder.search(andTerm); //根据设置好的条件获取message
logger.info("search邮件: " + messages.length + "封, SearchTerm:" + andTerm.getClass());
// FetchProfile fProfile = new FetchProfile(); // 选择邮件的下载模式,
// fProfile.add(FetchProfile.Item.ENVELOPE); // 根据网速选择不同的模式
// folder.fetch(messages, fProfile);// 选择性的下载邮件
// 5. 循环处理每个邮件并实现邮件转为新闻的功能
for (int i = 0; i < messages.length; i++) {
// 单个邮件
logger.info("---第" + i + "邮件开始------------");
mailReceiver(messages[i]);
logger.info("---第" + i + "邮件结束------------");
// 邮件读取备份保存,用来校验
// messages[i].writeTo(new FileOutputStream(FILE_SAVE_PATH + "pop3Mail_" + messages[i].getMessageNumber() + ".eml"));
}
}
/**
* 解析邮件
*
* @param msg 邮件对象
* @throws Exception
*/
private void mailReceiver(Message msg) {
try {
// 发件人信息
Address[] froms = msg.getFrom();
String mailSubject = transferChinese(msg.getSubject());
if (froms != null) {
InternetAddress addr = (InternetAddress) froms[0];
logger.info("发件人地址:" + addr.getAddress() + ", 发件人显示名:" + transferChinese(addr.getPersonal()));
} else {
logger.error("msg.getFrom() is null... subject:" + mailSubject);
}
Date sentDate = msg.getSentDate();
logger.info("邮件主题: {}, sentDate: {}", mailSubject,
sentDate == null ? null : DateTimeUtil.formatDateTime(sentDate, DateTimeUtil.DATA_FORMAT_yyyy_MM_dd_HH_mm_ss));
// getContent() 是获取包裹内容, Part相当于外包装
Object content = msg.getContent();
if (content instanceof Multipart) {
Multipart multipart = (Multipart) content;
reMultipart(multipart);
} else if (content instanceof Part) {
Part part = (Part) content;
rePart(part);
} else {
String contentType = msg.getContentType();
if (contentType != null && contentType.startsWith("text/html")) {
logger.warn("---类型:" + contentType);
} else {
logger.warn("---类型:" + contentType);
logger.warn("---内容:" + msg.getContent());
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
/**
* 把邮件主题转换为中文.
*
* @param strText the str text
* @return the string
*/
public String transferChinese(String strText) {
try {
if (StringUtils.isBlank(strText)) {
return null;
}
strText = MimeUtility.encodeText(new String(strText.getBytes(),
"UTF-8"), "UTF-8", "B");
strText = MimeUtility.decodeText(strText);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return strText;
}
/**
* @param part 解析内容
* @throws Exception
*/
private void rePart(Part part) {
String tempFilePath = null;
try {
// 附件
if (part.getDisposition() != null) {
// 邮件附件
String strFileName = MimeUtility.decodeText(part.getFileName()); //MimeUtility.decodeText解决附件名乱码问题
logger.info("发现附件: {}, 内容类型: {} ", strFileName, MimeUtility.decodeText(part.getContentType()));
// 读取附件字节并存储到文件中. xls/xlsx
String fileType = strFileName.substring(strFileName.lastIndexOf(".") + 1);
if ((fileType.equals("xlsx") || fileType.equals("xls")) &&
(strFileName.contains(FILE_NAME_FLAG1) || strFileName.contains(FILE_NAME_FLAG2))) {
InputStream in = part.getInputStream();// 打开附件的输入流
tempFilePath = FILE_SAVE_PATH + dateTimeFlag + strFileName;
FileOutputStream out = new FileOutputStream(tempFilePath);
int data;
while ((data = in.read()) != -1) {
out.write(data);
}
in.close();
out.close();
} else {
logger.info("not what we need file, discard it: {}", strFileName);
}
} else {
// 邮件内容
if (part.getContentType().startsWith("text/plain") || part.getContentType().startsWith("Text/Plain")) {
logger.info("Content文本内容:" + part.getContent());
} else if (part.getContentType().startsWith("text/html")) {
// logger.info("HTML内容:" + part.getContent());
logger.debug("HTML内容,,不记录日志展示。。");
} else {
logger.debug("!其它ContentType:" + part.getContentType() + " ?内容:" + part.getContent());
}
}
} catch (MessagingException e) {
logger.error(e.getMessage(), e);
} catch (IOException e) {
logger.error(e.getMessage(), e);
} finally {
// 单个处理黑名单文件,放入线程池处理
String finalTempFilePath = tempFilePath;
threadPool.execute(() -> {
dealBlacklist(finalTempFilePath);
}
);
}
}
/**
* @param multipart // 接卸包裹(含所有邮件内容(包裹+正文+附件))
* @throws Exception
*/
private void reMultipart(Multipart multipart) throws Exception {
logger.debug("Multipart邮件共有" + multipart.getCount() + "部分组成");
// 依次处理各个部分
for (int j = 0, n = multipart.getCount(); j < n; j++) {
Part part = multipart.getBodyPart(j);
// 解包, 取出 MultiPart的各个部分, 每部分可能是邮件内容, 也可能是另一个小包裹(MultipPart)
if (part.getContent() instanceof Multipart) {
logger.debug("部分" + j + "的ContentType: " + part.getContentType() + ", to reMultipart() ");
Multipart p = (Multipart) part.getContent();// 转成小包裹
//递归迭代
reMultipart(p);
} else {
logger.debug("部分" + j + "的ContentType: " + part.getContentType() + ", to rePart() ");
rePart(part);
}
}
}
/**
* 单个处理下载好的文件
*
* @param tempFilePath
*/
private void dealBlacklist(String tempFilePath) {
if (StringUtil.isBlank(tempFilePath)) {
return;
}
logger.info("to deal with blacklist Excel file: {}", tempFilePath);
blacklistService.dealBlacklist(tempFilePath);
}
}