package com.jack.platformweb.email.service; import com.sun.mail.imap.IMAPStore; import com.jack.common.redis.service.RedisService; import com.jack.common.utils.DateUtils; import com.jack.common.utils.JsonUtils; import com.jack.common.utils.ZipUtils; import com.jack.db.urgerobot.robot.model.RobotInfo; import com.jack.platformweb.partner.service.GzOutUrgeFileService; import com.jack.platformweb.robot.service.RobotInfoService; import net.lingala.zip4j.exception.ZipException; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.mail.*; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeUtility; import javax.print.DocFlavor; import java.io.*; import java.util.*; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @Description * @Author zhenghao * @Date 2021/8/17 22:07 **/ @Service public class RemoteEmailService { private static Logger log = LoggerFactory.getLogger(RemoteEmailService.class); @Value("${gz.local.path}") private String attachFilePath; @Autowired private GzOutUrgeFileService gzOutUrgeFileService; @Autowired private RobotInfoService robotInfoService; @Autowired private RedisService redisService; //从哪个邮箱地址获取内容 private static String username = "test@qq.com"; private static String password = "123456"; private static Integer robotId = 161; //过滤发件人 private static List<String> monitoringEmail = Stream.of("tt@qq.com").collect(Collectors.toList()); private IMAPStore getConnect() { log.info("开始获得邮件链接"); // 准备连接服务器的会话信息 IMAPStore store = null; try { Properties props = new Properties(); // props.setProperty("mail.store.protocol", "imap"); // props.setProperty("mail.imap.host", "imap.exmail.qq.com"); // props.setProperty("mail.imap.port", "993"); // props.setProperty("mail.imap.ssl.enable", "true"); // // props.setProperty("mail.imap.auth.plain.disable", "true"); // // Session session = Session.getInstance(props, new javax.mail.Authenticator() { // @Override // // protected PasswordAuthentication getPasswordAuthentication() { // return new PasswordAuthentication(username, password // // ); // // } // // }); props.put("mail.imap.host", "imap.exmail.qq.com");//QQ邮箱为:imap.qq.com props.put("mail.imap.auth", "true"); props.setProperty("mail.store.protocol", "imap"); props.put("mail.imap.starttls.enable", "true"); Session session = Session.getInstance(props); // // 创建Session实例对象 // Session session = Session.getInstance(props); // 创建IMAP协议的Store对象 store = (IMAPStore) session.getStore("imap"); // 连接邮件服务器 store.connect("imap.exmail.qq.com", username, password); } catch (Exception e) { log.info("成功获得邮件链接失败"); e.printStackTrace(); } log.info("成功获得邮件链接"); return store; } public boolean receiveEmail() { log.info("开始执行远程获得邮件任务"); try { String key = "remoteEmailkey" + DateUtils.getToDayStartYYMMMDD(); String s = redisService.get(key); if (StringUtils.isNotEmpty(s)) { log.info("远程获得邮件已经成功执行"); return false; } /** * 1. 取得链接 */ IMAPStore imapStore = getConnect(); if (null == imapStore) { log.error("获取邮箱imap连接失败。方法执行失败。退出当前方法!!!!!!!"); return false; } Folder defaultFolder = imapStore.getDefaultFolder(); if (defaultFolder == null) { log.info("服务器不可用"); return false; } Folder folder = imapStore.getFolder("INBOX"); folder.open(Folder.READ_WRITE); //获得所有近30天的邮件,近30天是在客户端配置的 Message[] messages = folder.getMessages(); // Message[] messages = folder.getMessages(folder.getMessageCount() - folder.getUnreadMessageCount() + 1, folder.getMessageCount()); log.info("未读邮件数量: {}", messages.length); for (Message msg : messages) { try { //邮件发送日期超过两天 退出遍历方法 if (!outDays(msg)) { log.info("邮件{}已过期,退出循环", msg.getSubject()); continue; } //不是最新邮件,跳过 // if (isNew(msg)) { // log.info("邮件不是新邮件,跳过"); // continue; // } //是否属于需要处理的邮件 if (needProcessEmail(msg)) { redisService.setex(key, 20 * 60 * 60, "1"); break; } else { log.info("邮件不需要处理,跳过"); } } catch (Exception e) { log.error(e.getMessage(), e); } } //关闭资源 folder.close(true); imapStore.close(); } catch (MessagingException e) { e.printStackTrace(); } return false; } /** * @param * @param msg * @return boolean * @author FeianLing * @date 2019/8/20 * @desc 检查当前邮件是否已超过1天, 接收时间大于1天以前 返回true */ private boolean outDays(Message msg) { String s = ""; Date receiveDate = null; try { receiveDate = msg.getReceivedDate(); s = DateUtils.formatYYYYMMDD(receiveDate); log.info("邮件接收时间:{}", DateUtils.formatYYYYMMDD(receiveDate)); return DateUtils.getToDayYYYYMMDD().equals(s); } catch (MessagingException e) { e.printStackTrace(); } return true; } /** * @param * @param msg * @return boolean * @author FeianLing * @date 2019/8/20 * @desc 判断邮件是否是新的邮件 */ private boolean isNew(Message msg) throws MessagingException { boolean isNewFlag = false; Flags flags = msg.getFlags(); Flags.Flag[] flagsArr = flags.getSystemFlags(); log.info("邮件状态:" + JsonUtils.writeValue(flagsArr)); for (Flags.Flag flag : flagsArr) { if (flag == Flags.Flag.SEEN) { isNewFlag = true; log.info("当前邮件为未读状态!"); break; } } return isNewFlag; } /** * @param * @param msg * @return boolean * @author FeianLing * @date 2019/8/20 * @desc 检查邮件内容是否需要我们处理 * 1. 检查发件人是否满足要求 * 2. 检查是否包含附件 * 3. 检查是否有满足条件的附件 */ private boolean needProcessEmail(Message msg) throws Exception { log.info("needProcessEmail > 当前邮件的标题:{}", msg.getSubject()); // 1. 检查发件人邮箱是否包含在我们监控的邮箱列表里面 String from = getFrom(msg); if (!monitoringEmail.contains(from)) { log.info("当前邮件的发件人[{}]不是我们要监控的对象", from); return false; } if (!isContainAttach((Part) msg)) { log.info("发件人满足要求但是附件为空,不满足我们监控的需求!"); return false; } Map<String, InputStream> fileMap = new HashMap<>(); getFileInputStream(msg, fileMap); if (fileMap.isEmpty()) { log.info("尽管邮件中有附件但是邮件中的附件却无一个满足要求!"); return false; } else { //写入本地文件 for (String s : fileMap.keySet()) { InputStream inputStream = fileMap.get(s); this.getFile(inputStream, attachFilePath + "/" + s); this.dealFileData(attachFilePath + "/" + s); break; } } return true; } /** * @param * @param part * @return java.io.InputStream * @author FeianLing * @date 2019/8/20 * @desc 获取文件输入流 */ private void getFileInputStream(Part part, Map<String, InputStream> inputStreamMap) throws Exception { String fileName; if (part.isMimeType("multipart/*")) { Multipart mp = (Multipart) part.getContent(); for (int i = 0; i < mp.getCount(); i++) { BodyPart mPart = mp.getBodyPart(i); String disposition = mPart.getDisposition(); if ((disposition != null) && ((disposition.equals(Part.ATTACHMENT)) || (disposition .equals(Part.INLINE)))) { fileName = mPart.getFileName(); fileName = MimeUtility.decodeText(fileName); if (checkFileName(fileName)) { inputStreamMap.put(fileName, mPart.getInputStream()); } } else if (mPart.isMimeType("multipart/*")) { log.info("子邮件里面的附件"); getFileInputStream(mPart, inputStreamMap); } else { fileName = mPart.getFileName(); if ((fileName != null) && (fileName.toLowerCase().indexOf("GB2312") != -1)) { fileName = MimeUtility.decodeText(fileName); if (checkFileName(fileName)) { inputStreamMap.put(fileName, mPart.getInputStream()); } } } } } else if (part.isMimeType("message/rfc822")) { getFileInputStream((Part) part.getContent(), inputStreamMap); } } /** * @param * @param fileName * @return boolean * @author FeianLing * @date 2019/8/20 * @desc 检查文件名称是否符合要求 AI智能语音催收名单——智清厂商-0803.xls */ private boolean checkFileName(String fileName) { return (fileName.contains("AI外呼剔除名单") || fileName.contains("AI外呼提出名单")); } /** * @param * @param part * @return boolean * @author FeianLing * @date 2019/8/20 * @desc 判断邮件是否包含附件,如果没有包含附件,返回false 反之返回true */ private boolean isContainAttach(Part part) throws Exception { boolean attachFlag = false; // String contentType = part.getContentType(); if (part.isMimeType("multipart/*")) { Multipart mp = (Multipart) part.getContent(); for (int i = 0; i < mp.getCount(); i++) { BodyPart mPart = mp.getBodyPart(i); String disposition = mPart.getDisposition(); if ((disposition != null) && ((disposition.equals(Part.ATTACHMENT)) || (disposition .equals(Part.INLINE)))) { attachFlag = true; } else if (mPart.isMimeType("multipart/*")) { attachFlag = isContainAttach((Part) mPart); } else { String conType = mPart.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; } /** * @param * @param msg * @return java.lang.String * @author FeianLing * @date 2019/8/20 * @desc 获取发送地址 */ private String getFrom(Message msg) throws MessagingException { String from = ""; InternetAddress[] addresses = (InternetAddress[]) msg.getFrom(); if (null == addresses || addresses.length == 0) { log.error("无法获取发送人地址信息!"); return from; } Address address = addresses[0]; log.info("发件人地址json:" + JsonUtils.writeValue(address)); String form = ((InternetAddress) address).getAddress(); return form; } public void getFile(InputStream is, String fileName) { try { BufferedInputStream in = null; BufferedOutputStream out = null; in = new BufferedInputStream(is); out = new BufferedOutputStream(new FileOutputStream(fileName)); int len = -1; byte[] b = new byte[1024]; while ((len = in.read(b)) != -1) { out.write(b, 0, len); } in.close(); out.close(); } catch (IOException e) { e.printStackTrace(); } } //业务处理方法 public void dealFileData(String filePath) { try { log.info("开始处理文件:" + filePath); File file = new File(filePath); String name = file.getName(); String fileName = name.replace(".zip", ".xls"); ZipUtils.unZip(file, attachFilePath, "111111"); RobotInfo robotInfoById = robotInfoService.getRobotInfoById(robotId); String tempFilePath = attachFilePath + "/" + fileName; log.info("处理文件路径:" + tempFilePath); gzOutUrgeFileService.autoOutUrge(robotInfoById, tempFilePath); log.info("出催文件处理完毕"); } catch (ZipException e) { e.printStackTrace(); } } public static void main(String[] args) { } }