xinyb
2024-09-14 f6ae0b6568c8000e9bfb9ce1d13400525a223d20
提交 | 用户 | age
7caeae 1 package com.yc.crm.mail.service;
X 2
3 import com.sun.mail.imap.IMAPBodyPart;
4 import com.sun.mail.imap.IMAPStore;
5 import com.yc.crm.mail.entity.FoundationEntity;
6 import com.yc.crm.mail.entity.MailFileEntity;
7 import com.yc.crm.mail.entity.T482102Entity;
8 import com.yc.crm.mail.entity.t482101HEntity;
9 import com.yc.entity.attachment.AttachmentEntity;
10 import com.yc.service.BaseService;
11 import org.apache.commons.io.FileUtils;
12 import org.apache.commons.lang3.StringUtils;
13 import org.springframework.beans.factory.annotation.Autowired;
14 import org.springframework.stereotype.Service;
15
16 import javax.mail.*;
17 import javax.mail.internet.*;
18 import javax.servlet.http.HttpServletRequest;
19 import java.io.*;
20 import java.text.SimpleDateFormat;
7cf738 21 import java.time.LocalDate;
X 22 import java.time.ZoneId;
7caeae 23 import java.util.*;
X 24
25 import static com.yc.crm.mail.service.MailImpl.shoppingImageServer;
26
27 /**
28  * @BelongsProject: eCoWorksV3
29  * @BelongsPackage: com.yc.crm.mail.service
30  * @author: xinyb
31  * @CreateTime: 2024-09-12  10:30
32  * @Description:
33  */
34 @Service
35 public class MailServiceImpl extends BaseService implements MailServiceIfc {
36
37     @Autowired
38     MailIfc mailIfc;
39     @Autowired
40     MailAccountIfc mailAccountIfc;
41
42     @Override
43     public void receivingEmails(T482102Entity emailEntity, FoundationEntity foundation) throws MessagingException {
44         String imapServer = emailEntity.getReceiveHost();//"imap.qq.com";
45         String user = emailEntity.getReceiveEmail();//"xxx@qq.com";
46         String pwd = emailEntity.getReceivePassword();//"xxxx";
47
48         Properties properties = new Properties();
49         properties.put("mail.store.protocol", "imaps");//emailEntity.getReceiveProtocol()); // IMAP over SSL
50         properties.put("mail.imaps.host", emailEntity.getReceiveHost());
51         properties.put("mail.imaps.port", emailEntity.getReceivePort());
52         properties.put("mail.imaps.starttls.enable", "true");//// IMAP 协议设置 STARTTLS
53
54         HashMap IAM = new HashMap();
55         //带上IMAP ID信息,由key和value组成,例如name,version,vendor,support-email等。
56         IAM.put("name", emailEntity.getReceiveEmail());
57         IAM.put("version", emailEntity.getDocVersion() + "");
58         IAM.put("vendor", emailEntity.getCompanyName());
59         IAM.put("support-email", emailEntity.getEmail());
60         //创建会话
61         Session session = Session.getInstance(properties, new Authenticator() {
62             @Override
63             protected PasswordAuthentication getPasswordAuthentication() {
64                 return new PasswordAuthentication(user, pwd);
65             }
66         });
67         //存储对象
68         IMAPStore store = (IMAPStore) session.getStore(emailEntity.getReceiveProtocol());//imap协议或pop3协议类型(推荐你使用IMAP协议来存取服务器上的邮件。)
69         //连接
70         store.connect(imapServer, user, pwd);
71         store.id(IAM);//163邮箱需要,不然会报:A3 NO SELECT Unsafe Login. Please contact kefu@188.com for help
72         Folder folder = null;
73         try {
74             // 获得收件箱
75             folder = store.getFolder("INBOX");
76             // 以读写模式打开收件箱
77             folder.open(Folder.READ_WRITE);
7cf738 78
X 79             //false 表示未读 ,true已读,获得收件箱的邮件列表
7caeae 80 //            FlagTerm flagTerm = new FlagTerm(new Flags(Flags.Flag.SEEN), true);
X 81 //            Message[] messages = folder.search(flagTerm);
7cf738 82
7caeae 83             //获取收件箱邮件(全部)
X 84             Message[] messages = folder.getMessages();
7cf738 85
X 86             //根据时间
87 //            SimpleDateFormat format=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");//
88 //            SearchTerm sinceTerm=new FromStringTerm(emailEntity.getCreateTime());//开始时间
89 //            SearchTerm beforeTerm=new FromStringTerm(format.format(new Date()));//结束时间
90 //            Message[] messages = folder.search(new AndTerm(sinceTerm,beforeTerm));
91
7caeae 92             //邮箱封装保存
7cf738 93             setMailContent(messages, emailEntity, foundation);
7caeae 94         } catch (NoSuchProviderException e) {
X 95             throw e;
96         } catch (MessagingException e) {
97             throw e;
98         } catch (IOException e) {
99             throw new RuntimeException(e);
100         } catch (Exception e) {
101             throw new RuntimeException(e);
102         } finally {
103             try {
104                 if (folder != null) {
105                     folder.close(false);
106                 }
107                 if (store != null) {
108                     store.close();
109                 }
110             } catch (MessagingException e) {
111                 throw e;
112             }
113         }
114     }
115
116
117     @Override
118     public void sendEmails(t482101HEntity t482101H, HttpServletRequest request) throws Exception {
119         try {
120             //根据当前用户查询绑定的邮箱信息
121             T482102Entity emailEntity = mailAccountIfc.getAccountInfo(t482101H.getUserCode(), t482101H.getSender());//返回邮箱的账号信息
122             if (emailEntity == null || StringUtils.isBlank(emailEntity.getSmtpEmail())) {
123                 if (StringUtils.isBlank(t482101H.getDocCode())) {
124                     t482101H.setMailType(0);//草稿箱状态
125                     t482101H = mailIfc.saveReceivingMail(t482101H);//保存到草稿箱内
126                 }
f6ae0b 127                 throw new MessagingException("找不到邮箱:" + t482101H.getSender() + "配置信息请完善。邮件已保存到草稿箱#" + t482101H.getDocCode());
7caeae 128             }
X 129             //有发送的邮件保存到后台数据库
130             //邮箱服务器配置
131             Properties properties = new Properties();
132             properties.setProperty("mail.smtp.host", emailEntity.getSmtpHost());
133             properties.setProperty("mail.smtp.port", emailEntity.getSmtpPort() + "");
134             properties.setProperty("mail.smtp.auth", "true");// // 设置SMTP是否需要认证
135             properties.put("mail.smtp.ssl.enable", emailEntity.isSmtpSSL() + "");// // 设置启用SSL加密
136             properties.setProperty("mail.smtp.starttls.enable", "true");//// SMTP 协议设置 STARTTLS  开启tls
137
138             //
139             String sendEmail = emailEntity.getSmtpEmail();//发件人
140             String sendPassword = emailEntity.getSmtpPassword();//密码
141             String recipientEmail = StringUtils.join(t482101H.getReceiver(), ",");//收件人
142             Session session = Session.getInstance(properties, new Authenticator() {
143                 @Override
144                 protected PasswordAuthentication getPasswordAuthentication() {
145                     return new PasswordAuthentication(sendEmail, sendPassword);
146                 }
147             });
148
149             MimeMessage message = new MimeMessage(session);
150             message.setFrom(new InternetAddress(sendEmail));
151             message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail));
152             message.setSubject(t482101H.getSubject());
153
154             String Unique_ID = "<onBus_" + UUID.randomUUID().toString().toUpperCase() + "@mail.com>";//系统单号唯一码
155             message.setHeader("Message-ID", Unique_ID);//系统内部唯一码
156             t482101H.setMessageId(Unique_ID);//messageId赋值
157
158             if (t482101H.getCc() != null && t482101H.getCc().size() > 0) {//抄送
159                 message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(StringUtils.join(t482101H.getCc(), ",")));
160             }
161             if (t482101H.getBcc() != null && t482101H.getBcc().size() > 0) {//密送
162                 message.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(StringUtils.join(t482101H.getBcc(), ",")));
163             }
164
165             //创建多部分消息
166             Multipart multipart = new MimeMultipart();
167
168             MimeBodyPart textPart = new MimeBodyPart();
169             textPart.setText(t482101H.getContent());//内容
170             multipart.addBodyPart(textPart);
171
172             //下面附件内容
173             if (StringUtils.isNotBlank(t482101H.getAttachmentList())) {//有附件内容
174                 //获取到附件内容
175                 List<AttachmentEntity> attachmentEntities = mailIfc.getAttachmentEntityList(t482101H.getAttachmentList());
176                 if (attachmentEntities != null && attachmentEntities.size() > 0) {
177                     for (AttachmentEntity a : attachmentEntities) {
178                         InputStream inputStream = new ByteArrayInputStream(a.getOriginalPicture());
179                         File file = new File(a.getOriginalFileName());
180                         FileUtils.copyInputStreamToFile(inputStream, file);
181                         MimeBodyPart bodyPart = new MimeBodyPart();
182                         bodyPart.attachFile(file);
183                         bodyPart.setFileName(a.getOriginalFileName());
184                         multipart.addBodyPart(bodyPart);
185                     }
186                 }
187             }
188             message.setContent(multipart);
189             try {
190                 if (StringUtils.isBlank(t482101H.getDocCode())) {//不在草稿箱有单号
191                     mailIfc.saveReceivingMail(t482101H);//保存后发送
192                 } else {
193                     t482101H.setMailType(2);//发件箱状态
194                     mailIfc.updateMailDrafts(t482101H);//更新成发件箱
195                 }
196                 Transport.send(message);//发送
197             } catch (MessagingException m) {//发送异常处理
198                 t482101H.setMailType(0);//草稿箱状态
199                 mailIfc.updateMailDrafts(t482101H);//更新成草稿箱
f6ae0b 200                 throw new MessagingException("发送邮件异常,邮件已保存在草稿箱。异常原因:" + m.getMessage()+"#"+t482101H.getDocCode());
7caeae 201             }
X 202         } catch (Exception e) {
203             throw e;
204         }
205     }
206
207     /**
208      * 收件箱返回的信息进行封装处理
209      *
210      * @param messages
211      * @return
212      * @throws MessagingException
213      * @throws IOException
214      */
7cf738 215     public void setMailContent(Message[] messages, T482102Entity email, FoundationEntity foundation) throws Exception {
7caeae 216         try {
X 217             List<t482101HEntity> t482101HEntityList = new ArrayList<>();
7cf738 218             List<String> messageIdList = mailIfc.getMessageIdList(email.getReceiveEmail());//存在系统表里的邮件
7caeae 219             Message m = null;
7cf738 220             LocalDate startTime = LocalDate.parse(email.getCreateTime().split(" ")[0]);//创建时间
X 221             LocalDate endTime = LocalDate.parse(email.getUpdateTime().split(" ")[0]);//更新时间
222             if (startTime.equals(endTime)) {
223                 startTime = endTime.minusDays(30);
224             } else {
225                 startTime = endTime;
226                 endTime = LocalDate.now();
227             }
228             Date nowTime = new Date();
7caeae 229             for (int i = 0; i < messages.length; i++) {
X 230                 m = messages[i];
7cf738 231                 LocalDate sendDate = m.getSentDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
X 232                 if ((sendDate.isAfter(startTime) || sendDate.isEqual(startTime)) &&
233                         (sendDate.isBefore(endTime) || sendDate.isEqual(endTime))) {//时间段获取邮件
234                     t482101HEntity mail = new t482101HEntity();
235                     String messageId = m.getHeader("Message-ID")[0];
236                     if (messageIdList != null && messageIdList.contains(messageId)) {//存在就不组装
237                         continue;
7caeae 238                     }
7cf738 239                     mail.setMessageId(messageId);//获取邮件唯一ID
X 240                     mail.setMailType(1);//收件
241                     if (m.isSet(Flags.Flag.SEEN)) {//邮件已标记为已读
242                         mail.setReadFlag(1);//已读
243                     }
244                     if (m.isExpunged()) {//检查一个消息是否已被删除。‌
245                         mail.setDeleteFlag(1);//已删除
246                     }
247                     if (m.isSet(Flags.Flag.ANSWERED)) {//邮件是否已回复
248
249                     }
250                     if (m.isSet(Flags.Flag.DRAFT)) {//是否是草稿箱
251                         mail.setMailType(0);//是草稿箱
252                     }
253                     mail.setUserCode(foundation.getUserCode());
254                     mail.setUserName(foundation.getUserName());
255                     mail.setCompanyId(foundation.getCompanyId());
256                     mail.setCompanyName(foundation.getCompanyName());
257                     mail.setClassType(1);
258                     mail.setSubject(m.getSubject());//标题
259                     Date date = m.getReceivedDate();//时间
260                     SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
261                     mail.setReceiveTime(formatter.format(date));
262                     String result = "";
263                     StringBuilder plainText = new StringBuilder();//纯文本
264                     if (m.isMimeType("text/plain")) {
265                         plainText.append(m.getContent());
266                     } else if (m.isMimeType("text/html")) {//html格式
267                         result = m.getContent().toString();
268                     } else if (m.isMimeType("multipart/*")) {
269                         MailFileEntity mailFile = new MailFileEntity();//附件
270                         List<MailFileEntity.MailBodyPart> part = new ArrayList<>();
271                         String unId = UUID.randomUUID().toString().toUpperCase();
272                         StringBuilder attachment = new StringBuilder();
273                         result = getTextFromMimeMultipart((MimeMultipart) m.getContent(), plainText, part, unId, attachment);
274                         mailFile.setPart(part);
275                         mailFile.setUnId(unId);//生成uuid
276                         mail.setMailFile(mailFile);//附件添加到里面
277                         if (StringUtils.isNotBlank(attachment)) {//附件游标保存
278                             mail.setAttachFlag(1);
279                             mail.setAttachmentList(unId + attachment.toString());
280                         }
281                     } else {
282                         result = m.getContent().toString();
283                     }
284                     mail.setContent(result);//保存内容
285                     mail.setPlainText(plainText.toString().trim());//明文
286                     String from = MimeUtility.decodeText(m.getFrom()[0].toString());
287                     InternetAddress internetAddress = new InternetAddress(from);
288                     mail.setSender(internetAddress.getAddress());//发件人
289                     from = MimeUtility.decodeText(m.getRecipients(Message.RecipientType.TO)[0].toString());
290                     internetAddress = new InternetAddress(from);
7caeae 291 //                mail.setReceiver(internetAddress.getAddress());//收件人
7cf738 292                     List<String> receivers = new ArrayList<>();//抄送人
X 293                     receivers.add(email.getReceiveEmail());
294                     mail.setReceiver(receivers);//统一成一个收件人
7caeae 295
7cf738 296                     Address[] ccAddress = m.getRecipients(Message.RecipientType.CC);
X 297                     if (ccAddress != null && ccAddress.length > 0) {
298                         List<String> cc = new ArrayList<>();//抄送人
299                         for (Address c : ccAddress) {
300                             from = MimeUtility.decodeText(c.toString());
301                             internetAddress = new InternetAddress(from);
302                             cc.add(internetAddress.getAddress());
303                         }
304                         mail.setCc(cc);
7caeae 305                     }
7cf738 306                     Address[] bccAddress = m.getRecipients(Message.RecipientType.BCC);
X 307                     if (bccAddress != null && bccAddress.length > 0) {
308                         List<String> bcc = new ArrayList<>();//密送
309                         for (Address c : bccAddress) {
310                             from = MimeUtility.decodeText(c.toString());
311                             internetAddress = new InternetAddress(from);
312                             bcc.add(internetAddress.getAddress());
313                         }
314                         mail.setBcc(bcc);//密送人
7caeae 315                     }
7cf738 316                     t482101HEntityList.add(mail);
7caeae 317                 }
X 318             }
319             if (t482101HEntityList.size() > 0) {
7cf738 320                 mailAccountIfc.updateEmailTime(email.getAccountId());//更新一次配置
7caeae 321                 mailIfc.saveReceivingMailList(t482101HEntityList);//保存
X 322             }
323         } catch (Exception e) {
324             throw e;
325         }
326     }
327
328     /**
329      * @param mimeMultipart 邮箱对象
330      * @param plainText     纯文本
331      * @param part          邮件附件集合
332      * @return
333      * @throws Exception
334      */
335     // 辅助方法,用于递归获取纯文本邮件内容
336     private String getTextFromMimeMultipart(MimeMultipart mimeMultipart, StringBuilder plainText, List<MailFileEntity.MailBodyPart> part, String unId, StringBuilder attachment) throws Exception {
337         int count = mimeMultipart.getCount();
338         if (count == 0) {
339             throw new MessagingException("Multipart with no body parts");
340         }
341         boolean multipartAlternative = isMultipartAlternative(mimeMultipart);
342         StringBuilder result = new StringBuilder();
343         if (multipartAlternative) {
344             for (int i = 0; i < count; i++) {
345                 BodyPart bodyPart = mimeMultipart.getBodyPart(i);
346                 if (bodyPart.isMimeType("text/plain")) {//这个是获取纯文本
347                     plainText.append(bodyPart.getContent());
348                 }
349                 if (bodyPart.isMimeType("text/html")) {//这个是获取html格式
350                     result.append(bodyPart.getContent());
351                 }
352             }
353         } else {
354             for (int i = 0; i < count; i++) {
355                 BodyPart bodyPart = mimeMultipart.getBodyPart(i);
356                 if (bodyPart.isMimeType("image/*")) {//图片
357                     MailFileEntity.MailBodyPart p = new MailFileEntity.MailBodyPart();
7cf738 358                     String fileName = MimeUtility.decodeText(bodyPart.getFileName());
X 359                     p.setFileName(fileName);//有些邮件没有扩展名
7caeae 360                     String cId = ((IMAPBodyPart) bodyPart).getContentID();//获取cId
7cf738 361                     if (StringUtils.isNotBlank(cId)) {//在有扩展名时候
X 362                         if (cId.lastIndexOf(".") != -1) {
363                             p.setFileType(cId.substring(cId.lastIndexOf(".") + 1));
364                             p.setFileName(cId);//有些邮件没有扩展名
365                         }
366                     }
367                     if (StringUtils.isBlank(p.getFileType()) && StringUtils.isNotBlank(fileName)) {
368                         if (fileName.lastIndexOf(".") != -1) {
369                             p.setFileType(fileName.substring(fileName.lastIndexOf(".") + 1));
370                         }
371                     }
7caeae 372                     p.setFileSize(bodyPart.getSize());
7cf738 373                     p.setByteFile(convertInputStreamToByteArray(bodyPart.getInputStream()));
X 374                     String fieldId = UUID.randomUUID().toString();//系统自定义一个随机字段
375                     p.setFieldId(fieldId);
7caeae 376                     String nextResult = result.toString();
X 377                     if (nextResult.contains(cId)) {//有嵌套内容
378                         //替换
7cf738 379                         nextResult = nextResult.replace("cid:" + cId + "", shoppingImageServer + "/uploads/attachment/82/482101/" + unId + "@p@" + p.getPhysicalFile());
7caeae 380                         result.setLength(0);//清空先
X 381                         result.append(nextResult);
382                     }
7cf738 383                     part.add(p);
7caeae 384                 } else if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) {//附件
X 385                     MailFileEntity.MailBodyPart p = new MailFileEntity.MailBodyPart();
7cf738 386                     String fileName = MimeUtility.decodeText(bodyPart.getFileName());
X 387                     p.setFileName(fileName);
388                     if (StringUtils.isNotBlank(fileName)) {
389                         p.setFileType(fileName.substring(fileName.lastIndexOf(".") + 1));
390                     }
7caeae 391                     p.setFileSize(bodyPart.getSize());
7cf738 392                     p.setByteFile(convertInputStreamToByteArray(bodyPart.getInputStream()));
X 393                     String fieldId = UUID.randomUUID().toString();//系统自定义一个随机字段
394                     p.setFieldId(fieldId);
395                     attachment.append(";" + fieldId);
7caeae 396                     part.add(p);
X 397                 } else if (bodyPart.isMimeType("multipart/*")) {
398                     result.append(getTextFromMimeMultipart((MimeMultipart) bodyPart.getContent(), plainText, part, unId, attachment));
399                 }
400             }
401         }
402         return result.toString();
403     }
404
405     /**
406      * 辅助方法,判断是否为multipart/alternative类型的邮件
407      *
408      * @param mimeMultipart
409      * @return
410      * @throws Exception
411      */
412     private boolean isMultipartAlternative(MimeMultipart mimeMultipart) throws Exception {
413         boolean textPlainFound = false;
414         boolean textHtmlFound = false;
415         int count = mimeMultipart.getCount();
416         for (int i = 0; i < count; i++) {
417             BodyPart bodyPart = mimeMultipart.getBodyPart(i);
418             if (bodyPart.isMimeType("text/plain")) {
419                 textPlainFound = true;
420             } else if (bodyPart.isMimeType("text/html")) {
421                 textHtmlFound = true;
422             }
423         }
424         return textPlainFound && textHtmlFound;
425     }
426
427     /**
428      * 转换 byte
429      *
430      * @param inputStream
431      * @return
432      * @throws IOException
433      */
434     private byte[] convertInputStreamToByteArray(InputStream inputStream) throws IOException {
435         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
436         byte[] buffer = new byte[1024];
437         int length;
438         while ((length = inputStream.read(buffer)) != -1) {
439             byteArrayOutputStream.write(buffer, 0, length);
440         }
441         return byteArrayOutputStream.toByteArray();
442     }
443 }