From 81cb8082468c705eda672decf6b29d02e5836afb Mon Sep 17 00:00:00 2001 From: duwenyuan <15600000461@163.com> Date: Fri, 4 Jul 2025 15:07:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=99=BB=E5=BD=95=E9=82=AE?= =?UTF-8?q?=E7=AE=B1=E9=85=8D=E7=BD=AE=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/email/EmailServiceManager.java | 235 ++++++++++++++---- .../exception/CheckMailContentException.java | 9 + .../spectrum/SpectrumParsingActuator.java | 3 +- 3 files changed, 204 insertions(+), 43 deletions(-) create mode 100644 jeecg-module-auto-process/src/main/java/org/jeecg/modules/exception/CheckMailContentException.java diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/email/EmailServiceManager.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/email/EmailServiceManager.java index e1982487..ed7ab1be 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/common/email/EmailServiceManager.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/email/EmailServiceManager.java @@ -1,13 +1,17 @@ package org.jeecg.common.email; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import com.google.common.collect.Lists; import com.sun.mail.imap.IMAPStore; +import com.sun.mail.pop3.POP3Folder; import com.sun.mail.smtp.SMTPAddressFailedException; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.jeecg.common.api.dto.message.MessageDTO; import org.jeecg.common.constant.RedisConstant; @@ -32,6 +36,7 @@ import javax.mail.search.SearchTerm; import java.io.*; import java.net.InetSocketAddress; import java.net.Socket; +import java.nio.file.Files; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; @@ -64,7 +69,8 @@ public class EmailServiceManager { /** * smtp协议的存储对象 */ - private IMAPStore store = null; + //private IMAPStore store = null; + private Store store = null; /** * 邮件附件临时存储路径 */ @@ -73,7 +79,8 @@ public class EmailServiceManager { * 收件箱 */ private Folder folder = null; - + // 判断协议类型 + private String protocol; private RedisUtil redisUtil; private Object downloadEmlLocal = new Object(); @@ -138,7 +145,7 @@ public class EmailServiceManager { /** * 接收邮件 */ - public Message[] receiveMail() throws Exception { + public Message[] receiveMail1() throws Exception { String status = EmailLogManager.STATUS_SUCCESS; try { //配置邮件服务属性 @@ -169,10 +176,10 @@ public class EmailServiceManager { store = (IMAPStore) session.getStore(); //连接 store.connect(email.getUsername(), email.getPassword()); - if (email.getEmailServerType()==1) { + if (email.getEmailServerType() == 1) { // 解决163普通邮箱无法建立连接问题 - store.id(IAM); + ((IMAPStore) store).id(IAM); } //获取收件箱 @@ -218,6 +225,134 @@ public class EmailServiceManager { return null; } + public Message[] receiveMail() throws Exception { + String status = EmailLogManager.STATUS_SUCCESS; + try { + store = setStoreProperties(); + //获取收件箱 + folder = store.getFolder("INBOX");//INBOX + folder.open(Folder.READ_WRITE); + //如果邮箱邮件数量 > 0 + final int messageCount = folder.getMessageCount(); + if (messageCount > 0) { + Message[] messages = null; + if (Objects.isNull(this.systemStartupTime)) { + int finalNum = messageCount > this.receiveNum ? this.receiveNum : messageCount; + //邮箱邮件下标是从1开始的 + return folder.getMessages(1, finalNum); + } + SearchTerm searchTerm = new ReceivedDateTerm(ComparisonTerm.GE, this.systemStartupTime); + messages = folder.search(searchTerm); + Arrays.sort(messages, (o1, o2) -> { + try { + if (o1.getReceivedDate() == null && o2.getReceivedDate() == null) { + return o1.getSentDate().compareTo(o2.getSentDate()); + } else { + return o1.getReceivedDate().compareTo(o2.getReceivedDate()); + } + } catch (MessagingException e) { + e.printStackTrace(); + log.error(e.getMessage(), e); + } + return 0; + }); + if (this.receiveNum >= messages.length) { + return messages; + } else { + return Arrays.copyOfRange(messages, 0, this.receiveNum - 1); + } + } + } catch (Exception e) { + status = EmailLogManager.STATUS_ERROR; + log.error("Email connection is abnormal, account is {}, service is {},the reason is {}.", email.getName(), email.getEmailServerAddress(), e.getMessage()); + throw e; + } finally { + EmailLogEvent connectEvent = new EmailLogEvent(EmailLogManager.GS_TYPE_GET, email, status, EmailLogManager.CONNECT); + EmailLogManager.getInstance().setConnectLogEvent(connectEvent); + //GetAllId C++原业务是把远程邮箱邮件同步到C++,本次java编写没有这一步,所以和Connect绑定,若Connect成功则GetAllId成功 + EmailLogEvent getAllEvent = new EmailLogEvent(EmailLogManager.GS_TYPE_GET, status, EmailLogManager.GETALLID); + EmailLogManager.getInstance().setGetAllIdLogEvent(getAllEvent); + } + return null; + } + + + private Store setStoreProperties() throws MessagingException { + HashMap IAM = new HashMap(); + //带上IMAP ID信息,由key和value组成,例如name,version,vendor,support-email等。 + IAM.put("name", "myname"); + IAM.put("version", "1.0.0"); + IAM.put("vendor", "myclient"); + IAM.put("support-email", "testmail@test.com"); + Properties properties = getProperties(); + + //获取邮件回话 + Session session = Session.getInstance(properties); + //获取smtp协议的存储对象 + Store store = session.getStore(); + log.info("连接 {}:{}:{}", email.getUsername(), email.getPassword(), email.getPort()); + //连接 + store.connect(email.getUsername(), email.getPassword()); + + if (email.getEmailServerType() == 1) { + // 解决163普通邮箱无法建立连接问题 + ((IMAPStore) store).id(IAM); + } + protocol = store.getURLName().getProtocol(); + return store; + } + + @NotNull + private Properties getProperties() { + Properties properties = new Properties(); + switch (email.getPort()) { + case 110: + properties.put("mail.store.protocol", "pop3"); + properties.put("mail.pop3.host", email.getEmailServerAddress()); + properties.put("mail.pop3.port", email.getPort()); + properties.put("mail.pop3.starttls.enable", "true"); + // 超时设置(毫秒) + properties.put("mail.pop3.connectiontimeout", "10000"); + properties.put("mail.pop3.timeout", "15000"); + break; + case 995: + properties.put("mail.store.protocol", "pop3"); + properties.put("mail.pop3.host", email.getEmailServerAddress()); + properties.put("mail.pop3.port", email.getPort()); + properties.put("mail.pop3.starttls.enable", "true"); + properties.put("mail.pop3.connectiontimeout", "10000"); + properties.put("mail.pop3.timeout", "15000"); + properties.put("mail.pop3.auth", "true"); + break; + case 143: + properties.put("mail.store.protocol", "imap"); + properties.put("mail.imap.host", email.getEmailServerAddress()); + properties.put("mail.imap.port", email.getPort()); + properties.put("mail.imap.ssl.enable", "false"); + properties.put("mail.imap.starttls.enable", "true"); + properties.put("mail.imap.auth", "true"); + // 超时设置(毫秒) + properties.put("mail.imap.connectiontimeout", "10000"); + properties.put("mail.imap.timeout", "30000"); + break; + case 993: + default: + properties.put("mail.store.protocol", "imap"); + properties.put("mail.imap.host", email.getEmailServerAddress()); + properties.put("mail.imap.port", email.getPort()); + properties.put("mail.imap.connectiontimeout", "3000"); + properties.put("mail.imap.timeout", "3000"); + if (email.getIsQiye() == 1) { + properties.put("mail.imap.ssl.enable", "true"); + } else { + properties.put("mail.imap.ssl.enable", "false"); + } + + break; + } + return properties; + } + /* * 测试收件邮箱账号是否可以正常使用 * */ @@ -227,10 +362,7 @@ public class EmailServiceManager { String password = email.getPassword(); String host = email.getEmailServerAddress(); - Properties props = new Properties(); - props.put("mail.store.protocol", "imap"); - props.put("mail.imap.host", host); - props.put("mail.imap.port", port); + Properties props = getProperties(); Session session = Session.getInstance(props, new Authenticator() { @Override @@ -482,6 +614,31 @@ public class EmailServiceManager { return subject; } + public String getMessagesID(Message message, Integer batchesCounter) throws MessagingException { + String messageId = null; + String status = EmailLogManager.STATUS_SUCCESS; + try { + + if (null == message.getHeader("Message-ID")) { + String subject = message.getSubject().replace(" ", StringConstant.UNDER_LINE); + Date date = message.getReceivedDate() == null ? message.getSentDate() : message.getReceivedDate(); + String receivedStr = DateUtil.format(date, DatePattern.NORM_DATETIME_MINUTE_PATTERN); + messageId = subject + StringConstant.UNDER_LINE + receivedStr; + } else { + messageId = ((MimeMessage) message).getMessageID(); + } + } catch (MessagingException e) { + status = EmailLogManager.STATUS_ERROR; + log.error(e.getMessage()); + throw e; + + }finally { + EmailLogEvent event = new EmailLogEvent(batchesCounter, Thread.currentThread().getId(), EmailLogManager.GS_TYPE_GET, status, EmailLogManager.GETIDHEADER); + EmailLogManager.getInstance().offer(Thread.currentThread().getId(), event); + } + return messageId; + } + /** * 获取邮件内容 * @@ -555,8 +712,8 @@ public class EmailServiceManager { File emlFile = null; String status = EmailLogManager.STATUS_SUCCESS; Date receivedDate = null; - InputStream inputStream = null; - BufferedOutputStream outputStream = null; + //InputStream inputStream = null; + //BufferedOutputStream outputStream = null; try { //获取发件人 final String address = ((InternetAddress) message.getFrom()[0]).getAddress(); @@ -569,7 +726,7 @@ public class EmailServiceManager { if (subject.indexOf(StringConstant.COLON) != -1) { subject = StringUtils.replace(subject, StringConstant.COLON, ""); } - receivedDate = message.getReceivedDate(); + receivedDate = message.getReceivedDate() == null ? message.getSentDate() : message.getReceivedDate(); StringBuilder fileName = new StringBuilder(); fileName.append(from); fileName.append(StringConstant.UNDER_LINE); @@ -590,19 +747,21 @@ public class EmailServiceManager { final String rootPath = spectrumPathProperties.getRootPath(); final String emlPath = spectrumPathProperties.getEmlPath(); emlFile = new File(rootPath + emlPath + File.separator + fileName); -// outputStream = new FileOutputStream(emlFile); -// message.writeTo(outputStream); - int bufferSize = 1024 * 1024; // 1M - inputStream = message.getInputStream(); - outputStream = new BufferedOutputStream(new FileOutputStream(emlFile), bufferSize); - // 从邮件的输入流读取内容,并写入到本地文件 - byte[] buffer = new byte[bufferSize]; - int bytesRead; - while ((bytesRead = inputStream.read(buffer)) != -1) { - outputStream.write(buffer, 0, bytesRead); + try (InputStream inputStream = message.getInputStream(); + BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(emlFile),bufferSize)) { + byte[] buffer = new byte[1024*1024]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + outputStream.flush(); // 显式刷新 + } catch (IOException e) { + FileUtils.copyInputStreamToFile(message.getInputStream(), emlFile); + } + if (emlFile.length() <= 0) { + FileUtils.copyInputStreamToFile(message.getInputStream(), emlFile); } - } catch (MessagingException | IOException e) { // 下载邮件失败 抛出自定义邮件下载异常 status = EmailLogManager.STATUS_ERROR; @@ -616,17 +775,6 @@ public class EmailServiceManager { EmailLogEvent event = new EmailLogEvent(batchesCounter, Thread.currentThread().getId(), EmailLogManager.GS_TYPE_GET, status, EmailLogManager.GETIDEML, subject, DateUtils.formatDate(receivedDate, "yyyy-MM-dd HH:mm:ss:SSS"), (Objects.isNull(emlFile) ? " " : emlFile.getAbsolutePath())); EmailLogManager.getInstance().offer(Thread.currentThread().getId(), event); - try { - if (Objects.nonNull(inputStream)) { - inputStream.close(); - } - if (Objects.nonNull(outputStream)) { - outputStream.flush(); - outputStream.close(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } } return emlFile; } @@ -685,7 +833,7 @@ public class EmailServiceManager { if (subject.contains(StringConstant.COLON)) { subject = StringUtils.replace(subject, StringConstant.COLON, ""); } - receivedDate = message.getReceivedDate(); + receivedDate = message.getReceivedDate() == null ? message.getSentDate() : message.getReceivedDate(); StringBuilder fileName = new StringBuilder(); fileName.append(from); fileName.append(StringConstant.UNDER_LINE); @@ -744,7 +892,7 @@ public class EmailServiceManager { Date receivedDate = null; try { subject = MimeUtility.decodeText(message.getSubject()); - receivedDate = message.getReceivedDate(); + receivedDate = message.getReceivedDate() == null ? message.getSentDate() : message.getReceivedDate(); message.setFlag(Flags.Flag.DELETED, true); // log.info("EmailServiceManager: Remove Email:{},receiveTime:{}",message.getSubject(), DateUtils.formatDate(message.getReceivedDate(),"yyyy-MM-dd HH:mm:ss")); } catch (MessagingException | UnsupportedEncodingException e) { @@ -768,17 +916,19 @@ public class EmailServiceManager { public void close(List messageIds) { try { if (null != folder) { - folder.expunge(); + if ("imap".equalsIgnoreCase(protocol)) { + folder.expunge(); + } folder.close(); } if (null != store) { store.close(); } log.info("{}: EmailServiceManage资源关闭完成.", Thread.currentThread().getName()); -// for(String messageId : messageIds){ -// String key = RedisConstant.EMAIL_MSG_ID+StringConstant.COLON+messageId; -// redisUtil.del(key); -// } + for (String messageId : messageIds) { + String key = RedisConstant.EMAIL_MSG_ID + StringConstant.COLON + messageId; + redisUtil.del(key); + } } catch (MessagingException e) { log.error("Email closure failed, email address is: {}, reason is: {}", email.getUsername(), e); e.printStackTrace(); @@ -799,7 +949,8 @@ public class EmailServiceManager { // exist = redisUtil.hasKey(key); if (numberKey >= taskProperties.getForceDeletedNumber()) { exist = true; - log.info("Check: Remove Email:{},receiveTime:{}", message.getSubject(), DateUtils.formatDate(message.getReceivedDate(), "yyyy-MM-dd HH:mm:ss")); + Date dateUtils = message.getReceivedDate() == null ? message.getSentDate() : message.getReceivedDate(); + log.info("Check: Remove Email:{},receiveTime:{}", message.getSubject(), DateUtils.formatDate(dateUtils, "yyyy-MM-dd HH:mm:ss")); message.setFlag(Flags.Flag.DELETED, true); redisUtil.del(key); } diff --git a/jeecg-module-auto-process/src/main/java/org/jeecg/modules/exception/CheckMailContentException.java b/jeecg-module-auto-process/src/main/java/org/jeecg/modules/exception/CheckMailContentException.java new file mode 100644 index 00000000..48f535b1 --- /dev/null +++ b/jeecg-module-auto-process/src/main/java/org/jeecg/modules/exception/CheckMailContentException.java @@ -0,0 +1,9 @@ +package org.jeecg.modules.exception; + +public class CheckMailContentException extends RuntimeException { + + public CheckMailContentException() {super();} + public CheckMailContentException(String message) { + super(message); + } +} diff --git a/jeecg-module-auto-process/src/main/java/org/jeecg/modules/spectrum/SpectrumParsingActuator.java b/jeecg-module-auto-process/src/main/java/org/jeecg/modules/spectrum/SpectrumParsingActuator.java index aa17ffae..94eddc27 100644 --- a/jeecg-module-auto-process/src/main/java/org/jeecg/modules/spectrum/SpectrumParsingActuator.java +++ b/jeecg-module-auto-process/src/main/java/org/jeecg/modules/spectrum/SpectrumParsingActuator.java @@ -16,6 +16,7 @@ import org.jeecg.common.util.DateUtils; import org.jeecg.modules.email.EmailProperties; import org.jeecg.modules.enums.SpectrumSource; import org.jeecg.modules.exception.AnalySpectrumException; +import org.jeecg.modules.exception.CheckMailContentException; import org.jeecg.modules.file.FileOperation; import javax.mail.Message; @@ -151,7 +152,7 @@ public class SpectrumParsingActuator implements Runnable { // 如果邮件内容校验失败(邮件内容不完整) 将错误邮件从eml移动到emlError if (Objects.nonNull(emlFile) && emlFile.exists()) { moveEmail(emlFile, key); - throw new DownloadEmailException("邮件移走后手动抛出DownloadEmailException"); + throw new CheckMailContentException("邮件内容校验失败,邮件移走后手动抛出CheckMailContentException"); } } } catch (Exception e) {