直接使用圖片的局域網地址(此方案不可行)
直接使用圖片的局域網內的地址,比如圖片url地址為本地地址,則只有在本機上打開收到的郵件時才會顯示圖片,在其他機器上打開郵件發現圖片不顯示
解決方案:
1.為圖片存儲的環境映射外網地址
2.使用javamail提供的cid方式進行圖片發送(可行)
使用javamail中cid方式發送html中的圖片
1 package com.montnets.test; 2 3 import com.montnets.email.specmailgate.constant.EmailGateConstant; 4 import com.montnets.email.specmailgate.service.MyAuthenticator; 5 import lombok.extern.slf4j.Slf4j; 6 import org.dom4j.Document; 7 import org.dom4j.DocumentHelper; 8 import org.dom4j.Element; 9 10 import javax.activation.DataHandler; 11 import javax.mail.Message; 12 import javax.mail.MessagingException; 13 import javax.mail.Session; 14 import javax.mail.Transport; 15 import javax.mail.internet.InternetAddress; 16 import javax.mail.internet.MimeBodyPart; 17 import javax.mail.internet.MimeMessage; 18 import javax.mail.internet.MimeMultipart; 19 import java.net.HttpURLConnection; 20 import java.net.URL; 21 import java.util.*; 22 23 /** 24 * @Author: chenlinyan 25 * @Date: 2019/7/8 16:40 26 * @Version 1.0 27 */ 28 @Slf4j 29 public class TestEmail { 30 31 32 /** 33 * 創建一封郵件的實例對象 34 * 35 * @param session 36 * @param theme 郵件主題 37 * @param content 郵件內容 38 * @param sendAccount 發送賬號 39 * @param receiver 接收者賬號 40 * @return 41 * @throws Exception 42 */ 43 public MimeMessage getMimeMessage(Session session, String theme, String content, String sendAccount, String receiver) throws Exception { 44 //創建一封郵件的實例對象 45 MimeMessage msg = new MimeMessage(session); 46 //設置發件人地址 47 msg.setFrom(new InternetAddress(sendAccount)); 48 //單個目標收件人 49 msg.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(receiver)); 50 //設置郵件主題 51 msg.setSubject(theme); 52 MimeMultipart multipart = new MimeMultipart(); 53 //處理郵件內容 54 Document document = getHtmlDocument(content); 55 if (document != null) { 56 Set<String> imgPaths = getImgs(document); 57 setImageMultipart(multipart, imgPaths); 58 content = getHtmlContent(document); 59 } 60 //設置郵件正文 61 MimeBodyPart text = new MimeBodyPart(); 62 text.setContent(content, "text/html;charset=UTF-8"); 63 multipart.addBodyPart(text); 64 multipart.setSubType("related"); 65 msg.setSentDate(new Date()); 66 msg.setContent(multipart); 67 msg.saveChanges(); 68 return msg; 69 } 70 71 72 public Document getHtmlDocument(String html) { 73 try { 74 //有些圖片鏈接帶有&符號 75 String content = html.replace("&", "&"); 76 return DocumentHelper.parseText(content); 77 } catch (Exception e) { 78 log.warn("郵件html內容不符合xml格式,郵件內容為{}", html, e); 79 return null; 80 } 81 } 82 83 84 public String getHtmlContent(Document document) { 85 String content = document.asXML().replace("&", "&"); 86 log.info("郵件發送內容為:{}", content); 87 return content; 88 } 89 90 /** 91 * 獲取圖片資源地址 92 * 93 * @param document 94 * @return 95 */ 96 public Set<String> getImgs(Document document) { 97 Set<String> sets = new HashSet<>(); 98 String imgPath = null; 99 try { 100 List<Element> elements = document.selectNodes("//img"); 101 for (Element element : elements) { 102 imgPath = element.attributeValue("src"); 103 if (imgPath != null) { 104 element.addAttribute("src", "cid:" + imgPath); 105 sets.add(imgPath); 106 } 107 } 108 } catch (Exception e) { 109 log.error("獲取html中img標簽內圖片路徑異常,html內容為{}", document.asXML(), e); 110 } 111 return sets; 112 } 113 114 115 /** 116 * 設置圖片cid至MimeMultipart中 117 * 118 * @param multipart 119 * @param imgPaths 120 */ 121 public void setImageMultipart(MimeMultipart multipart, Set<String> imgPaths) { 122 if (imgPaths == null || imgPaths.isEmpty()) { 123 return; 124 } 125 MimeBodyPart image = null; 126 URL url; 127 for (String imgPath : imgPaths) { 128 try { 129 url = new URL(imgPath); 130 //判斷圖片地址資源是否可訪問 131 if (isConnect(url)) { 132 image = new MimeBodyPart(); 133 DataHandler dh = new DataHandler(url); 134 image.setDataHandler(dh); 135 image.setContentID(imgPath); 136 multipart.addBodyPart(image); 137 } else { 138 log.warn("{}資源地址無效", imgPath); 139 } 140 } catch (Exception e) { 141 log.error("郵件圖片發送,設置圖片cid異常,異常圖片為{}", imgPath, e); 142 } 143 } 144 } 145 146 147 /** 148 * 功能:檢測當前URL是否可連接或是否有效, 149 * 描述:最多連接網絡 n 次, 如果 n 次都不成功,視為該地址不可用 150 * 151 * @param url 指定URL網絡地址 152 * @return boolean 153 */ 154 public synchronized static boolean isConnect(URL url) { 155 HttpURLConnection con; 156 int state = -1; 157 int counts = 0; 158 if (url == null) { 159 return false; 160 } 161 while (counts < EmailGateConstant.CONN_TIMES) { 162 try { 163 con = (HttpURLConnection) url.openConnection(); 164 //連接超時時間 165 con.setConnectTimeout(3000); 166 state = con.getResponseCode(); 167 if (state == 200) { 168 return true; 169 } 170 break; 171 } catch (Exception ex) { 172 counts++; 173 continue; 174 } 175 } 176 return false; 177 } 178 179 180 /** 181 *方法入口,測試 182 */ 183 public static void main(String[] args) { 184 String host = "smtp.qq.com"; 185 String sendAccount = "xxxx@qq.com"; 186 String receiver = "xxxx@qq.com"; 187 String pwd = "123456"; 188 String theme = "發送圖片"; 189 String content = "<p>圖片測試<img src=\"http://192.169.1.101:8080/WebTest/file/qq.PNG\"/></p>"; 190 191 Properties props = new Properties(); 192 //設置用戶的認證方式 193 props.setProperty("mail.smtp.auth", "true"); 194 //設置傳輸協議 195 props.setProperty("mail.transport.protocol", "smtp"); 196 //設置發件人的SMTP服務器地址 197 props.setProperty("mail.smtp.host", host); 198 props.setProperty("mail.smtp.port", "25"); 199 //連接超時時間 200 props.put("mail.smtp.connectiontimeout", 30000); 201 //讀超時時間 202 props.put("mail.smtp.timeout", 30000); 203 //寫超時時間 204 props.put("mail.smtp.writetimeout", 30000); 205 206 Transport transport = null; 207 try { 208 //1、創建定義整個應用程序所需的環境信息的 Session 對象 209 Session session = Session.getInstance(props, new MyAuthenticator(sendAccount, pwd)); 210 //設置調試信息在控制台打印出來 211 session.setDebug(true); 212 //根據session對象獲取郵件傳輸對象Transport 213 transport = session.getTransport(); 214 // //添加監聽器 215 // transport.addTransportListener(mailListener); 216 //與服務器建立連接 217 transport.connect(); 218 Message message = new TestEmail().getMimeMessage(session, theme,content,sendAccount,receiver); 219 //發送郵件 220 transport.sendMessage(message, message.getAllRecipients()); 221 } catch (Exception e) { 222 e.printStackTrace(); 223 }finally { 224 if(transport != null){ 225 try { 226 transport.close(); 227 } catch (MessagingException e) { 228 e.printStackTrace(); 229 } 230 } 231 } 232 } 233 }