Java 基於javaMail的郵件發送(支持附件)


 

 

基於JavaMail的Java郵件發送
Author xiuhong.chen@hand-china.com

Desc 簡單郵件發送

Date 2017/12/8

項目中需要根據物料資質的狀況實時給用戶發送郵件,然后我就簡單學習了SMTP.

電子郵件的在網絡中傳輸和網頁一樣需要遵從特定的協議,常用的電子郵件協議包括 SMTP,POP3,IMAP。其中郵件的創建和發送只需要用到 SMTP協議,所以本文也只會涉及到SMTP協議。SMTP 是 Simple Mail Transfer Protocol 的簡稱,即簡單郵件傳輸協議。

1.導入jar包javax.mail.jar
JavaMail 下載地址: https://github.com/javaee/javamail/releases

特別注意:

本測試用例用的 JavaMail 版本是 1.6.0,如果下載到其他版本的 JavaMail 運行時出現問題,請使用 JavaMail 1.6.0 版本再進行嘗試。
使用 JavaMail 1.6.0 要求的 JDK 版本必須是 JDK 1.7 以上(建議使用最新版 JDK)。
不要直接就完完全全復制我的代碼,需要 修改一下發送的標題、內容、用戶昵稱,要不然所有人都直接復制我的代碼發送,內容一致,郵箱服務器就可能會檢測到這些內容是垃圾廣告內容,不讓你發送,會返回錯誤碼,查詢錯誤碼也能查詢到失敗原因。
2.創建一封簡單的電子郵件
首先創建一個 Java 工程,把下載好的 javax.mail.jar 作為類庫加入工程

郵件創建步驟:

配置連接郵件服務器的參數( 郵件服務器SMTP, 是否需要SMTP驗證 )
創建一個郵件對象( MimeMessage )
設置發件人,收件人 ( 可增加多個收件人,抄送人,密送人 )
設置郵件標題, 正文 , 附件等
設置顯示的發送時間

public void sendMail() throws Exception{
        System.out.println("sendMailServlet-----start");

        //1.創建郵件對象
        Properties properties = new Properties();
        properties.put("mail.smtp.host", "mail.hand-china.com"); // 指定SMTP服務器
        properties.put("mail.smtp.auth", "true"); // 指定是否需要SMTP驗證
        Session session = Session.getInstance(properties);
        MimeMessage mimeMessage =new MimeMessage(session);

        /*2.設置發件人
        * 其中 InternetAddress 的三個參數分別為: 郵箱, 顯示的昵稱(只用於顯示, 沒有特別的要求), 昵稱的字符集編碼
        * */
        mimeMessage.setFrom(new InternetAddress("xiuhong.chen@hand-china.com","xiuhong","UTF-8"));
        /*3.設置收件人
        To收件人   CC 抄送  BCC密送*/
        mimeMessage.setRecipient(MimeMessage.RecipientType.TO,new InternetAddress("17862***@qq.com","xiuhong","UTF-8"));
        mimeMessage.addRecipient(MimeMessage.RecipientType.TO,new InternetAddress("178622***@qq.com","xiuhong","UTF-8"));

        /*4.設置標題和內容*/
        mimeMessage.setSubject("測試郵件","UTF-8");
        mimeMessage.setContent("Test Content:這是一封測試郵件...","text/html;charset=UTF-8");
        mimeMessage.setSentDate(new Date());

        /*5.保存郵件*/
        mimeMessage.saveChanges();

        Transport transport = session.getTransport("smtp"); //獲取郵件傳輸對象
        transport.connect("mail.hand-china.com","xiuhong.chen@hand-china.com","*******");
        transport.sendMessage(mimeMessage,mimeMessage.getAllRecipients());
        transport.close();

        System.out.println("sendMailServlet-----end");
    }

  

查看郵箱客戶端,可以接收到郵件

 

 

