使用JavaMail實現收取和回覆郵件

qq_39006919 發表於 2020-10-16

最近專案實現了一個使用javaMail來實現郵箱郵件的讀取和郵件回覆。本人查閱資料並彙總做個記錄。

需要提前瞭解郵件協議

  1. 收取郵箱郵件的協議主要有兩個,第一個是pop3,第二個是imap協議。兩者協議唯一區別就是pop3不能識別郵箱郵件是否為已讀需要自己去判斷,而imap就很輕鬆做到這一點。我在這裡選擇imap協議
  2. 傳送協議選擇smtp協議

常見郵箱型別的協議

我們專案不能確定客戶到底使用什麼型別的郵箱,所以自己單獨測試了各型別的郵箱做個彙總,省的再去翻閱資料查詢。注意:以下郵箱密碼如果是授權碼,需要單獨查詢各型別郵箱獲取授權碼的方式!如果是密碼則直接使用郵箱密碼即可!

QQ郵箱

	imap伺服器:imap.qq.com
	smtp伺服器:smtp.qq.com
	smtp埠:587
	使用者名稱:賬號名稱
	密碼:授權碼

企業郵箱

	imap伺服器:imap.exmail.qq.com
	smtp伺服器:smtp.exmail.qq.com
	smtp埠:25
	使用者名稱:賬號名稱
	密碼:密碼

新浪郵箱

imap伺服器:imap.sina.com
smtp伺服器:smtp.sina.com
smtp埠:25
使用者名稱:賬號名稱
密碼:授權碼

outlook郵箱

imap伺服器:outlook.office365.com
smtp伺服器:smtp-mail.outlook.com
smtp埠:587
使用者名稱:賬號名稱
密碼:密碼

注意:本人在測試163郵箱的時候,總是連結163郵箱伺服器出現問題(好像意思是許可權問題),網上試過各種辦法沒有解決,這裡記錄一下!

接下來不多BB,直接上程式碼(程式碼裡的帶前後~~ ~~格式的需要自己去填寫具體的協議、賬號、密碼 )

  1. 收取郵件
/**
 1. 讀取郵件
*/
public void readEmail() {
        Properties props = new Properties();
        props.put("mail.imap.host", "~~imapHost~~ ");
        props.put("mail.imap.auth", "true");
        props.setProperty("mail.store.protocol", "imap");
        props.put("mail.imap.starttls.enable", "true");
        Session session = Session.getInstance(props);
        try {
            Store store = session.getStore();
            store.connect("~~imapHost~~ ","~~userName~~ ", "~~passWord~~ ");
            Folder folder = store.getFolder("Inbox");
            //郵箱開啟方式
            folder.open(Folder.READ_WRITE);
            //收取未讀郵件
            Message[] messages = folder.getMessages(folder.getMessageCount() - folder.getUnreadMessageCount() + 1, folder.getMessageCount());
            //解析郵件
            if (messages.length != 0) {
                parseMessage(messages);
            }
            //設定郵件為已讀
            folder.setFlags(messages, new Flags(Flags.Flag.SEEN), true);
            folder.close(true);
            store.close();
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }
    
	/**
     * 解析郵件
     */
    public void parseMessage(Message[] messages) {
        for (Message message : messages) {
            try {
                //獲取未讀郵件
                if (!message.getFlags().contains(Flags.Flag.SEEN)) {
                    MimeMessage mimeMsg = (MimeMessage) message;
                    //判斷郵件是否包含附件
                    boolean containAttachment = this.containAttachment(mimeMsg);
                    // 解析郵件發件人
                    EmailInfo emailInfo = this.processEmailInfo(mimeMsg);
                    log.debug("-----> 發件人資訊:{}, 包含附件:{}", emailInfo, containAttachment);
                    if (containAttachment) {
                        // 郵箱附件解析
                        List<BodyPart> mimeFileList = this.getMimeFile(mimeMsg);
                        // 附件操作(具體情況具體操作)
                        saveEmailAttach(mimeFileList);
                    }
                }
            } catch (MessagingException e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 郵件是否包含附件
     */
     public static boolean containAttachment(MimeMessage mimeMsg) {
        try {
            if (mimeMsg.isMimeType(MULTIPART_MIME_TYPE)) {
                Multipart mp = (Multipart) mimeMsg.getContent();
                for (int i = 0; i < mp.getCount(); i++) {
                    BodyPart bp = mp.getBodyPart(i);
                    // 如果該BodyPart物件包含附件
                    if (bp.getDisposition() != null) {
                        return true;
                    }
                }
            }
        } catch (MessagingException | IOException e) {
            log.error("-----> {}", LogUtil.stackTraceInfo(e));
        }
        return false;
    }
    
    /**
     * 解析郵件發件資訊
     */
    public static EmailInfo processEmailInfo(MimeMessage mimeMsg) {
        EmailInfo emailInfo = new EmailInfo();
        try {
            String from = ((InternetAddress) (mimeMsg.getFrom()[0])).getAddress();
            String subject = mimeMsg.getSubject();
            Date sentDate = mimeMsg.getSentDate();
            emailInfo.setFrom(from)
                    .setSubject(subject)
                    .setSendDate(sentDate)
                    .setSendDateStr(DateUtil.format(sentDate, DatePattern.NORM_DATETIME_PATTERN));
        } catch (MessagingException e) {
            log.error("-----> {}", LogUtil.stackTraceInfo(e));
        }
        return emailInfo;
    }
    
    /**
     * 解析郵件附件
     *
     * @param part 郵件中多個組合體中的其中一個組合體
     */
    public static List<BodyPart> getMimeFile(Part part) {

        List<BodyPart> files = new ArrayList<>();
        try {
            if (part.isMimeType(MULTIPART_MIME_TYPE)) {
                //複雜體郵件
                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))) {
                        files.add(bodyPart);
                    } else if (bodyPart.isMimeType(MULTIPART_MIME_TYPE)) {
                        getFile(bodyPart);
                    } else {
                        String contentType = bodyPart.getContentType();
                        if (contentType.contains("name") || contentType.contains("application")) {
                            files.add(bodyPart);
                        }
                    }
                }
            } else if (part.isMimeType(RFC822_MIME_TYPE)) {
                getMimeFile((BodyPart) part.getContent());
            }
        } catch (IOException | MessagingException e) {
            log.error("-----> {}", LogUtil.stackTraceInfo(e));
        }
        return files;
    }
    /**
     * 儲存附件
     */
     public void saveEmailAttach(List<BodyPart> bodyPartList) {
        ArrayList<Attach> attachList = new ArrayList<>();
        try {
            for (BodyPart file : bodyPartList) {
                String fileNameSuffix = file.getFileName();
                fileNameSuffix = MimeUtility.decodeText(fileNameSuffix);
                String suffix = fileNameSuffix.substring(fileNameSuffix.lastIndexOf(".") + 1);
                suffix = MimeUtility.decodeText(suffix);
                //判斷附件型別是否為PDF(看具體情況具體處理)
                if (!suffix.equalsIgnoreCase("PDF")) {
                    continue;
                }
                //獲取輸入流
                InputStream inputStream = file.getInputStream();
                //TODO
            }
        } catch (MessagingException | IOException e) {
            throw new CommonException(e);
        }
    }

    /**
     * 發件人資訊
     */
    public class EmailInfo {
    /** 發件人 */
    private String from;
    /** 主題 */
    private String subject;
    /** 發件時間 */
    private Date sendDate;
    /** 發件時間字串 */
    private String sendDateStr;
    }
  

 2. 回覆郵件
 

