|
|
@@ -0,0 +1,513 @@
|
|
|
+package com.storlead.sales.mail.mkt.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
+import com.storlead.framework.common.constant.CommonConstant;
|
|
|
+import com.storlead.framework.common.util.DateUtil;
|
|
|
+import com.storlead.framework.common.util.DateUtils;
|
|
|
+import com.storlead.framework.common.util.RandomGenerateHelper;
|
|
|
+import com.storlead.sales.mail.common.connection.MailConnection;
|
|
|
+import com.storlead.sales.mail.common.connection.client.MailConnectionUtil;
|
|
|
+import com.storlead.sales.mail.common.connection.config.MailProperties;
|
|
|
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
|
|
|
+import com.storlead.sales.mail.common.properties.MailFileProperties;
|
|
|
+import com.storlead.sales.mail.common.util.MailReceiveQueueThreadPool;
|
|
|
+import com.storlead.sales.mail.mkt.entity.MktMailAttachmentEntity;
|
|
|
+import com.storlead.sales.mail.mkt.entity.MktMailMessageEntity;
|
|
|
+import com.storlead.sales.mail.mkt.enums.MktMailFolderEnum;
|
|
|
+import com.storlead.sales.mail.mkt.service.MktMailAttachmentService;
|
|
|
+import com.storlead.sales.mail.mkt.service.MktMailMessageService;
|
|
|
+import com.storlead.sales.mail.mkt.service.MktMailReceiveService;
|
|
|
+import com.sun.mail.imap.IMAPFolder;
|
|
|
+import com.sun.mail.pop3.POP3Folder;
|
|
|
+import lombok.extern.log4j.Log4j2;
|
|
|
+import org.apache.commons.io.FilenameUtils;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import javax.mail.Address;
|
|
|
+import javax.mail.BodyPart;
|
|
|
+import javax.mail.Flags;
|
|
|
+import javax.mail.Folder;
|
|
|
+import javax.mail.Message;
|
|
|
+import javax.mail.Multipart;
|
|
|
+import javax.mail.Part;
|
|
|
+import javax.mail.internet.InternetAddress;
|
|
|
+import javax.mail.internet.MimeUtility;
|
|
|
+import javax.mail.search.ComparisonTerm;
|
|
|
+import javax.mail.search.ReceivedDateTerm;
|
|
|
+import javax.mail.search.SearchTerm;
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileOutputStream;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 营销收信:对齐 CRM receiveEmails,落 mkt_mail_message(folder 区分),并绑定 reply_msg_id。
|
|
|
+ */
|
|
|
+@Log4j2
|
|
|
+@Service
|
|
|
+public class MktMailReceiveServiceImpl implements MktMailReceiveService {
|
|
|
+
|
|
|
+ private static final int STATUS_RECEIVED = 1;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private MktMailMessageService mktMailMessageService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private MktMailAttachmentService mktMailAttachmentService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private MailFileProperties mailFileProperties;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void receiveEmails(SmtpPopSettingsEntity account) {
|
|
|
+ if (account == null || account.getId() == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (account.getEnableReceive() != null && !Integer.valueOf(1).equals(account.getEnableReceive())) {
|
|
|
+ log.warn("mkt receive skipped, enable_receive!=1, accountId={}", account.getId());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String taskKey = "mkt_" + account.getEmailAddress() + "_" + account.getId();
|
|
|
+ MailReceiveQueueThreadPool pool = MailReceiveQueueThreadPool.getInstance();
|
|
|
+ if (Boolean.TRUE.equals(pool.getTaskInProgressByMail(taskKey))) {
|
|
|
+ log.warn("mkt receive already running: {}", taskKey);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ pool.addTask(taskKey, () -> {
|
|
|
+ try {
|
|
|
+ receiveHeadEmails(account);
|
|
|
+ loadMailContents(account);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("mkt receiveEmails error, accountId={}", account.getId(), e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void receiveHeadEmails(SmtpPopSettingsEntity account) {
|
|
|
+ pullFolder(account, "INBOX", MktMailFolderEnum.INBOX);
|
|
|
+ pullFolder(account, "Sent Items", MktMailFolderEnum.SENT);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void pullFolder(SmtpPopSettingsEntity account, String serverFolder, MktMailFolderEnum folderEnum) {
|
|
|
+ try {
|
|
|
+ List<Message> messages = searchMessages(account, serverFolder, folderEnum);
|
|
|
+ if (CollectionUtils.isEmpty(messages)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<String> recentIds = listRecentMessageIds(account.getId(), folderEnum.code);
|
|
|
+ for (Message message : messages) {
|
|
|
+ try {
|
|
|
+ String[] headers = message.getHeader("Message-ID");
|
|
|
+ if (headers == null || headers.length == 0 || !StringUtils.hasText(headers[0])) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String messageId = normalizeMessageId(headers[0]);
|
|
|
+ if (recentIds.contains(messageId) || existsByMessageId(account.getId(), messageId)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ MktMailMessageEntity entity = convertMessage(message, folderEnum);
|
|
|
+ if (entity == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ entity.setMessageId(messageId);
|
|
|
+ entity.setAccountId(account.getId());
|
|
|
+ entity.setOrgId(account.getOrgId());
|
|
|
+ entity.setOwnerBy(account.getOwnerBy());
|
|
|
+ entity.setCreateBy(account.getOwnerBy());
|
|
|
+ entity.setStatus(STATUS_RECEIVED);
|
|
|
+ entity.setIsDelete(CommonConstant.DEL_FLAG_0);
|
|
|
+ entity.setEnabled(Boolean.TRUE);
|
|
|
+ entity.setIsTrack(0);
|
|
|
+ entity.setOpened(0);
|
|
|
+ entity.setOpenCount(0);
|
|
|
+ fillMsgUid(message, account, entity);
|
|
|
+ bindReply(account.getId(), message, entity);
|
|
|
+
|
|
|
+ if (mktMailMessageService.save(entity)) {
|
|
|
+ recentIds.add(messageId);
|
|
|
+ }
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("mkt pull one mail error, accountId={}", account.getId(), ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("mkt pullFolder error, folder={}, accountId={}", serverFolder, account.getId(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<Message> searchMessages(SmtpPopSettingsEntity account, String folderName, MktMailFolderEnum folderEnum) {
|
|
|
+ try {
|
|
|
+ QueryWrapper<MktMailMessageEntity> qw = new QueryWrapper<>();
|
|
|
+ qw.eq("account_id", account.getId());
|
|
|
+ qw.eq("folder", folderEnum.code);
|
|
|
+ qw.select("max(recipient_date) as recipient_date");
|
|
|
+ MktMailMessageEntity latest = mktMailMessageService.getOne(qw);
|
|
|
+
|
|
|
+ MailProperties properties = new MailProperties(account);
|
|
|
+ MailConnection connection = MailConnectionUtil.receiveEmailsConnection(properties);
|
|
|
+ if (connection == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ Folder inbox = connection.getFolder(folderName);
|
|
|
+ if (inbox == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ inbox.open(Folder.READ_ONLY);
|
|
|
+
|
|
|
+ Date beginDate = latest == null ? null : latest.getRecipientDate();
|
|
|
+ if (beginDate == null) {
|
|
|
+ LocalDate currentDate = LocalDate.now();
|
|
|
+ if (account.getPullDay() == null || Integer.valueOf(0).equals(account.getPullDay())) {
|
|
|
+ beginDate = DateUtil.getDateByFormat(currentDate.minusYears(1).toString(), "yyyy-MM-dd");
|
|
|
+ } else {
|
|
|
+ beginDate = DateUtil.getDateByFormat(currentDate.minusDays(account.getPullDay()).toString(), "yyyy-MM-dd");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ SearchTerm searchTerm = new ReceivedDateTerm(ComparisonTerm.GT, beginDate);
|
|
|
+ Message[] messages = inbox.search(searchTerm);
|
|
|
+ if (messages == null || messages.length == 0) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return Arrays.asList(messages);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("mkt searchMessages error, folder={}", folderName, e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void loadMailContents(SmtpPopSettingsEntity account) {
|
|
|
+ List<MktMailMessageEntity> heads = mktMailMessageService.list(new LambdaQueryWrapper<MktMailMessageEntity>()
|
|
|
+ .eq(MktMailMessageEntity::getAccountId, account.getId())
|
|
|
+ .eq(MktMailMessageEntity::getIsOnlyHead, 1)
|
|
|
+ .eq(MktMailMessageEntity::getIsDelete, CommonConstant.DEL_FLAG_0)
|
|
|
+ .in(MktMailMessageEntity::getFolder, MktMailFolderEnum.INBOX.code, MktMailFolderEnum.SENT.code));
|
|
|
+ if (CollectionUtils.isEmpty(heads)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ MailProperties properties = new MailProperties(account);
|
|
|
+ MailConnection connection = MailConnectionUtil.receiveEmailsConnection(properties);
|
|
|
+ if (connection == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for (MktMailMessageEntity mail : heads) {
|
|
|
+ try {
|
|
|
+ if (!StringUtils.hasText(mail.getMsgUid())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String serverFolder = MktMailFolderEnum.INBOX.code.equals(mail.getFolder()) ? "INBOX" : "Sent Items";
|
|
|
+ Message message = connection.getMessageByUid(mail.getMsgUid(), serverFolder);
|
|
|
+ if (message == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String body = extractBody(message);
|
|
|
+ LambdaUpdateWrapper<MktMailMessageEntity> update = new LambdaUpdateWrapper<>();
|
|
|
+ update.eq(MktMailMessageEntity::getId, mail.getId());
|
|
|
+ update.set(MktMailMessageEntity::getContent, body);
|
|
|
+ update.set(MktMailMessageEntity::getIsOnlyHead, 0);
|
|
|
+ mktMailMessageService.update(update);
|
|
|
+ saveAttachments(mail, message, account);
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("mkt load content error, mailId={}", mail.getId(), ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("mkt loadMailContents error, accountId={}", account.getId(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void bindReply(Long accountId, Message message, MktMailMessageEntity entity) {
|
|
|
+ try {
|
|
|
+ String inReplyTo = firstHeader(message, "In-Reply-To");
|
|
|
+ if (!StringUtils.hasText(inReplyTo)) {
|
|
|
+ String references = firstHeader(message, "References");
|
|
|
+ if (StringUtils.hasText(references)) {
|
|
|
+ String[] parts = references.trim().split("\\s+");
|
|
|
+ inReplyTo = parts[parts.length - 1];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!StringUtils.hasText(inReplyTo)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String normalized = normalizeMessageId(inReplyTo);
|
|
|
+ entity.setInReplyTo(normalized);
|
|
|
+ MktMailMessageEntity parent = findByMessageId(accountId, normalized);
|
|
|
+ if (parent != null) {
|
|
|
+ entity.setReplyMsgId(parent.getId());
|
|
|
+ // 继承业务单号,便于营销侧回查
|
|
|
+ if (!StringUtils.hasText(entity.getBizRef()) && StringUtils.hasText(parent.getBizRef())) {
|
|
|
+ entity.setBizRef(parent.getBizRef());
|
|
|
+ }
|
|
|
+ if (!StringUtils.hasText(entity.getBizBatchNo()) && StringUtils.hasText(parent.getBizBatchNo())) {
|
|
|
+ entity.setBizBatchNo(parent.getBizBatchNo());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("mkt bindReply error", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private MktMailMessageEntity findByMessageId(Long accountId, String messageId) {
|
|
|
+ if (!StringUtils.hasText(messageId)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String normalized = normalizeMessageId(messageId);
|
|
|
+ List<MktMailMessageEntity> list = mktMailMessageService.list(new LambdaQueryWrapper<MktMailMessageEntity>()
|
|
|
+ .eq(MktMailMessageEntity::getAccountId, accountId)
|
|
|
+ .eq(MktMailMessageEntity::getIsDelete, CommonConstant.DEL_FLAG_0)
|
|
|
+ .and(w -> w.eq(MktMailMessageEntity::getMessageId, normalized)
|
|
|
+ .or().eq(MktMailMessageEntity::getMessageId, "<" + stripBrackets(normalized) + ">")
|
|
|
+ .or().eq(MktMailMessageEntity::getMessageId, stripBrackets(normalized)))
|
|
|
+ .orderByDesc(MktMailMessageEntity::getId)
|
|
|
+ .last("limit 1"));
|
|
|
+ return CollectionUtils.isEmpty(list) ? null : list.get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean existsByMessageId(Long accountId, String messageId) {
|
|
|
+ return findByMessageId(accountId, messageId) != null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<String> listRecentMessageIds(Long accountId, String folder) {
|
|
|
+ QueryWrapper<MktMailMessageEntity> qw = new QueryWrapper<>();
|
|
|
+ qw.select("message_id");
|
|
|
+ qw.eq("folder", folder);
|
|
|
+ qw.eq("account_id", accountId);
|
|
|
+ qw.isNotNull("message_id");
|
|
|
+ qw.last("order by recipient_date desc limit 200");
|
|
|
+ List<Object> objs = mktMailMessageService.listObjs(qw);
|
|
|
+ if (CollectionUtils.isEmpty(objs)) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+ return objs.stream().filter(Objects::nonNull).map(o -> normalizeMessageId(String.valueOf(o))).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ private MktMailMessageEntity convertMessage(Message message, MktMailFolderEnum folderEnum) {
|
|
|
+ try {
|
|
|
+ MktMailMessageEntity entity = new MktMailMessageEntity();
|
|
|
+ String subject = message.getSubject() == null ? "" : MimeUtility.decodeText(message.getSubject());
|
|
|
+ entity.setSubject(subject);
|
|
|
+ entity.setFolder(folderEnum.code);
|
|
|
+ entity.setInOutMark(folderEnum == MktMailFolderEnum.INBOX ? 1 : 2);
|
|
|
+
|
|
|
+ Map<String, String> fromMap = decodeAddresses(message.getFrom());
|
|
|
+ entity.setFromAddr(joinKeys(fromMap));
|
|
|
+ entity.setFromName(joinValues(fromMap));
|
|
|
+
|
|
|
+ Map<String, String> toMap = decodeAddresses(message.getRecipients(Message.RecipientType.TO));
|
|
|
+ String recipient = joinKeys(toMap);
|
|
|
+ entity.setRecipient(StringUtils.hasText(recipient) ? recipient : "");
|
|
|
+
|
|
|
+ Map<String, String> ccMap = decodeAddresses(message.getRecipients(Message.RecipientType.CC));
|
|
|
+ entity.setRecipientCc(joinKeys(ccMap));
|
|
|
+
|
|
|
+ entity.setEmailSize((long) Math.max(message.getSize(), 0));
|
|
|
+ if (message.getSentDate() != null) {
|
|
|
+ entity.setSentDate(message.getSentDate());
|
|
|
+ entity.setSentTime(message.getSentDate());
|
|
|
+ }
|
|
|
+ if (message.getReceivedDate() != null) {
|
|
|
+ entity.setRecipientDate(message.getReceivedDate());
|
|
|
+ } else if (message.getSentDate() != null) {
|
|
|
+ entity.setRecipientDate(message.getSentDate());
|
|
|
+ } else {
|
|
|
+ entity.setRecipientDate(new Date());
|
|
|
+ }
|
|
|
+ entity.setIsRead(message.isSet(Flags.Flag.SEEN) ? 1 : 0);
|
|
|
+
|
|
|
+ try {
|
|
|
+ Object content = message.getContent();
|
|
|
+ if (content instanceof String) {
|
|
|
+ entity.setIsOnlyHead(0);
|
|
|
+ entity.setContent(content.toString());
|
|
|
+ } else {
|
|
|
+ entity.setIsOnlyHead(1);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ entity.setIsOnlyHead(1);
|
|
|
+ }
|
|
|
+ return entity;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("mkt convertMessage error", e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void fillMsgUid(Message message, SmtpPopSettingsEntity account, MktMailMessageEntity entity) {
|
|
|
+ try {
|
|
|
+ if ("IMAP".equalsIgnoreCase(account.getProtocolType()) && message.getFolder() instanceof IMAPFolder) {
|
|
|
+ long uid = ((IMAPFolder) message.getFolder()).getUID(message);
|
|
|
+ entity.setMsgUid(String.valueOf(uid));
|
|
|
+ } else if ("POP3".equalsIgnoreCase(account.getProtocolType()) && message.getFolder() instanceof POP3Folder) {
|
|
|
+ entity.setMsgUid(((POP3Folder) message.getFolder()).getUID(message));
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("mkt fillMsgUid error", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void saveAttachments(MktMailMessageEntity mail, Message message, SmtpPopSettingsEntity account) {
|
|
|
+ try {
|
|
|
+ int exist = mktMailAttachmentService.count(new LambdaQueryWrapper<MktMailAttachmentEntity>()
|
|
|
+ .eq(MktMailAttachmentEntity::getMailId, mail.getId())
|
|
|
+ .eq(MktMailAttachmentEntity::getIsDelete, CommonConstant.DEL_FLAG_0));
|
|
|
+ if (exist > 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Object content = message.getContent();
|
|
|
+ if (!(content instanceof Multipart)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String day = DateUtils.date2Str(
|
|
|
+ mail.getRecipientDate() == null ? new Date() : mail.getRecipientDate(), DateUtils.yyyyMMdd);
|
|
|
+ String downloadDir = mailFileProperties.getPath().getPath() + File.separator
|
|
|
+ + account.getEmailAddress() + File.separator + day + File.separator;
|
|
|
+ Multipart multipart = (Multipart) content;
|
|
|
+ for (int i = 0; i < multipart.getCount(); i++) {
|
|
|
+ BodyPart bodyPart = multipart.getBodyPart(i);
|
|
|
+ if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())
|
|
|
+ || bodyPart.isMimeType("application/octet-stream")) {
|
|
|
+ saveOneAttachment(bodyPart, downloadDir, mail, account);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("mkt saveAttachments error, mailId={}", mail.getId(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void saveOneAttachment(BodyPart bodyPart, String downloadDir, MktMailMessageEntity mail, SmtpPopSettingsEntity account) {
|
|
|
+ try {
|
|
|
+ String fileName = bodyPart.getFileName();
|
|
|
+ if (!StringUtils.hasText(fileName)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fileName = MimeUtility.decodeText(fileName).replace("\n", "").replace("\r", "");
|
|
|
+ String code = RandomGenerateHelper.generateRandomString(6);
|
|
|
+ if (!new File(downloadDir).exists()) {
|
|
|
+ new File(downloadDir).mkdirs();
|
|
|
+ }
|
|
|
+ String storedName = fileName + "." + code;
|
|
|
+ File file = new File(downloadDir + File.separator + storedName);
|
|
|
+ try (FileOutputStream output = new FileOutputStream(file)) {
|
|
|
+ bodyPart.getInputStream().transferTo(output);
|
|
|
+ }
|
|
|
+ MktMailAttachmentEntity att = new MktMailAttachmentEntity();
|
|
|
+ att.setMailId(mail.getId());
|
|
|
+ att.setAccountId(account.getId());
|
|
|
+ att.setFileCode(code);
|
|
|
+ att.setFileName(FilenameUtils.getBaseName(fileName));
|
|
|
+ att.setFileExt(FilenameUtils.getExtension(fileName));
|
|
|
+ att.setFilePath(file.getAbsolutePath().replace(mailFileProperties.getPath().getPath(), ""));
|
|
|
+ att.setFileSize(file.length());
|
|
|
+ att.setOwnerBy(mail.getOwnerBy());
|
|
|
+ att.setCreateBy(mail.getOwnerBy());
|
|
|
+ att.setIsDelete(CommonConstant.DEL_FLAG_0);
|
|
|
+ att.setEnabled(Boolean.TRUE);
|
|
|
+ mktMailAttachmentService.save(att);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("mkt saveOneAttachment error", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String extractBody(Message message) {
|
|
|
+ try {
|
|
|
+ Object content = message.getContent();
|
|
|
+ if (content instanceof String) {
|
|
|
+ return content.toString();
|
|
|
+ }
|
|
|
+ if (content instanceof Multipart) {
|
|
|
+ return parseMultipart((Multipart) content);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("mkt extractBody error", e);
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String parseMultipart(Multipart multipart) throws Exception {
|
|
|
+ StringBuilder html = new StringBuilder();
|
|
|
+ StringBuilder plain = new StringBuilder();
|
|
|
+ for (int i = 0; i < multipart.getCount(); i++) {
|
|
|
+ BodyPart part = multipart.getBodyPart(i);
|
|
|
+ Object content = part.getContent();
|
|
|
+ if (content instanceof Multipart) {
|
|
|
+ String nested = parseMultipart((Multipart) content);
|
|
|
+ html.append(nested);
|
|
|
+ } else if (part.isMimeType("text/html")) {
|
|
|
+ html.append(content == null ? "" : content.toString());
|
|
|
+ } else if (part.isMimeType("text/plain")) {
|
|
|
+ plain.append(content == null ? "" : content.toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return html.length() > 0 ? html.toString() : plain.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Map<String, String> decodeAddresses(Address[] addresses) throws Exception {
|
|
|
+ Map<String, String> map = new HashMap<>();
|
|
|
+ if (addresses == null) {
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+ for (Address address : addresses) {
|
|
|
+ InternetAddress internetAddress = (InternetAddress) address;
|
|
|
+ String personal = internetAddress.getPersonal();
|
|
|
+ if (personal != null) {
|
|
|
+ personal = MimeUtility.decodeText(personal);
|
|
|
+ }
|
|
|
+ map.put(internetAddress.getAddress(), personal != null ? personal : "N/A");
|
|
|
+ }
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String joinKeys(Map<String, String> map) {
|
|
|
+ if (map == null || map.isEmpty()) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ return String.join(",", map.keySet());
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String joinValues(Map<String, String> map) {
|
|
|
+ if (map == null || map.isEmpty()) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ return map.values().stream()
|
|
|
+ .filter(v -> v != null && !"N/A".equals(v))
|
|
|
+ .collect(Collectors.joining(","));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String firstHeader(Message message, String name) throws Exception {
|
|
|
+ String[] values = message.getHeader(name);
|
|
|
+ if (values == null || values.length == 0) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return values[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String normalizeMessageId(String messageId) {
|
|
|
+ if (!StringUtils.hasText(messageId)) {
|
|
|
+ return messageId;
|
|
|
+ }
|
|
|
+ return messageId.trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String stripBrackets(String messageId) {
|
|
|
+ if (!StringUtils.hasText(messageId)) {
|
|
|
+ return messageId;
|
|
|
+ }
|
|
|
+ String v = messageId.trim();
|
|
|
+ if (v.startsWith("<") && v.endsWith(">") && v.length() > 2) {
|
|
|
+ return v.substring(1, v.length() - 1);
|
|
|
+ }
|
|
|
+ return v;
|
|
|
+ }
|
|
|
+}
|