某些郵箱服務器要求 SMTP 連接需要使用 SSL 安全認證 (為了提高安全性, 郵箱支持SSL連接, 也可以自己開啟),
如果無法連接郵件服務器, 仔細查看控制台打印的 log, 如果有有類似 “連接失敗, 要求 SSL 安全連接” 等錯誤,需要開啟SSL安全連接,如下代碼:

/*SMTP 服務器的端口 (非 SSL 連接的端口一般默認為 25, 可以不添加, 如果開啟了 SSL 連接,需要改為對應郵箱的 SMTP 服務器的端口, 具體可查看對應郵箱服務的幫助,
QQ郵箱的SMTP(SLL)端口為465或587, 其他郵箱自行去查看)*/
final String smtpPort = "465";
props.setProperty("mail.smtp.port", smtpPort);
props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.setProperty("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.socketFactory.port", smtpPort);

  

3.創建一封包含圖片和附件的復雜郵件
一封復雜的郵件內容可以看做是由很多節點(或者可以說是“片段”/“部分”/“零件”)組成,文本、圖片、附件等都可以看成是郵件內容中的一個節點。這些節點之間又可以相互關聯組合成一個節點。最終組合成一個大節點就是郵件的正文內容。

比如圖片和文字是關聯關系related,和簡單郵件不同之處在於設置圖片節點和文本節點

/*創建復雜郵件*/
    public void sendMail2()throws Exception{
        System.out.println("sendMailServlet-----start2");

        //1.創建郵件對象
        Properties properties = new Properties();
        properties.put("mail.smtp.host", "mail.hand-china.com"); // 指定SMTP服務器
        properties.put("mail.smtp.auth", "true"); // 指定是否需要SMTP驗證
        Session session = Session.getInstance(properties);
        MimeMessage message =new MimeMessage(session);

        /*2.設置發件人
        * 其中 InternetAddress 的三個參數分別為: 郵箱, 顯示的昵稱(只用於顯示, 沒有特別的要求), 昵稱的字符集編碼
        * */
        message.setFrom(new InternetAddress("xiuhong.chen@hand-china.com","xiuhong","UTF-8"));
        /*3.設置收件人
        To收件人   CC 抄送  BCC密送*/
        message.setRecipient(MimeMessage.RecipientType.TO,new InternetAddress("17862****@qq.com","xiuhong","UTF-8"));
        message.addRecipient(MimeMessage.RecipientType.TO,new InternetAddress("17862*****@qq.com","xiuhong","UTF-8"));

        /*4.設置標題*/
        message.setSubject("測試郵件","UTF-8");
        //message.setContent("Test Content:這是一封測試郵件...","text/html;charset=UTF-8");

        /*5.設置郵件正文*/

        //一個Multipart對象包含一個或多個bodypart對象,組成郵件正文
        MimeMultipart multipart = new MimeMultipart();
        //讀取本地圖片,將圖片數據添加到"節點"
        MimeBodyPart image = new MimeBodyPart();
        DataHandler dataHandler1 = new DataHandler(new FileDataSource("C:\\Users\\Chen Xiuhong\\Pictures\\suo.png"));
        image.setDataHandler(dataHandler1);
        image.setContentID("image_suo");

        //創建文本節點
        MimeBodyPart text = new MimeBodyPart();
        text.setContent("這張圖片是��鎖<br/><img src='cid:image_suo'/>","text/html;charset=UTF-8");

        //將文本和圖片添加到multipart
        multipart.addBodyPart(text);
        multipart.addBodyPart(image);
        multipart.setSubType("related");//關聯關系

        message.setContent(multipart);

        message.setSentDate(new Date());
        message.saveChanges();
        Transport transport = session.getTransport("smtp");
        transport.connect("mail.hand-china.com","xiuhong.chen@hand-china.com","******");
        transport.sendMessage(message,message.getAllRecipients());
        transport.close();

        System.out.println("sendMailServlet-----end2");
    }

  

 

