Author xiuhong.chen@hand-china.comhtml
Desc 簡單郵件發送前端
Date 2017/12/8java
項目中須要根據物料資質的情況實時給用戶發送郵件,而後我就簡單學習了SMTP.git
電子郵件的在網絡中傳輸和網頁同樣須要聽從特定的協議,經常使用的電子郵件協議包括 SMTP,POP3,IMAP。其中郵件的建立和發送只須要用到 SMTP協議,因此本文也只會涉及到SMTP協議。SMTP 是 Simple Mail Transfer Protocol 的簡稱,即簡單郵件傳輸協議。github
JavaMail 下載地址: https://github.com/javaee/javamail/releases安全
特別注意:服務器
首先建立一個 Java 工程,把下載好的 javax.mail.jar 做爲類庫加入工程網絡
郵件建立步驟:session
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"); }
查看郵箱客戶端,能夠接收到郵件app
某些郵箱服務器要求 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);
一封複雜的郵件內容能夠看作是由不少節點(或者能夠說是「片斷」/「部分」/「零件」)組成,文本、圖片、附件等均可以當作是郵件內容中的一個節點。這些節點之間又能夠相互關聯組合成一個節點。最終組合成一個大節點就是郵件的正文內容。
好比圖片和文字是關聯關係related,和簡單郵件不一樣之處在於設置圖片節點和文本節點
下邊發送一封即有圖片文字,又有多個附件的郵件,設置節點關係爲混合關係mixed
截圖以下:
通常項目中是不會從本地讀取文件,須要動態生成文件,這個時候咱們能夠把生成的文件寫入inputStream中,而後傳遞到sendmail方法中,來建立附件節點,具體代碼以下:
MimeBodyPart fileBody = new MimeBodyPart(); DataSource source = new ByteArrayDataSource(inputStream, "application/msexcel"); fileBody.setDataHandler(new DataHandler(source)); fileBody.setFileName(MimeUtility.encodeText(fileName));
HAP框架提供了郵件帳戶,郵件模板和郵件狀態查詢三個功能, 咱們能夠在郵件帳戶中配置郵件服務器,端口號,以及帳戶名和密碼. 在郵件模板中配置好將要發送的郵件模板,這個模板是HTML格式的,便於咱們設置郵件正文格式.下邊詳細介紹每一個模塊的功能:
SYS_MESSAGE_EMAIL_CONFIG : 存放配置代碼config_id, 郵件服務器host, 端口號port, account_id
SYS_MESSAGE_EMAIL_ACCOUNT: 存放郵件帳戶配置Id, 帳戶代碼,用戶名userName 密碼password
在該界面配置了發送郵件時須要準備的信息, 方便用戶在前臺界面動態維護, 不須要改變後臺代碼.
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));
業務背景: 以物料爲例,將非有效狀態的資質數據以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; }
效果以下: