javaMail使用javax.mail自動讀取郵件,並下載解析附件,IMAP/POP3協議等

搜索網上各個案例,總結的一套比較全面且行之有效的方法。供大家參考使用!

使用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);

    }


}

 

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