javamail邮件工具类(增加465端口发送,收件,无效收件人过滤)
package com.flysand; import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; import com.j1cn.bizclient.meta.entity.email.EmailEntity; import com.j1cn.bizclient.meta.entity.email.EmailInfo; import com.j1cn.bizclient.meta.entity.email.ReceiveEntity; import com.j1cn.commons.exception.JyException; import com.j1cn.commons.utils.StringUtils; import com.sun.net.ssl.internal.ssl.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.mail.*; import javax.mail.internet.*; import javax.mail.util.ByteArrayDataSource; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.security.Security; import java.util.Date; import java.util.List; import java.util.Properties; import java.util.Vector; /** * 邮件工具类 * * @author flysand **/ public class EmailUtils { private static final Logger logger = LoggerFactory.getLogger(EmailUtils.class); private static final String MAIL_SMTP_AUTH = "mail.smtp.auth"; private static final String MAIL_TRANSPORT_PROTOCOL = "mail.transport.protocol"; private static final String MAIL_SMTP_HOST = "mail.smtp.host"; private static final String TEXT = "TEXT"; private static final String TEXT_PLAIN = "TEXT/PLAIN"; private static final String TEXT_HTML = "TEXT/HTML"; private static final String INVALID_ADDRESS_MESSAGE = "Invalid Addresses"; public static void sendAttachMail(EmailEntity emailEntity, InputStream is, String excelName) { logger.debug("发送一封带一个附件的邮件"); //基础校验 if (StringUtils.isBlank(emailEntity.getHost())) { throw new JyException("发件服务器未设置"); } if (emailEntity.getPort() == null) { emailEntity.setPort(25); } if (StringUtils.isBlank(emailEntity.getFrom())) { throw new JyException("发件人未设置"); } if (StringUtils.isBlank(emailEntity.getPassword())) { throw new JyException("发件人密码未设置"); } Properties properties = new Properties(); properties.setProperty(MAIL_SMTP_AUTH, "true"); properties.setProperty(MAIL_TRANSPORT_PROTOCOL, "smtp"); properties.setProperty(MAIL_SMTP_HOST, emailEntity.getHost()); Session session = Session.getDefaultInstance(properties); session.setDebug(false); MimeMessage message = new MimeMessage(session); try { //设置发件人邮箱 message.setFrom(new InternetAddress(emailEntity.getFrom())); setReCcList(emailEntity, message); //设置主题 message.setSubject(emailEntity.getSubject()); //设置中文 message.addHeader("charset", "UTF-8"); //正文 Multipart multipart = new MimeMultipart(); BodyPart bodyPart = new MimeBodyPart(); //设置邮件正文内容 bodyPart.setText(emailEntity.getContent()); //设置正文中文 bodyPart.setHeader("Content-Type", "text/html;charset=UTF-8"); multipart.addBodyPart(bodyPart); //附件 MimeBodyPart fileBody = new MimeBodyPart(); DataSource source = new ByteArrayDataSource(is, "application/vnd.ms-excel"); fileBody.setDataHandler(new DataHandler(source)); String filename = StringUtils.isBlank(excelName) ? "excel" + FileUtils.EXCEL_SUFFIX : excelName; fileBody.setFileName(MimeUtility.encodeText(filename)); multipart.addBodyPart(fileBody); message.setContent(multipart); message.setSentDate(new Date()); message.saveChanges(); Transport transport = session.getTransport("smtp"); transport.connect(emailEntity.getHost(), emailEntity.getPort(), emailEntity.getFrom(), emailEntity.getPassword()); transport.sendMessage(message, message.getAllRecipients()); transport.close(); } catch (Exception e) { e.printStackTrace(); throw new JyException("邮件发送失败"); } } public static void sendSslAttachMail(EmailEntity emailEntity, InputStream is, String excelName) { logger.debug("发送一封带一个附件的邮件"); //基础校验 if (StringUtils.isBlank(emailEntity.getHost())) { throw new JyException("发件服务器未设置"); } if (emailEntity.getPort() == null) { emailEntity.setPort(465); } if (StringUtils.isBlank(emailEntity.getFrom())) { throw new JyException("发件人未设置"); } if (StringUtils.isBlank(emailEntity.getPassword())) { throw new JyException("发件人密码未设置"); } //设置SSL连接、邮件配置 Security.addProvider(new Provider()); Properties props = System.getProperties(); props.setProperty("mail.smtp.host", emailEntity.getHost()); props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.setProperty("mail.smtp.socketFactory.fallback", "false"); props.setProperty("mail.smtp.port", "465"); props.setProperty("mail.smtp.socketFactory.port", "465"); props.setProperty("mail.smtp.auth", "true"); Session session = Session.getDefaultInstance(props, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(emailEntity.getFrom(), emailEntity.getPassword()); } }); session.setDebug(false); MimeMessage message = new MimeMessage(session); try { //设置发件人邮箱 message.setFrom(new InternetAddress(emailEntity.getFrom())); setReCcList(emailEntity, message); //设置主题 message.setSubject(emailEntity.getSubject()); //设置中文 message.addHeader("charset", "UTF-8"); //正文 Multipart multipart = new MimeMultipart(); BodyPart bodyPart = new MimeBodyPart(); //设置邮件正文内容 bodyPart.setText(emailEntity.getContent()); //设置正文中文 bodyPart.setHeader("Content-Type", "text/html;charset=UTF-8"); multipart.addBodyPart(bodyPart); //附件 MimeBodyPart fileBody = new MimeBodyPart(); DataSource source = new ByteArrayDataSource(is, "application/vnd.ms-excel"); fileBody.setDataHandler(new DataHandler(source)); String filename = StringUtils.isBlank(excelName) ? "excel" + FileUtils.EXCEL_SUFFIX : excelName; fileBody.setFileName(MimeUtility.encodeText(filename)); multipart.addBodyPart(fileBody); message.setContent(multipart); message.setSentDate(new Date()); message.saveChanges(); Transport transport = session.getTransport("smtp"); transport.connect(emailEntity.getHost(), emailEntity.getPort(), emailEntity.getFrom(), emailEntity.getPassword()); transport.sendMessage(message, message.getAllRecipients()); transport.close(); } catch (SendFailedException se) { // 判断当前失败信息,如果为地址错误,则过滤无效地址后重发 if (INVALID_ADDRESS_MESSAGE.equals(se.getMessage())) { Address[] addresses = se.getInvalidAddresses(); List<String> addressList = Lists.newArrayList(); List<String> recipientList = emailEntity.getRecipients(); List<String> ccList = emailEntity.getCcList(); for (Address address : addresses) { InternetAddress internetAddress = (InternetAddress) address; if (recipientList.contains(internetAddress.getAddress())) { recipientList.remove(internetAddress.getAddress()); } if (ccList.contains(internetAddress.getAddress())) { ccList.remove(internetAddress.getAddress()); } addressList.add(internetAddress.getAddress()); } logger.error("存在不可用邮箱地址:{},过滤后重新发送邮件...", JSON.toJSONString(addressList)); if (CollectionUtils.isEmpty(recipientList)) { logger.error("不存在有效的邮箱地址,已配置但无效的邮箱地址:{}", JSON.toJSONString(addressList)); throw new JyException("不存在有效的邮箱地址,已配置但无效的邮箱地址:" + JSON.toJSONString(addressList)); } // 重新发送 emailEntity.setRecipients(new Vector<>(recipientList)); if (!CollectionUtils.isEmpty(ccList)) { emailEntity.setCcList(new Vector<>(ccList)); } sendSslAttachMail(emailEntity, is, excelName); } } catch (Exception e) { e.printStackTrace(); throw new JyException("邮件发送失败"); } } private static void setReCcList(EmailEntity emailEntity, MimeMessage message) throws MessagingException { //设置收件人和抄送人 if (!CollectionUtils.isEmpty(emailEntity.getRecipients())) { Address[] addresses = new Address[emailEntity.getRecipients().size()]; for (int i = 0; i < emailEntity.getRecipients().size(); i++) { addresses[i] = new InternetAddress(emailEntity.getRecipients().get(i)); } message.addRecipients(Message.RecipientType.TO, addresses); } if (!CollectionUtils.isEmpty(emailEntity.getCcList())) { Address[] ccList = new Address[emailEntity.getCcList().size()]; for (int i = 0; i < emailEntity.getCcList().size(); i++) { ccList[i] = new InternetAddress(emailEntity.getCcList().get(i)); } message.addRecipients(Message.RecipientType.CC, ccList); } } /** * 发送带多个附件的邮件 * * @param emailEntity 邮箱参数对象 * @param fileList 附件文件列表 */ public static void sendMultiAttachEmail(EmailEntity emailEntity, List<File> fileList) { logger.debug("发送多附件邮件..."); //基础校验 if (StringUtils.isBlank(emailEntity.getHost())) { throw new JyException("发件服务器未设置"); } if (emailEntity.getPort() == null) { emailEntity.setPort(25); } if (StringUtils.isBlank(emailEntity.getFrom())) { throw new JyException("发件人未设置"); } if (StringUtils.isBlank(emailEntity.getPassword())) { throw new JyException("发件人密码未设置"); } Properties properties = new Properties(); properties.setProperty(MAIL_SMTP_AUTH, "true"); properties.setProperty(MAIL_TRANSPORT_PROTOCOL, "smtp"); properties.setProperty(MAIL_SMTP_HOST, emailEntity.getHost()); Session session = Session.getDefaultInstance(properties); session.setDebug(false); setEmailMessage(emailEntity, fileList, session); } private static void setEmailMessage(EmailEntity emailEntity, List<File> fileList, Session session) { MimeMessage message = new MimeMessage(session); try { //设置发件人邮箱 message.setFrom(new InternetAddress(emailEntity.getFrom())); //设置收件人和抄送人 setReCcList(emailEntity, message); //设置主题 message.setSubject(MimeUtility.encodeText(emailEntity.getSubject(), "UTF-8", "B")); //设置中文 message.addHeader("charset", "UTF-8"); //正文 Multipart multipart = new MimeMultipart(); BodyPart bodyPart = new MimeBodyPart(); //设置邮件正文内容 bodyPart.setText(emailEntity.getContent()); //设置正文中文 bodyPart.setHeader("Content-Type", "text/html;charset=UTF-8"); multipart.addBodyPart(bodyPart); //附件 for (File file : fileList) { MimeBodyPart fileBody = new MimeBodyPart(); FileDataSource fileDataSource = new FileDataSource(file); fileBody.setDataHandler(new DataHandler(fileDataSource)); fileBody.setFileName(MimeUtility.encodeText(file.getName(), "UTF-8", "B")); multipart.addBodyPart(fileBody); } message.setContent(multipart); message.setSentDate(new Date()); message.saveChanges(); Transport transport = session.getTransport("smtp"); transport.connect(emailEntity.getHost(), emailEntity.getPort(), emailEntity.getFrom(), emailEntity.getPassword()); transport.sendMessage(message, message.getAllRecipients()); transport.close(); } catch (SendFailedException se) { // 判断当前失败信息,如果为地址错误,则过滤无效地址后重发 if (INVALID_ADDRESS_MESSAGE.equals(se.getMessage())) { Address[] addresses = se.getInvalidAddresses(); List<String> addressList = Lists.newArrayList(); List<String> recipientList = emailEntity.getRecipients(); List<String> ccList = emailEntity.getCcList(); for (Address address : addresses) { InternetAddress internetAddress = (InternetAddress) address; if (recipientList.contains(internetAddress.getAddress())) { recipientList.remove(internetAddress.getAddress()); } if (ccList.contains(internetAddress.getAddress())) { ccList.remove(internetAddress.getAddress()); } addressList.add(internetAddress.getAddress()); } logger.error("存在不可用邮箱地址:{},过滤后重新发送邮件...", JSON.toJSONString(addressList)); if (CollectionUtils.isEmpty(recipientList)) { logger.error("不存在有效的邮箱地址,已配置但无效的邮箱地址:{}", JSON.toJSONString(addressList)); throw new JyException("不存在有效的邮箱地址,已配置但无效的邮箱地址:" + JSON.toJSONString(addressList)); } // 重新发送 emailEntity.setRecipients(new Vector<>(recipientList)); if (!CollectionUtils.isEmpty(ccList)) { emailEntity.setCcList(new Vector<>(ccList)); } setEmailMessage(emailEntity, fileList, session); } } catch (Exception e) { e.printStackTrace(); throw new JyException("邮件发送失败"); } } /** * 发送邮件 * * @param email 邮件发送参数 * @param fileList 附件列表 * @return 是否发送成功 */ public static boolean sendEmail(EmailEntity email, List<File> fileList) { try { EmailUtils.sendMultiAttachEmail(email, fileList); logger.info("邮件发送成功"); return true; } catch (JyException e) { logger.error("邮件发送失败{}", e.getMessage()); return false; } } /** * SSL发送邮件 465端口 * * @param email * @param fileList * @return */ public static boolean sendSslEmail(EmailEntity email, List<File> fileList) { logger.info("ssl发送邮件..."); try { if (email.getPort() == null) { email.setPort(465); } //设置SSL连接、邮件配置 Security.addProvider(new Provider()); Properties props = System.getProperties(); props.setProperty("mail.smtp.host", email.getHost()); props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.setProperty("mail.smtp.socketFactory.fallback", "false"); props.setProperty("mail.smtp.port", "465"); props.setProperty("mail.smtp.socketFactory.port", "465"); props.setProperty("mail.smtp.auth", "true"); Session session = Session.getDefaultInstance(props, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(email.getFrom(), email.getPassword()); } }); session.setDebug(true); setEmailMessage(email, fileList, session); logger.info("邮件发送成功"); return true; } catch (JyException e) { logger.error("邮件发送失败 - {}", e.getMessage()); return false; } } /** * 获取当前邮箱的所有邮件 -- 暂不能包含附件 * * @param receiveEntity * @return * @throws Exception */ public static List<EmailInfo> receiveAllEmail(ReceiveEntity receiveEntity) throws Exception { logger.info("收取邮件..."); Folder folder = getInBox(receiveEntity); // 获得收件箱的邮件列表 Message[] messages = folder.getMessages(); return getReceivedEmailContent(messages); } /** * 获取邮件信息,仅支持纯文本邮件 * * @param messages * @return * @throws MessagingException * @throws IOException */ public static List<EmailInfo> getReceivedEmailContent(Message[] messages) throws Exception { List<EmailInfo> emailInfoList = Lists.newArrayList(); for (Message message : messages) { emailInfoList.add(getReceivedEmailContent(message)); } return emailInfoList; } /** * 获取邮件信息,仅支持除文本邮件 * * @param message * @return * @throws Exception */ public static EmailInfo getReceivedEmailContent(Message message) throws Exception { EmailInfo emailInfo = new EmailInfo(); InternetAddress[] fromAddress = (InternetAddress[]) message.getFrom(); InternetAddress[] recipientAddress = (InternetAddress[]) message.getAllRecipients(); emailInfo.setFrom(fromAddress[0].getAddress()); List<String> recipientList = Lists.newArrayList(); for (InternetAddress recipient : recipientAddress) { recipientList.add(recipient.getAddress()); } emailInfo.setRecipient(recipientList); emailInfo.setSubject(message.getSubject()); if (message.getContentType().contains(TEXT)) { //纯文本 -- 获取html 不包含图片等其他资源 emailInfo.setContent((String) message.getContent()); } else { //签名信息中含有图片 -- 暂不处理纯文本和图片 获取html内容 Multipart multipart = (Multipart) message.getContent(); for (int i = 0; i < multipart.getCount(); i++) { BodyPart bodyPart = multipart.getBodyPart(i); if (!bodyPart.getContentType().contains(TEXT)) { Multipart part = (Multipart) bodyPart.getContent(); for (int j = 0; j < part.getCount(); j++) { BodyPart bodyPart1 = part.getBodyPart(j); if (bodyPart1.getContentType().contains(TEXT_HTML)) { emailInfo.setContent(bodyPart1.getContent().toString()); break; } } } else if (bodyPart.getContentType().contains(TEXT_HTML)) { emailInfo.setContent(bodyPart.getContent().toString()); break; } if (StringUtils.isNotBlank(emailInfo.getContent())) { break; } } } return emailInfo; } /** * 获取收件箱 * * @param receiveEntity * @return * @throws Exception */ public static Folder getInBox(ReceiveEntity receiveEntity) throws Exception { Properties props = new Properties(); props.setProperty("mail.imap.host", receiveEntity.getHost()); props.put("mail.smtp.auth", true); props.put("mail.smtps.ssl.protocols", "TSLv1 TSLv1.1 TLSv1.2"); props.put("mail.transport.protocol", "imap"); props.put("mail.smtp.ssl.ciphersuites", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, TLS_DH_anon_WITH_AES_128_GCM_SHA256, TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_ECDH_anon_WITH_AES_128_CBC_SHA, TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_DH_anon_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, TLS_RSA_WITH_NULL_SHA256, TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_RSA_WITH_NULL_SHA, TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS_ECDH_RSA_WITH_NULL_SHA, TLS_ECDH_anon_WITH_NULL_SHA, SSL_RSA_WITH_NULL_MD5, TLS_KRB5_WITH_3DES_EDE_CBC_SHA, TLS_KRB5_WITH_3DES_EDE_CBC_MD5, TLS_KRB5_WITH_DES_CBC_SHA, TLS_KRB5_WITH_DES_CBC_MD5, TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"); // 创建session实例对象 Session session = Session.getInstance(props); session.setDebug(true); // 创建IMAP协议的Store对象 Store store = session.getStore("imap"); // 连接邮件服务器 store.connect(receiveEntity.getReceiver(), receiveEntity.getPassword()); // 获得收件箱 Folder folder = store.getFolder("INBOX"); // 以读写模式打开收件箱 folder.open(Folder.READ_WRITE); return folder; } }