下邊發送一封即有圖片文字,又有多個附件的郵件,設置節點關系為混合關系mixed.

public void sendMail2()throws Exception{
        System.out.println("sendMailServlet-----start2");

        //1.創建郵件對象
        Properties properties = new Properties();
        properties.put("mail.smtp.host", "mail.hand-china.com"); // 指定SMTP服務器
        properties.put("mail.smtp.auth", "true"); // 指定是否需要SMTP驗證
        Session session = Session.getInstance(properties);
        MimeMessage message =new MimeMessage(session);

        /*2.設置發件人
        * 其中 InternetAddress 的三個參數分別為: 郵箱, 顯示的昵稱(只用於顯示, 沒有特別的要求), 昵稱的字符集編碼
        * */
        message.setFrom(new InternetAddress("xiuhong.chen@hand-china.com","xiuhong","UTF-8"));
        /*3.設置收件人
        To收件人   CC 抄送  BCC密送*/
        message.setRecipient(MimeMessage.RecipientType.TO,new InternetAddress("178622****@qq.com","xiuhong","UTF-8"));
        message.addRecipient(MimeMessage.RecipientType.TO,new InternetAddress("17862****9@qq.com","xiuhong","UTF-8"));

        /*4.設置標題*/
        message.setSubject("測試郵件","UTF-8");
        //message.setContent("Test Content:這是一封測試郵件...","text/html;charset=UTF-8");

        /*5.設置郵件正文*/

        //一個Multipart對象包含一個或多個bodypart對象,組成郵件正文
        MimeMultipart multipart = new MimeMultipart();
        //讀取本地圖片,將圖片數據添加到"節點"
        MimeBodyPart image = new MimeBodyPart();
        DataHandler dataHandler1 = new DataHandler(new FileDataSource("C:\\Users\\Chen Xiuhong\\Pictures\\suo.png"));
        image.setDataHandler(dataHandler1);
        image.setContentID("image_suo");

        //創建文本節點
        MimeBodyPart text = new MimeBodyPart();
        text.setContent("這張圖片是��鎖<br/><img src='cid:image_suo'/>","text/html;charset=UTF-8");

        //創建附件節點  讀取本地文件,並讀取附件名稱
        MimeBodyPart file1 = new MimeBodyPart();
        DataHandler dataHandler2 = new DataHandler(new FileDataSource("C:\\Users\\Chen Xiuhong\\Pictures\\clothes.png"));
        file1.setDataHandler(dataHandler2);
        file1.setFileName(MimeUtility.encodeText(dataHandler2.getName()));

        MimeBodyPart file2 = new MimeBodyPart();
        DataHandler dataHandler3 = new DataHandler(new FileDataSource("C:\\Users\\Chen Xiuhong\\Downloads\\list.xlsx"));
        file2.setDataHandler(dataHandler3);
        file2.setFileName(MimeUtility.encodeText(dataHandler3.getName()));

        //將文本和圖片添加到multipart
        multipart.addBodyPart(text);
        multipart.addBodyPart(image);
        multipart.addBodyPart(file1);
        multipart.addBodyPart(file2);
        multipart.setSubType("mixed");//混合關系

        message.setContent(multipart);

        message.setSentDate(new Date());
        message.saveChanges();
        Transport transport = session.getTransport("smtp");
        transport.connect("mail.hand-china.com","xiuhong.chen@hand-china.com","*******");
        transport.sendMessage(message,message.getAllRecipients());
        transport.close();
        Boolean isFlag = true;
        logger.info(Calendar.getInstance().getTime()+" : # Send mail to "+" success #");

        System.out.println("sendMailServlet-----end2");
    }

  截圖如下:

一般項目中是不會從本地讀取文件,需要動態生成文件,這個時候我們可以把生成的文件寫入inputStream中,然后傳遞到sendmail方法中,來創建附件節點,具體代碼如下:

