package com.yc.crm.mail.service; import com.sun.mail.imap.IMAPBodyPart; import com.sun.mail.imap.IMAPStore; import com.yc.action.grid.GridUtils; import com.yc.crm.mail.action.MailPush; import com.yc.crm.mail.entity.FoundationEntity; import com.yc.crm.mail.entity.MailFileEntity; import com.yc.crm.mail.entity.T482102Entity; import com.yc.crm.mail.entity.t482101HEntity; import com.yc.entity.attachment.AttachmentEntity; import com.yc.factory.FactoryBean; import com.yc.service.BaseService; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.mail.*; import javax.mail.internet.*; import javax.servlet.http.HttpServletRequest; import java.io.*; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.ZoneId; import java.util.*; import static com.yc.crm.mail.service.MailImpl.shoppingImageServer; /** * @BelongsProject: eCoWorksV3 * @BelongsPackage: com.yc.crm.mail.service * @author: xinyb * @CreateTime: 2024-09-12 10:30 * @Description: */ @Service public class MailServiceImpl extends BaseService implements MailServiceIfc { @Autowired MailIfc mailIfc; @Autowired MailAccountIfc mailAccountIfc; @Autowired MailFileIfc mailFileIfc; @Override public void receivingEmails(T482102Entity emailEntity, FoundationEntity foundation) throws MessagingException { String protocol = emailEntity.getReceiveProtocol().toLowerCase();//接收协议 imap pop3 String server = emailEntity.getReceiveHost();//"imap.qq.com"; Integer port = emailEntity.getReceivePort();//993 String user = emailEntity.getReceiveEmail();//邮箱 String pwd = emailEntity.getReceivePassword();//密码 Properties properties = new Properties(); properties.setProperty("mail.store.protocol", protocol); // IMAP over SSL if (protocol.contains("imap")) {//接收协议imap properties.setProperty("mail.imaps.host", server); properties.setProperty("mail.imaps.port", port + ""); } else if (protocol.contains("pop3")) {//接收协议pop3 properties.setProperty("mail.pop3.host", server); properties.setProperty("mail.pop3.port", port + ""); } else {//其他(再加) properties.setProperty("mail.imaps.host", server); properties.setProperty("mail.imaps.port", port + ""); } // properties.put("mail.imaps.starttls.enable", "true");//// IMAP 协议设置 STARTTLS HashMap IAM = new HashMap(); //带上IMAP ID信息,由key和value组成,例如name,version,vendor,support-email等。 IAM.put("name", user); IAM.put("version", emailEntity.getDocVersion() + ""); IAM.put("vendor", emailEntity.getCompanyName()); IAM.put("support-email", emailEntity.getEmail()); //创建会话 Session session = Session.getInstance(properties, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(user, pwd); } }); //存储对象 IMAPStore store = (IMAPStore) session.getStore(protocol);//imap协议或pop3协议类型(推荐你使用IMAP协议来存取服务器上的邮件。) //连接 store.connect(server, user, pwd); store.id(IAM);//163邮箱需要,不然会报:A3 NO SELECT Unsafe Login. Please contact kefu@188.com for help Folder folder = null; try { // 获得收件箱 folder = store.getFolder("INBOX"); // 以读写模式打开收件箱 folder.open(Folder.READ_WRITE); //false 表示未读 ,true已读,获得收件箱的邮件列表 // FlagTerm flagTerm = new FlagTerm(new Flags(Flags.Flag.SEEN), true); // Message[] messages = folder.search(flagTerm); //获取收件箱邮件(全部) Message[] messages = folder.getMessages(); //邮箱封装保存 setMailContent(messages, emailEntity, foundation); } catch (NoSuchProviderException e) { throw e; } catch (MessagingException e) { throw e; } catch (IOException e) { throw new RuntimeException(e); } catch (Exception e) { throw new RuntimeException(e); } finally { try { if (folder != null) { folder.close(false); } if (store != null) { store.close(); } } catch (MessagingException e) { throw e; } } } @Override public void sendEmails(t482101HEntity t482101H, HttpServletRequest request) throws Exception { try { //根据当前用户查询绑定的邮箱信息 T482102Entity emailEntity = mailAccountIfc.getAccountInfo(t482101H.getUserCode(), t482101H.getSender());//返回邮箱的账号信息 if (emailEntity == null || StringUtils.isBlank(emailEntity.getSmtpEmail())) { if (StringUtils.isBlank(t482101H.getDocCode())) { t482101H.setMailType(0);//草稿箱状态 t482101H = mailIfc.saveReceivingMail(t482101H);//保存到草稿箱内 } throw new MessagingException("找不到邮箱:" + t482101H.getSender() + "配置信息请完善。邮件已保存到草稿箱#" + t482101H.getDocCode()); } //有发送的邮件保存到后台数据库 //邮箱服务器配置 Properties properties = new Properties(); properties.setProperty("mail.smtp.auth", "true");// // 设置SMTP是否需要认证 指定客户端是否向邮件服务器提交认证 properties.setProperty("mail.transport.protocol", "smtp");//设置传输协议 指定采用的邮件发送协议。 properties.setProperty("mail.smtp.ssl.enable", emailEntity.isSmtpSSL() + "");// // 设置启用SSL加密 properties.setProperty("mail.smtp.host", emailEntity.getSmtpHost()); properties.setProperty("mail.smtp.port", emailEntity.getSmtpPort() + ""); //Could not connect to SMTP host: smtp.qq.com, port: 465, response: -1 by danaus 2024-09-23 11:01 // properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); // MailSSLSocketFactory sf = new MailSSLSocketFactory("TLSv1.2"); // properties.put("mail.smtp.ssl.socketFactory", sf); // properties.setProperty("mail.smtp.ssl.protocols", "TLSv1.2"); // properties.setProperty("mail.smtp.starttls.enable", "true");//// SMTP 协议设置 STARTTLS 开启tls // properties.setProperty("mail.smtp.socketFactory.port", emailEntity.getSmtpPort() + ""); // String sendEmail = emailEntity.getSmtpEmail();//发件人 String sendPassword = emailEntity.getSmtpPassword();//密码 String recipientEmail = StringUtils.join(t482101H.getReceiver(), ",");//收件人 Session session = Session.getInstance(properties, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(sendEmail, sendPassword); } }); MimeMessage message = new MimeMessage(session); message.setFrom(new InternetAddress(sendEmail)); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail)); message.setSubject(t482101H.getSubject());//主题 String Unique_ID = "";//系统单号唯一码 message.setHeader("Message-ID", Unique_ID);//系统内部唯一码 t482101H.setMessageId(Unique_ID);//messageId赋值 if (t482101H.getCc() != null && t482101H.getCc().size() > 0) {//抄送 message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(StringUtils.join(t482101H.getCc(), ","))); } if (t482101H.getBcc() != null && t482101H.getBcc().size() > 0) {//密送 message.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(StringUtils.join(t482101H.getBcc(), ","))); } //创建多部分消息 Multipart multipart = new MimeMultipart(); MimeBodyPart textPart = new MimeBodyPart(); textPart.setText(t482101H.getContent());//内容 multipart.addBodyPart(textPart); //下面附件内容 if (StringUtils.isNotBlank(t482101H.getAttachmentList())) {//有附件内容 //获取到附件内容 List attachmentEntities = mailFileIfc.getAttachmentEntityList(t482101H.getAttachmentList()); if (attachmentEntities != null && attachmentEntities.size() > 0) { for (AttachmentEntity a : attachmentEntities) { InputStream inputStream = new ByteArrayInputStream(a.getOriginalPicture()); File file = new File(a.getOriginalFileName()); FileUtils.copyInputStreamToFile(inputStream, file); MimeBodyPart bodyPart = new MimeBodyPart(); bodyPart.attachFile(file); bodyPart.setFileName(a.getOriginalFileName()); multipart.addBodyPart(bodyPart); } } } message.setContent(multipart); try { if (StringUtils.isBlank(t482101H.getDocCode())) {//不在草稿箱有单号 mailIfc.saveReceivingMail(t482101H);//保存后发送 } else { t482101H.setMailType(2);//发件箱状态 mailIfc.updateMailDrafts(t482101H);//更新成发件箱 } Transport.send(message);//发送 } catch (MessagingException m) {//发送异常处理 t482101H.setMailType(0);//草稿箱状态 mailIfc.updateMailDrafts(t482101H);//更新成草稿箱 throw new MessagingException("发送邮件异常,邮件已保存在草稿箱。异常原因:" + m.getMessage() + "#" + t482101H.getDocCode()); } } catch (Exception e) { throw e; } } @Override public Integer setQuickReply(String docCode, String content) throws MessagingException { String sql = "set nocount on\n"; try { sql += "declare @docCode varchar(200) ='" + docCode + "'\n"; sql += "update t482101H set receive_time=getdate() where docCode=@docCode\n";//更新回复时间 sql += "select a.subject,a.sender,a.receiver,a.messageid,b.smtpEmail,b.smtpPassword,b.smtpHost,b.smtpPort,isnull(b.smtpSSL,0) as smtpSSL " + " from t482101H a join t482102 b on a.receiver=b.smtpEmail where docCode=@docCode"; Map map = jdbcTemplate.queryForMap(sql); if (map == null || map.get("sender") == null) { throw new MessagingException("回复人信息查找不到,请检查docCode唯一码"); } String receiver = (String) map.get("sender");//收件人 String sender = (String) map.get("receiver");//发件人 String smtpSSL = map.get("smtpSSL").equals(0) ? "false" : "true"; Properties props = new Properties(); props.setProperty("mail.smtp.auth", "true"); props.setProperty("mail.transport.protocol", "smtp");//设置传输协议 指定采用的邮件发送协议。 props.setProperty("mail.smtp.ssl.enable", smtpSSL);// // 设置启用SSL加密 props.setProperty("mail.smtp.host", (String) map.get("smtpHost")); props.setProperty("mail.smtp.port", map.get("smtpPort") + ""); // props.setProperty("mail.smtp.starttls.enable", "true"); Session session = Session.getInstance(props, new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication((String) map.get("smtpEmail"), (String) map.get("smtpPassword")); } }); Message replyMessage = new MimeMessage(session); replyMessage.setFrom(new InternetAddress(sender)); replyMessage.setRecipients(Message.RecipientType.TO, InternetAddress.parse(receiver));//收件人 replyMessage.setSubject("Re: " + map.get("subject"));//主题 // 引用原邮件 replyMessage.setHeader("In-Reply-To", (String) map.get("messageid")); replyMessage.setHeader("References", (String) map.get("messageid")); replyMessage.setText(content);//这里是回复的内容 Transport.send(replyMessage); return 1; } catch (MessagingException e) { throw new MessagingException("快速回复异常:" + e.getMessage()); } catch (Exception e) { throw e; } } /** * 收件箱返回的信息进行封装处理 * * @param messages * @return * @throws MessagingException * @throws IOException */ @Override public void setMailContent(Message[] messages, T482102Entity email, FoundationEntity foundation) throws Exception { try { List t482101HEntityList = new ArrayList<>(); List messageIdList = mailIfc.getMessageIdList(email.getReceiveEmail());//存在系统表里的邮件 Message m = null; LocalDate startTime = LocalDate.parse(email.getCreateTime().split(" ")[0]);//创建时间 LocalDate endTime = LocalDate.parse(email.getUpdateTime().split(" ")[0]);//更新时间 if (startTime.equals(endTime)) { startTime = endTime.minusDays(30); } else { startTime = endTime; endTime = LocalDate.now(); } SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date nowTime = new Date(); for (int i = 0; i < messages.length; i++) { m = messages[i]; Date deliveryTime = m.getReceivedDate();//收件时间 Date senderTime = m.getSentDate();//发件时间 if (deliveryTime == null) { continue; } if (senderTime == null) { senderTime = senderTime; } LocalDate sendDate = deliveryTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); if ((sendDate.isAfter(startTime) || sendDate.isEqual(startTime)) && (sendDate.isBefore(endTime) || sendDate.isEqual(endTime))) {//时间段获取邮件 t482101HEntity mail = new t482101HEntity(); String messageId = m.getHeader("Message-ID")[0]; if (messageIdList != null && messageIdList.contains(messageId)) {//存在就不组装 continue; } mail.setSenderTime(sdf.format(senderTime));//发件时间 mail.setReceivingTime(sdf.format(deliveryTime));//收件时间 mail.setMessageId(messageId);//获取邮件唯一ID mail.setMailType(1);//收件 if (m.isSet(Flags.Flag.SEEN)) {//邮件已标记为已读 mail.setReadFlag(1);//已读 } if (m.isExpunged()) {//检查一个消息是否已被删除。‌ mail.setDeleteFlag(1);//已删除 } if (m.isSet(Flags.Flag.ANSWERED)) {//邮件是否已回复 } if (m.isSet(Flags.Flag.DRAFT)) {//是否是草稿箱 mail.setMailType(0);//是草稿箱 } mail.setUserCode(foundation.getUserCode()); mail.setUserName(foundation.getUserName()); mail.setCompanyId(foundation.getCompanyId()); mail.setCompanyName(foundation.getCompanyName()); mail.setClassType(1); mail.setSubject(m.getSubject());//标题 Date date = m.getReceivedDate();//时间 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); mail.setReceiveTime(formatter.format(date)); String result = ""; StringBuilder plainText = new StringBuilder();//纯文本 if (m.isMimeType("text/plain")) { plainText.append(m.getContent()); } else if (m.isMimeType("text/html")) {//html格式 result = m.getContent().toString(); } else if (m.isMimeType("multipart/*")) { MailFileEntity mailFile = new MailFileEntity();//附件 List part = new ArrayList<>(); String unId = UUID.randomUUID().toString().toUpperCase(); StringBuilder attachment = new StringBuilder(); result = getTextFromMimeMultipart((MimeMultipart) m.getContent(), plainText, part, unId, attachment, foundation.getDbId()); mailFile.setPart(part); mailFile.setUnId(unId);//生成uuid mail.setMailFile(mailFile);//附件添加到里面 if (StringUtils.isNotBlank(attachment)) {//附件游标保存 mail.setAttachFlag(1); mail.setAttachmentList(unId + attachment.toString()); } } else { result = m.getContent().toString(); } mail.setContent(result);//保存内容 mail.setPlainText(plainText.toString().trim());//明文 String from = MimeUtility.decodeText(m.getFrom()[0].toString()); InternetAddress internetAddress = new InternetAddress(from); mail.setSenderName(internetAddress.getPersonal());//发件人名称 mail.setSender(internetAddress.getAddress());//发件人 from = MimeUtility.decodeText(m.getRecipients(Message.RecipientType.TO)[0].toString()); internetAddress = new InternetAddress(from); // mail.setReceiver(internetAddress.getAddress());//收件人 List receivers = new ArrayList<>();//抄送人 receivers.add(email.getReceiveEmail()); mail.setReceiver(receivers);//统一成一个收件人 Address[] ccAddress = m.getRecipients(Message.RecipientType.CC); if (ccAddress != null && ccAddress.length > 0) { List cc = new ArrayList<>();//抄送人 for (Address c : ccAddress) { from = MimeUtility.decodeText(c.toString()); internetAddress = new InternetAddress(from); cc.add(internetAddress.getAddress()); } mail.setCc(cc); } Address[] bccAddress = m.getRecipients(Message.RecipientType.BCC); if (bccAddress != null && bccAddress.length > 0) { List bcc = new ArrayList<>();//密送 for (Address c : bccAddress) { from = MimeUtility.decodeText(c.toString()); internetAddress = new InternetAddress(from); bcc.add(internetAddress.getAddress()); } mail.setBcc(bcc);//密送人 } t482101HEntityList.add(mail); } } if (t482101HEntityList.size() > 0) { String docCodeList = mailIfc.saveReceivingMailList(t482101HEntityList);//保存 mailAccountIfc.updateEmailTime(email.getAccountId());//更新一次配置 //发送通知(极光和webscoket) //取用户的手机号 BaseService baseService = (BaseService) FactoryBean.getBean("BaseService"); String tel = baseService.getJdbcTemplate().queryForObject("select tel from _sys_LoginUser where usercode=" + GridUtils.prossSqlParm(foundation.getUserCode()), String.class); MailPush.pushEmailInfo(t482101HEntityList, docCodeList, foundation.getDbId(), tel); } } catch (Exception e) { throw e; } } /** * @param mimeMultipart 邮箱对象 * @param plainText 纯文本 * @param part 邮件附件集合 * @return * @throws Exception */ // 辅助方法,用于递归获取纯文本邮件内容 private String getTextFromMimeMultipart(MimeMultipart mimeMultipart, StringBuilder plainText, List part, String unId, StringBuilder attachment, Integer dbId) throws Exception { int count = mimeMultipart.getCount(); if (count == 0) { throw new MessagingException("Multipart with no body parts"); } boolean multipartAlternative = isMultipartAlternative(mimeMultipart); StringBuilder result = new StringBuilder(); if (multipartAlternative) { for (int i = 0; i < count; i++) { BodyPart bodyPart = mimeMultipart.getBodyPart(i); if (bodyPart.isMimeType("text/plain")) {//这个是获取纯文本 plainText.append(bodyPart.getContent()); } if (bodyPart.isMimeType("text/html")) {//这个是获取html格式 result.append(bodyPart.getContent()); } } if (StringUtils.isBlank(result.toString())) {//没html时候把纯文本赋值过去 result.append(plainText); } } // else { for (int i = 0; i < count; i++) { BodyPart bodyPart = mimeMultipart.getBodyPart(i); // if (bodyPart.isMimeType("text/html")) {//这个是获取html格式 // result.append(bodyPart.getContent()); // }else if (bodyPart.isMimeType("image/*")) {//图片 MailFileEntity.MailBodyPart p = new MailFileEntity.MailBodyPart(); String fileName = "xxx.jpg"; if (StringUtils.isNotBlank(bodyPart.getFileName())) { fileName = MimeUtility.decodeText(bodyPart.getFileName()); } p.setFileName(fileName);//有些邮件没有扩展名 String cId = ((IMAPBodyPart) bodyPart).getContentID();//获取cId if (StringUtils.isNotBlank(cId)) {//在有扩展名时候 if (cId.lastIndexOf(".") != -1) { p.setFileType(cId.substring(cId.lastIndexOf(".") + 1)); p.setFileName(cId);//有些邮件没有扩展名 } } if (StringUtils.isBlank(p.getFileType())) { if (fileName.lastIndexOf(".") != -1) { p.setFileType(fileName.substring(fileName.lastIndexOf(".") + 1)); } } p.setFileSize(bodyPart.getSize()); p.setByteFile(convertInputStreamToByteArray(bodyPart.getInputStream())); String fieldId = UUID.randomUUID().toString();//系统自定义一个随机字段 p.setFieldId(fieldId); String nextResult = result.toString(); if (nextResult.contains(cId)) {//有嵌套内容 //替换 nextResult = nextResult.replace("cid:" + cId + "", shoppingImageServer + "/uploads/email/" + dbId + "/482101/" + unId + "@p@" + p.getPhysicalFile()); result.setLength(0);//清空先 result.append(nextResult); } part.add(p); } else if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) {//附件 MailFileEntity.MailBodyPart p = new MailFileEntity.MailBodyPart(); String fileName = ""; if (StringUtils.isNotBlank(bodyPart.getFileName())) { fileName = MimeUtility.decodeText(bodyPart.getFileName()); } p.setFileName(fileName); if (StringUtils.isNotBlank(fileName)) { p.setFileType(fileName.substring(fileName.lastIndexOf(".") + 1)); } p.setFileSize(bodyPart.getSize()); p.setByteFile(convertInputStreamToByteArray(bodyPart.getInputStream())); String fieldId = UUID.randomUUID().toString();//系统自定义一个随机字段 p.setFieldId(fieldId); attachment.append(";" + fieldId); part.add(p); } else if (bodyPart.isMimeType("multipart/*")) { result.append(getTextFromMimeMultipart((MimeMultipart) bodyPart.getContent(), plainText, part, unId, attachment, dbId)); } } // } return result.toString(); } /** * 辅助方法,判断是否为multipart/alternative类型的邮件 * * @param mimeMultipart * @return * @throws Exception */ private boolean isMultipartAlternative(MimeMultipart mimeMultipart) throws Exception { boolean textPlainFound = false; boolean textHtmlFound = false; int count = mimeMultipart.getCount(); for (int i = 0; i < count; i++) { BodyPart bodyPart = mimeMultipart.getBodyPart(i); if (bodyPart.isMimeType("text/plain")) { textPlainFound = true; } else if (bodyPart.isMimeType("text/html")) { textHtmlFound = true; } } return textPlainFound || textHtmlFound; } /** * 转换 byte * * @param inputStream * @return * @throws IOException */ private byte[] convertInputStreamToByteArray(InputStream inputStream) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) != -1) { byteArrayOutputStream.write(buffer, 0, length); } return byteArrayOutputStream.toByteArray(); } }