/**
 * 傳送郵件
 *
 * @param sendAddr 傳送地址
 * @param message  傳送資訊
 * @param subject  傳送主題
 */
public void sendMsg(String sendAddr, String message, String subject) {
    log.debug("-----> sendMsg:{}", sendAddr);
    try {
            Properties props = new Properties();
            // 開啟debug除錯
            props.setProperty("mail.debug", "false");
            // 傳送伺服器需要身份驗證
            props.setProperty("mail.smtp.auth", "true");
            // 設定郵件伺服器主機名
            props.setProperty("mail.host", "~~smtpHost~~ ");
            // 傳送郵件協議名稱
            props.setProperty("mail.transport.protocol", "smtp");
            props.setProperty("mail.smtp.port", "~~smtpPort~~ ");
            props.put("mail.smtp.starttls.enable", "true");
            // 設定環境資訊
            Session session = Session.getInstance(props);
            // 建立郵件物件
            MimeMessage msg = new MimeMessage(session);
            // 設定發件人
            msg.setFrom(new InternetAddress("~~使用者名稱~~ "));
            // 設定收件人
            msg.addRecipient(Message.RecipientType.TO, new InternetAddress(sendAddr));
            // 設定郵件主題
            msg.setSubject(subject);
            //新建一個存放信件內容的BodyPart物件
            BodyPart mdp = new MimeBodyPart();
            //給BodyPart物件設定內容和格式/編碼方式
            mdp.setContent(message, "text/html;charset=UTF-8");
            //新建一個MimeMultipart物件用來存放BodyPart物件(事實上可以存放多個)
            Multipart mm = new MimeMultipart();
            //將BodyPart加入到MimeMultipart物件中(可以加入多個BodyPart)
            mm.addBodyPart(mdp);
            //把mm作為訊息物件的內容
            msg.setContent(mm);
            Transport transport = session.getTransport();
            // 連線郵件伺服器
            transport.connect("~~使用者名稱~~ ", "~~密碼~~ ");
            // 傳送郵件
            transport.sendMessage(msg, new Address[]{new InternetAddress(sendAddr)});
            // 關閉連線
            transport.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
**全部程式碼都在這裡,我在裡面刪除了自己好多專案具體自己處理的邏輯,有不對的地方可以指出,我再進行修改。**