MimeBodyPart fileBody = new MimeBodyPart();
DataSource source = new ByteArrayDataSource(inputStream, "application/msexcel");
fileBody.setDataHandler(new DataHandler(source));
fileBody.setFileName(MimeUtility.encodeText(fileName));


4.HAP框架郵件模塊詳解
HAP框架提供了郵件賬戶,郵件模板和郵件狀態查詢三個功能, 我們可以在郵件賬戶中配置郵件服務器,端口號,以及賬戶名和密碼. 在郵件模板中配置好將要發送的郵件模板,這個模板是HTML格式的,便於我們設置郵件正文格式.下邊詳細介紹每個模塊的功能:

1)郵件賬戶配置界面:
SYS_MESSAGE_EMAIL_CONFIG : 存放配置代碼config_id, 郵件服務器host, 端口號port, account_id

SYS_MESSAGE_EMAIL_ACCOUNT: 存放郵件賬戶配置Id, 賬戶代碼,用戶名userName 密碼password

在該界面配置了發送郵件時需要准備的信息, 方便用戶在前台界面動態維護, 不需要改變后台代碼.

2)郵件模板配置界面
SYS_MESSAGE_TEMPLATE: 存放模板代碼, 模板類型, 發送類型(直接發送/定時發送), 郵件賬戶(在郵件賬戶界面配置的賬戶信息) , 郵件標題和內容

其中郵件標題和正文可以設置變量, 后台在代碼中可以動態改變這些變量的value 如:

MessageTemplate messageTemplate = messageTemplateMapper.getMsgTemByCode(null,"MQ_EMAIL");
String subject = messageTemplate.getSubject();      //郵件標題
subject = subject.replaceAll("company",companyName);
String content = messageTemplate.getContent();      //郵件content
Date d = new Date();
String newContent=content.replaceAll("time",sdf1.format(d))
                         .replaceAll("company",companyName)
                         .replaceAll("expireDate", String.valueOf(count2))
                         .replaceAll("warnDate", String.valueOf(count1));

  

5.發送郵件帶excel附件
業務背景: 以物料為例,將非有效狀態的資質數據以excel附件的形式發送郵件提醒客戶. 具體步驟如下:

a. 首先要查詢出非有效狀態的數據 —此處不展示

b. 其次將數據寫入Excel中 ( 此處是提前設置好的模板, 只需要在代碼中讀取模板,寫入數據 )

c. 創建郵件標題和內容 ( 此處是根據框架封裝的模塊,在前端維護好,郵件模板和郵件賬戶 )

c. 查詢客戶郵箱 —此處不展示

d. 發送郵件

在這里重點介紹,如何將數據寫入excel中,如何將excel添加到郵件中作為附件, 又是如何獲得標題和模板,如何發送郵件的.數據寫入excel: 讀取模板—>創建工作表—>創建行—>創建單元格—>excel寫入工作流

獲得模板路徑需要通過FreemarkerUtil來獲取相對路徑, 避免項目部署到服務器上時獲取不到模板路徑, 模板存放位置為:

 

 

 

/*****一個Excel文件的層次:Excel文件-> 工作表-> 行-> 單元格 對應到POI中,為:
workbook-> sheet-> row-> cell********/
String path = FreemarkerUtil.class.getClassLoader().getResource("").getPath();
String rootPath = path.substring(1, path.indexOf("/WEB-INF/"))+"/WEB-INF/excel/物料資質預警郵件模板.xlsx";
rootPath=rootPath.replace("/","\\");
FileInputStream template = new FileInputStream(rootPath);

XSSFWorkbook workBook = new XSSFWorkbook(template);
XSSFSheet sheet=workBook.getSheetAt(0);
/*水平垂直居中*/
XSSFCellStyle cellStyle = workBook.createCellStyle();
cellStyle.setAlignment(XSSFCellStyle.VERTICAL_CENTER);
cellStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
/*設置字體樣式*/
XSSFFont cellFont = workBook.createFont();
cellFont.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
cellFont.setFontHeight((short) 300);
cellStyle.setFont(cellFont);

