直接使用图片的局域网地址(此方案不可行) 直接使用图片的局域网内的地址,比如图片url地址为本地地址,则只有在本机上打开收到的邮件时才会显示图片,在其他机器上打开邮件发现
直接使用图片的局域网地址(此方案不可行)
直接使用图片的局域网内的地址,比如图片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 = "[email protected]"; 186 String receiver = "[email protected]"; 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 }