使用JavaMail實現監控郵箱重要郵件並獲取附件保存

使用JavaMail實現監控郵箱重要文件並將附件保存

需求描述

系統需要監控阿里雲企業郵箱的收件信息,發現Dev發送過來的郵件,且附件名稱滿足一定格式要求的,我們需要將附件保存下來,並自動上傳管理系統。已到達郵件及時有效處理且降低人力成本的目的。

技術儲備

在實現這個功能之前我們需要了解一下與郵件有關的協議,smtp、pop3和imap協議,(關於smtp,pop3以及imap協議可以點擊鏈接瞭解)在這裏我們選擇的是imap協議。因爲我們需要更新郵件的狀態,如果我們系統處理過郵件,那麼我們要將它設計爲已讀狀態。防止重複處理。

實現代碼

獲取郵箱IMAPStore的鏈接

 private IMAPStore getConnect() {
        //代理配置
        Properties props = System.getProperties();
        if (enableProxy) {
            props.setProperty("proxySet", "true");
            //使用測試環境專有的郵件代理IP
            props.setProperty("ProxyHost", proxyIpEmail);
            //使用測試環境專有的郵件代理端口
            props.setProperty("ProxyPort", proxyPortEmail);
        }
        IMAPStore store = null;
        props.setProperty("mail.store.protocol", protocol);
        props.setProperty("mail.imap.host", imapHost);
        props.setProperty("mail.imap.port", imapPort);
        props.setProperty("mail.imap.auth.login.disable", "true");
        authentication = new PasswordAuthentication(username, password);
        int tryTimes = 0;
        do {
            try {
                session = Session.getInstance(props, this);
                // 2、通過session得到Store對象
                store = (IMAPStore) session.getStore("imap");
                // 3、連上郵件服務器
                store.connect(username, password);
            } catch (Exception e) {
                Logs.error("第{}次嘗試連接失敗:{}", tryTimes, e.getMessage());
            }
            tryTimes++;
            //嘗試10就可以了
            if (tryTimes >= EmailServiceImpl.TRY_TIMES) {
                break;
            }
            try {
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                //ignore this exception
            }
        } while (true);
        return store;
    }

參數配置參考

mail.store.protocol=imap
mail.imap.host=imap.mxhichina.com
mail.imap.port=143
email.username=********
email.password=******
  1. 獲取收件夾中的未讀郵件
  @Override
    public boolean receiveEmail() throws Exception {
        /**
         * 1. 取得鏈接
         */
        IMAPStore imapStore = getConnect();
        if (null == imapStore) {
            Logs.error("獲取郵箱imap連接失敗。方法執行失敗。退出當前方法!!!!!!!");
            return false;
        }
        Folder folder = imapStore.getFolder("INBOX");
        folder.open(Folder.READ_WRITE);
        Message[] messages = folder.getMessages(folder.getMessageCount() - folder.getUnreadMessageCount() + 1, folder.getMessageCount());
        Logs.info("未讀郵件數量: {}", messages.length);
        for (Message msg : messages) {
            try {
                //郵件發送日期超過兩天 退出遍歷方法
                if (outDays(msg)) {
                    Logs.info("郵件{}已過期,退出循環", msg.getSubject());
                    continue;
                }
                //不是最新郵件,跳過
                if (isNew(msg)) {
                    Logs.info("郵件不是新郵件,跳過");
                    continue;
                }
                //是否屬於需要處理的郵件
                if (!needProcessEmail(msg)) {
                    Logs.info("郵件不需要處理,跳過");
                    continue;
                }
                /**
                 * 處理郵件信息
                 */
                processEmailData(msg);
            } catch (Exception e) {
                Logs.error(e.getMessage(), e);
            }
        }
        //關閉資源
        folder.close(true);
        imapStore.close();
        return false;
    }

 /**
     * @param
     * @param msg
     * @return boolean
     * @author FeianLing
     * @date 2019/8/20
     * @desc 檢查當前郵件是否已超過1天, 接收時間大於1天以前 返回true
     */
    private boolean outDays(Message msg) throws MessagingException {
        Date date = DateUtils.offsetDate(new Date(), emailOutDays);
        Date receiveDate = msg.getReceivedDate();
        Logs.info("郵件接收時間:{}", DateUtils.formatYmdHms(receiveDate));
        return receiveDate.getTime() - date.getTime() < 0;
    }
 /**
     * @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();
        Logs.info("郵件狀態:" + JSONObject.toJSONString(flagsArr));
        for (Flags.Flag flag : flagsArr) {
            if (flag == Flags.Flag.SEEN) {
                isNewFlag = true;
                Logs.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 {
        Logs.info("needProcessEmail  > 當前郵件的標題:{}", msg.getSubject());
        // 1. 檢查發件人郵箱是否包含在我們監控的郵箱列表裏面
        String from = getFrom(msg);
        if (!monitoringEmail.contains(from)) {
            Logs.info("當前郵件的發件人[{}]不是我們要監控的對象", from);
            return false;
        }
        if (!isContainAttach((Part) msg)) {
            Logs.info("發件人滿足要求但是附件爲空,不滿足我們監控的需求!");
            return false;
        }
        Map<String, InputStream> fileMap = new HashMap<>();
        getFileInputStream(msg, fileMap);
        if (fileMap.isEmpty()) {
            Logs.info("儘管郵件中有附件但是郵件中的附件卻無一個滿足要求!");
            return false;
        }
        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();
                    if (fileName.toLowerCase().indexOf("gb2312") != -1) {
                        fileName = MimeUtility.decodeText(fileName);
                    }
                    if (checkFileName(fileName)) {
                        inputStreamMap.put(fileName, mPart.getInputStream());
                    }
                } else if (mPart.isMimeType("multipart/*")) {
                    Logs.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 檢查文件名稱是否符合要求 FTK-88584316 FTK-申請號.pdf
     */
    private boolean checkFileName(String fileName) {
        return EmailServiceImpl.FILENAME_REGEX.matcher(fileName).find();
    }

    /**
     * @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) {
            Logs.error("無法獲取發送人地址信息!");
            return from;
        }
        Address address = addresses[0];
        Logs.info("發件人地址json:" + JSONObject.toJSONString(address));
        String form = ((InternetAddress) address).getAddress();
        return form;
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章