/*數據寫入單元格*/
for(int j=0 ; j<gxpMqInfos1.size(); j++){
    rowIndex++ ;
    XSSFRow row=sheet.createRow(rowIndex);
    row.createCell(0).setCellValue(gxpMqInfos1.get(j).getOrganizationCode());
    row.createCell(1).setCellValue(gxpMqInfos1.get(j).getOrganizationName());
    row.createCell(2).setCellValue(gxpMqInfos1.get(j).getItemNo());
    row.createCell(3).setCellValue(gxpMqInfos1.get(j).getItemDesc());
    row.createCell(4).setCellValue(""); //產品線
    row.createCell(5).setCellValue(gxpMqInfos1.get(j).getQualifTpye());
    row.createCell(6).setCellValue(gxpMqInfos1.get(j).getQualifName());
    row.createCell(7).setCellValue(gxpMqInfos1.get(j).getCertificateNo());
    if("".equals(gxpMqInfos1.get(j).getStartDate()) || gxpMqInfos1.get(j).getStartDate() == null){
      row.createCell(8).setCellValue("");
    }else{
      row.createCell(8).setCellValue(sdf.format(gxpMqInfos1.get(j).getStartDate()));
    }
    if("".equals(gxpMqInfos1.get(j).getStartDate()) || gxpMqInfos1.get(j).getStartDate() == null){
      row.createCell(9).setCellValue("");
    }else{
      row.createCell(9).setCellValue(sdf.format(gxpMqInfos1.get(j).getEndDate()));
    }
    row.createCell(10).setCellValue(gxpMqInfos1.get(j).getWarningLeadTime());
    row.createCell(11).setCellValue(gxpMqInfos1.get(j).getRemainingDays());
    row.createCell(12).setCellValue(gxpMqInfos1.get(j).getAlertStatus());
}

/******workBook寫入輸出流**/
ByteArrayOutputStream baos = new ByteArrayOutputStream();
workBook.write(baos);
baos.flush();
baos.close();

  下一步獲取郵件賬戶,郵件標題,內容等

/*******7.4.1)獲取界面維護的郵件模板 郵件標題和內容*/
MessageTemplate messageTemplate = messageTemplateMapper.getMsgTemByCode(null,"MQ_EMAIL");
Long accountId = messageTemplate.getAccountId(); //郵件模板表SYS_MESSAGE_TEMPLATE中的 郵件賬戶ID

/*根據郵件模板表SYS_MESSAGE_TEMPLATE中的郵件賬戶ID accountId   在郵件賬戶表SYS_MESSAGE_EMAIL_ACCOUNT中查詢 賬戶(userName password)*/
MessageEmailAccount messageEmailAccount = emailAccountMapper.selectByPrimaryKey(accountId);

/*根據郵件賬戶表SYS_MESSAGE_EMAIL_ACCOUNT中的configId  在郵件賬戶配置表SYS_MESSAGE_EMAIL_CONFIG中查詢 賬戶配置信息(host port)*/
MessageEmailConfig messageEmailConfig = messageEmailConfigMapper.selectByPrimaryKey(messageEmailAccount.getConfigId());

String host=messageEmailConfig.getHost();           //郵件服務器
String userName = messageEmailAccount.getUserName();//發送人郵件用戶名
String password = messageEmailAccount.getPassword();//發送人郵件密碼
String subject = messageTemplate.getSubject();      //郵件標題
subject = subject.replaceAll("company",companyName);

String content = messageTemplate.getContent();      //郵件content
Date d = new Date();
String newContent=content.replaceAll("time",sdf1.format(d))
  .replaceAll("company",companyName)
  .replaceAll("expireDate", String.valueOf(count2*productLineList.size()))
  .replaceAll("warnDate", String.valueOf(count1*productLineList.size()));

  發送郵件,將郵件標題,內容和附件名稱,以及輸入流傳到郵件工具類中

for(String email:emailList){
  /***每次都需要新建輸入流  防止發送給第二個用戶的時候 郵件內容為空*/
  byte[] bt = baos.toByteArray();
  InputStream is = new ByteArrayInputStream(bt, 0, bt.length);
  MailUtil mailUtil=new MailUtil(host,userName,password);
  mailUtil.sendMail(subject, email, newContent ,"物料資質預警.xlsx", is,null);
}

  



發送郵件,主要是添加附件:

/*添加附件*/
if(is != null) {
  MimeBodyPart fileBody = new MimeBodyPart();
  DataSource source = new ByteArrayDataSource(is, "application/msexcel");
  fileBody.setDataHandler(new DataHandler(source));
  // 中文亂碼問題
  fileBody.setFileName(MimeUtility.encodeText(fileName));
  multipart.addBodyPart(fileBody);
}

  

完整的發送郵件工具類如下:

public class MailUtil {

    private String host;
    private String user;
    private String password;

    static Logger logger = LoggerFactory.getLogger(MailUtil.class);

    public MailUtil(String host, String user, String password){
        this.host = host;
        this.user = user;
        this.password = password;
    }

  public   boolean sendMail(String subject, String toMail, String content,String fileName, InputStream is,String ccList) {
        boolean isFlag = false;
        try {
            Properties props = new Properties();
            props.put("mail.smtp.host", host);   // 指定SMTP服務器
            props.put("mail.smtp.auth", "true"); // 指定是否需要SMTP驗證
            Session session = Session.getDefaultInstance(props);
            session.setDebug(false);

            MimeMessage message = new MimeMessage(session);
            try {
                //指定發送人
                message.setFrom(new InternetAddress(user));  
                //指定接收人
                message.addRecipient(Message.RecipientType.TO, new InternetAddress(toMail)); 
                //指定抄送人
                if(ccList!=null || !"".equals(ccList)){
                    message.addRecipients(Message.RecipientType.CC,ccList);
                }
                //設置標題
                message.setSubject(subject);
                message.addHeader("charset", "UTF-8");

                /*添加正文內容*/
                //一個Multipart對象包含一個或多個bodypart對象,組成郵件正文
                Multipart multipart = new MimeMultipart();   

                MimeBodyPart contentPart = new MimeBodyPart();
                contentPart.setText(content,"UTF-8");
                contentPart.setHeader("Content-Type", "text/html; charset=UTF-8");
                multipart.addBodyPart(contentPart);

                /*添加附件*/
                if(is != null) {
                    MimeBodyPart fileBody = new MimeBodyPart();
                    DataSource source = new ByteArrayDataSource(is, "application/msexcel");
                    fileBody.setDataHandler(new DataHandler(source));
                    // 中文亂碼問題
                    fileBody.setFileName(MimeUtility.encodeText(fileName));
                    multipart.addBodyPart(fileBody);
                }

                message.setContent(multipart);
                message.setSentDate(new Date());
                message.saveChanges();
                Transport transport = session.getTransport("smtp");             
                transport.connect(host, user, password);
                transport.sendMessage(message, message.getAllRecipients());
                transport.close();
                isFlag = true;
                logger.info(Calendar.getInstance().getTime()+":#Send mail to"+toMail+"success #");
            } catch (Exception e) {
                  logger.info(Calendar.getInstance().getTime()+":#Send mail to"+toMail+"error #");
                logger.info(e.toString());
                e.printStackTrace();
                isFlag = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return isFlag;
    }

  效果如下:

 

 

 

 

 

 

參考:http://www.runoob.com/java/java-sending-email.html

轉自:https://blog.csdn.net/a1786223749/article/details/78753184


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM