Parcourir la source

邮件服务接口增加和调整,业务拆分

1811872455@163.com il y a 2 mois
Parent
commit
4b17d26186
100 fichiers modifiés avec 1282 ajouts et 528 suppressions
  1. 11 1
      pom.xml
  2. 5 2
      storlead-api/pom.xml
  3. 5 2
      storlead-api/src/main/java/com/storlead/StorleadMailServiceApplication.java
  4. 1 1
      storlead-api/src/main/java/com/storlead/mail/common/EmailServiceChecker.java
  5. 82 21
      storlead-api/src/main/java/com/storlead/mail/common/SmtpPopSettingsApiController.java
  6. 1 1
      storlead-api/src/main/java/com/storlead/mail/crm/ClientSentEmailsController.java
  7. 23 14
      storlead-api/src/main/java/com/storlead/mail/crm/EmailFolderRuleApiController.java
  8. 38 16
      storlead-api/src/main/java/com/storlead/mail/crm/MaiAttachmentApiController.java
  9. 113 47
      storlead-api/src/main/java/com/storlead/mail/crm/MailApiController.java
  10. 21 13
      storlead-api/src/main/java/com/storlead/mail/crm/MailBlacklistRecordApiController.java
  11. 21 11
      storlead-api/src/main/java/com/storlead/mail/crm/MailTemplatesApiController.java
  12. 24 11
      storlead-api/src/main/java/com/storlead/mail/crm/MailboxAutoReplySetController.java
  13. 13 13
      storlead-api/src/main/java/com/storlead/mail/crm/SmtpPopMailApiController.java
  14. 9 8
      storlead-api/src/main/java/com/storlead/mail/crm/ThumbnailPreviewController.java
  15. 20 12
      storlead-api/src/main/java/com/storlead/mail/crm/UserEmailFolderApiController.java
  16. 65 0
      storlead-api/src/main/java/com/storlead/mail/mkt/MktMailApiController.java
  17. 19 10
      storlead-api/src/main/resources/application-dev.yml
  18. 30 17
      storlead-api/src/main/resources/application-test.yml
  19. 8 4
      storlead-api/src/main/resources/application.yml
  20. 32 0
      storlead-mail/README.md
  21. 7 39
      storlead-mail/pom.xml
  22. 0 85
      storlead-mail/src/main/java/com/storlead/sales/mail/integration/scheduler/MailIntegrationTaskScheduler.java
  23. 0 67
      storlead-mail/src/main/java/com/storlead/sales/mail/service/impl/SmtpPopSettingsServiceImpl.java
  24. 0 2
      storlead-mail/src/main/resources/META-INF/spring.factories
  25. 51 0
      storlead-mail/storlead-mail-common/pom.xml
  26. 1 1
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/IMAPConnection.java
  27. 1 1
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/IMAPConnectionFactory.java
  28. 1 2
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/MailConnection.java
  29. 1 1
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/MailConnectionFactory.java
  30. 1 2
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/POP3Connection.java
  31. 1 1
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/POP3ConnectionFactory.java
  32. 1 1
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/SMTPConnection.java
  33. 1 1
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/SMTPConnectionFactory.java
  34. 3 3
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/client/MailConnectionUtil.java
  35. 3 3
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/client/MailReceiverUtil.java
  36. 4 4
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/client/MailSenderUtil.java
  37. 2 2
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/config/MailProperties.java
  38. 1 1
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/entity/MailServerPortConfigEntity.java
  39. 21 1
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/entity/SmtpPopSettingsEntity.java
  40. 33 0
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/enums/AccountScopeEnum.java
  41. 41 0
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/enums/MailSceneEnum.java
  42. 2 2
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/mapper/MailServerPortConfigMapper.java
  43. 2 2
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/mapper/SmtpPopSettingsMapper.java
  44. 1 1
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/properties/MailFileProperties.java
  45. 37 0
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/MailAccountBizService.java
  46. 2 2
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/MailServerPortConfigService.java
  47. 12 2
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/SmtpPopSettingsService.java
  48. 107 0
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/impl/MailAccountBizServiceImpl.java
  49. 4 4
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/impl/MailServerPortConfigServiceImpl.java
  50. 95 0
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/impl/SmtpPopSettingsServiceImpl.java
  51. 46 0
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/transport/MailTransportSupport.java
  52. 1 1
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/util/EmailHelper.java
  53. 1 1
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/util/MailFormatPartUtil.java
  54. 74 0
      storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/util/SafeFilePathResolver.java
  55. 2 2
      storlead-mail/storlead-mail-common/src/main/resources/mapper/MailServerPortConfigMapper.xml
  56. 7 2
      storlead-mail/storlead-mail-common/src/main/resources/mapper/SmtpPopSettingsMapper.xml
  57. 49 0
      storlead-mail/storlead-mail-common/src/main/resources/sql/mail_scene_and_mkt.sql
  58. 31 0
      storlead-mail/storlead-mail-crm/pom.xml
  59. 0 0
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/Main.java
  60. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/QQEmailReceiver.java
  61. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/QQEmailSender.java
  62. 7 7
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/dispatch/AutoSendDelayEmailTaskJob.java
  63. 7 7
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/dispatch/DelayDeleteServerEmailTaskJob.java
  64. 12 6
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/dispatch/EmailPullHeadContentTaskJob.java
  65. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/AttachmentEntity.java
  66. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/ClientSentEmailsEntity.java
  67. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailBlacklistRecordEntity.java
  68. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailFileFolderEntity.java
  69. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailFolderRuleEntity.java
  70. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailFoldersEntity.java
  71. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailTemplatesEntity.java
  72. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailsEntity.java
  73. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/FoldersEntity.java
  74. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/MailAttachmentEntity.java
  75. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/MailDelayPullRecordEntity.java
  76. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/MailTempAttachmentEntity.java
  77. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/MailboxAutoReplySetEntity.java
  78. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/UserEmailFolderEntity.java
  79. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/UserMailTrackRecordEntity.java
  80. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/enums/EmailBoxEnum.java
  81. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/enums/EmailFileFolderEnum.java
  82. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/enums/EmailFolderlRuleEnum.java
  83. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/enums/SendStatus.java
  84. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/config/MailIntegrationConfiguration.java
  85. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/config/MailIntegrationProperties.java
  86. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/entity/MailIntegrationTaskEntity.java
  87. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/enums/MailIntegrationTaskStatus.java
  88. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/enums/MailIntegrationTaskType.java
  89. 2 2
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/external/IntegrationExternalInvoker.java
  90. 5 5
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/handler/CrmMailSyncHandler.java
  91. 9 9
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/handler/NewMailRemindHandler.java
  92. 2 2
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/mapper/MailIntegrationTaskMapper.java
  93. 2 2
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/service/MailIntegrationTaskService.java
  94. 8 8
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/service/impl/MailIntegrationTaskServiceImpl.java
  95. 5 5
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/support/MailEntityResolver.java
  96. 1 1
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/util/MailIdsParser.java
  97. 2 2
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/mapper/AttachmentMapper.java
  98. 2 2
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/mapper/ClientSentEmailsMapper.java
  99. 2 2
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/mapper/EmailBlacklistRecordMapper.java
  100. 2 2
      storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/mapper/EmailFileFolderMapper.java

+ 11 - 1
pom.xml

@@ -152,7 +152,17 @@
 
         <dependency>
             <groupId>com.storlead.boot</groupId>
-            <artifactId>storlead-mail</artifactId>
+            <artifactId>storlead-mail-common</artifactId>
+            <version>${revision}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.storlead.boot</groupId>
+            <artifactId>storlead-mail-crm</artifactId>
+            <version>${revision}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.storlead.boot</groupId>
+            <artifactId>storlead-mail-mkt</artifactId>
             <version>${revision}</version>
         </dependency>
         <!-- swagger -->

+ 5 - 2
storlead-api/pom.xml

@@ -17,9 +17,12 @@
     <dependencies>
         <dependency>
             <groupId>com.storlead.boot</groupId>
-            <artifactId>storlead-mail</artifactId>
+            <artifactId>storlead-mail-crm</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.storlead.boot</groupId>
+            <artifactId>storlead-mail-mkt</artifactId>
         </dependency>
-
         <dependency>
             <groupId>com.storlead.boot</groupId>
             <artifactId>storlead-web</artifactId>

+ 5 - 2
storlead-api/src/main/java/com/storlead/StorleadMailServiceApplication.java

@@ -1,4 +1,5 @@
 package com.storlead;
+
 import lombok.extern.slf4j.Slf4j;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.ApplicationRunner;
@@ -11,8 +12,10 @@ import java.net.InetAddress;
 
 @SpringBootApplication(scanBasePackages = "com.storlead")
 @MapperScan({
-        "com.storlead.sales.mail.mapper",
-        "com.storlead.sales.mail.integration.mapper"
+        "com.storlead.sales.mail.common.mapper",
+        "com.storlead.sales.mail.crm.mapper",
+        "com.storlead.sales.mail.crm.integration.mapper",
+        "com.storlead.sales.mail.mkt.mapper"
 })
 @Slf4j
 public class StorleadMailServiceApplication {

+ 1 - 1
storlead-api/src/main/java/com/storlead/mail/EmailServiceChecker.java → storlead-api/src/main/java/com/storlead/mail/common/EmailServiceChecker.java

@@ -1,4 +1,4 @@
-package com.storlead.mail;
+package com.storlead.mail.common;
 
 /**
  * @program: sp-sales-platform

+ 82 - 21
storlead-api/src/main/java/com/storlead/mail/SmtpPopSettingsApiController.java → storlead-api/src/main/java/com/storlead/mail/common/SmtpPopSettingsApiController.java

@@ -1,4 +1,4 @@
-package com.storlead.mail;
+package com.storlead.mail.common;
 
 
 import cn.hutool.core.collection.CollectionUtil;
@@ -13,25 +13,30 @@ import com.storlead.framework.common.util.encryptor.AccessKeyEncryptor;
 import com.storlead.framework.util.LoginUserUtil;
 import com.storlead.framework.common.constant.CommonConstant;
 import com.storlead.framework.common.result.Result;
-import com.storlead.sales.mail.connection.MailConnection;
-import com.storlead.sales.mail.connection.client.MailConnectionUtil;
-import com.storlead.sales.mail.connection.config.MailProperties;
-import com.storlead.sales.mail.entity.EmailsEntity;
-import com.storlead.sales.mail.entity.MailboxAutoReplySetEntity;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.enums.EmailBoxEnum;
-import com.storlead.sales.mail.pojo.vo.MailAcountVO;
-import com.storlead.sales.mail.service.EmailsService;
-import com.storlead.sales.mail.service.SmtpPopSettingsService;
+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.enums.AccountScopeEnum;
+import com.storlead.sales.mail.common.enums.MailSceneEnum;
+import com.storlead.sales.mail.common.service.SmtpPopSettingsService;
+import com.storlead.sales.mail.crm.entity.EmailsEntity;
+import com.storlead.sales.mail.crm.entity.MailboxAutoReplySetEntity;
+import com.storlead.sales.mail.crm.enums.EmailBoxEnum;
+import com.storlead.sales.mail.crm.pojo.vo.MailAcountVO;
+import com.storlead.sales.mail.crm.service.EmailsService;
+import com.storlead.sales.mail.crm.support.MailOwnershipGuard;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
@@ -61,6 +66,9 @@ public class SmtpPopSettingsApiController {
     @Resource
     private EmailsService emailsService;
 
+    @Resource
+    private MailOwnershipGuard mailOwnershipGuard;
+
 
     @PostMapping(value = "/pageList")
     @ApiOperation(value = "获取我的邮箱配置信息" )
@@ -77,6 +85,10 @@ public class SmtpPopSettingsApiController {
         LambdaQueryWrapper<SmtpPopSettingsEntity> queryWrapper = new LambdaQueryWrapper();
         queryWrapper.eq(SmtpPopSettingsEntity::getIsDelete,Integer.valueOf(0));
         queryWrapper.eq(SmtpPopSettingsEntity::getOwnerBy,currentUserId);
+        // 个人邮箱配置页默认只看 CRM 账户
+        queryWrapper.and(w -> w.isNull(SmtpPopSettingsEntity::getScene)
+                .or().eq(SmtpPopSettingsEntity::getScene, "")
+                .or().eq(SmtpPopSettingsEntity::getScene, MailSceneEnum.CRM.getCode()));
         IPage<SmtpPopSettingsEntity> pageList =  smtpPopSettingsService.page(page,queryWrapper);
         if (!CollectionUtils.isEmpty(pageList.getRecords())) {
             pageList.getRecords().forEach(e -> {
@@ -95,6 +107,10 @@ public class SmtpPopSettingsApiController {
         if (Objects.isNull(id) || Objects.isNull(autoReplyStatus)) {
             return Result.error("参数错误");
         }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (mailOwnershipGuard.getOwnedSmtpPop(id, currentUserId) == null) {
+            return Result.error("无权操作");
+        }
         if (Integer.valueOf(1).equals(autoReplyStatus)) {
             if(StrUtil.isBlank(replyContent) || StrUtil.isBlank(replyTitle)) {
                 return Result.error("参数错误");
@@ -106,6 +122,7 @@ public class SmtpPopSettingsApiController {
         updateWrapper.set(SmtpPopSettingsEntity::getReplyOnTime,new Date());
         updateWrapper.set(SmtpPopSettingsEntity::getIsAutoReply,autoReplyStatus);
         updateWrapper.eq(SmtpPopSettingsEntity::getId,id);
+        updateWrapper.eq(SmtpPopSettingsEntity::getOwnerBy, currentUserId);
         smtpPopSettingsService.update(updateWrapper);
         return Result.ok();
     }
@@ -119,10 +136,15 @@ public class SmtpPopSettingsApiController {
         if (Objects.isNull(id) || Objects.isNull(autoReplyStatus)) {
             return Result.error("参数错误");
         }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (mailOwnershipGuard.getOwnedSmtpPop(id, currentUserId) == null) {
+            return Result.error("无权操作");
+        }
         LambdaUpdateWrapper<SmtpPopSettingsEntity> updateWrapper = new LambdaUpdateWrapper();
         updateWrapper.set(SmtpPopSettingsEntity::getIsAutoReply,autoReplyStatus);
         updateWrapper.set(SmtpPopSettingsEntity::getReplyOnTime,new Date());
         updateWrapper.eq(SmtpPopSettingsEntity::getId,id);
+        updateWrapper.eq(SmtpPopSettingsEntity::getOwnerBy, currentUserId);
         smtpPopSettingsService.update(updateWrapper);
         return Result.ok();
     }
@@ -138,13 +160,14 @@ public class SmtpPopSettingsApiController {
             return Result.result(null);
         }
         SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getById(id);
-        if (Objects.isNull(smtpPop)) {
+        if (Objects.isNull(smtpPop) || mailOwnershipGuard.getOwnedSmtpPop(id, currentUserId) == null) {
             return Result.error("参数错误");
         }
 
         LambdaUpdateWrapper<SmtpPopSettingsEntity> updateWrapper = new LambdaUpdateWrapper<>();
         updateWrapper.set(SmtpPopSettingsEntity::getIsDelete,Integer.valueOf(1));
         updateWrapper.eq(SmtpPopSettingsEntity::getId,id);
+        updateWrapper.eq(SmtpPopSettingsEntity::getOwnerBy, currentUserId);
         smtpPopSettingsService.update(updateWrapper);
         return Result.ok();
     }
@@ -207,19 +230,31 @@ public class SmtpPopSettingsApiController {
 
         if (Objects.nonNull(entity.getId())) {
             // 修改
-            SmtpPopSettingsEntity old = smtpPopSettingsService.getById(entity.getId());
-            if (Objects.nonNull(old)) {
-                if(!old.getEmailAddress().equals(entity.getEmailAddress())){
-                    return Result.error("已绑定的邮箱无法修改,可新增邮箱配置!");
-                }
+            SmtpPopSettingsEntity old = mailOwnershipGuard.getOwnedSmtpPop(entity.getId(), currentUserId);
+            if (Objects.isNull(old)) {
+                return Result.error("无权操作");
+            }
+            if(!old.getEmailAddress().equals(entity.getEmailAddress())){
+                return Result.error("已绑定的邮箱无法修改,可新增邮箱配置!");
             }
         }
+        entity.setOwnerBy(currentUserId);
+        if (!StringUtils.hasText(entity.getScene())) {
+            entity.setScene(MailSceneEnum.CRM.getCode());
+        }
+        if (!StringUtils.hasText(entity.getAccountScope())) {
+            entity.setAccountScope(AccountScopeEnum.PERSONAL.getCode());
+        }
+        if (entity.getEnableReceive() == null) {
+            entity.setEnableReceive(MailSceneEnum.isMkt(entity.getScene()) ? 0 : 1);
+        }
         Boolean b = smtpPopSettingsService.saveOrUpdate(entity);
         if (Integer.valueOf(1).equals(entity.getUseDefault()) && b) {
-            // 如果设置了默认邮箱,则将所有默认邮箱改为非默认
+            // 同场景内取消其他默认账户
             LambdaUpdateWrapper<SmtpPopSettingsEntity> updateWrapper = new LambdaUpdateWrapper();
             updateWrapper.set(SmtpPopSettingsEntity::getUseDefault,Integer.valueOf(0));
             updateWrapper.eq(SmtpPopSettingsEntity::getOwnerBy,currentUserId);
+            updateWrapper.eq(SmtpPopSettingsEntity::getScene, entity.getScene());
             updateWrapper.ne(SmtpPopSettingsEntity::getId,entity.getId());
             smtpPopSettingsService.update(updateWrapper);
         }
@@ -237,10 +272,16 @@ public class SmtpPopSettingsApiController {
         if (Objects.isNull(currentUserId) || Objects.isNull(id)) {
             return Result.result(null);
         }
+        SmtpPopSettingsEntity target = mailOwnershipGuard.getOwnedSmtpPop(id, currentUserId);
+        if (target == null) {
+            return Result.error("无权操作");
+        }
+        String scene = StringUtils.hasText(target.getScene()) ? target.getScene() : MailSceneEnum.CRM.getCode();
 
         LambdaUpdateWrapper<SmtpPopSettingsEntity> updateWrapper = new LambdaUpdateWrapper();
         updateWrapper.set(SmtpPopSettingsEntity::getUseDefault,Integer.valueOf(0));
         updateWrapper.eq(SmtpPopSettingsEntity::getOwnerBy,currentUserId);
+        updateWrapper.eq(SmtpPopSettingsEntity::getScene, scene);
         smtpPopSettingsService.update(updateWrapper);
 
         updateWrapper = new LambdaUpdateWrapper();
@@ -248,12 +289,27 @@ public class SmtpPopSettingsApiController {
         updateWrapper.eq(SmtpPopSettingsEntity::getOwnerBy,currentUserId);
         updateWrapper.set(SmtpPopSettingsEntity::getUseDefault,Integer.valueOf(1));
         smtpPopSettingsService.update(updateWrapper);
-        /**
-         * 需要当前默认邮箱的邮件和未读数
-         */
         return Result.ok();
     }
 
+    @PostMapping(value = "/mkt_account_list")
+    @ApiOperation(value = "获取营销邮箱账户列表")
+    public Result<?> mktAccountList(@RequestParam(required = false) Long orgId) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (Objects.isNull(currentUserId)) {
+            return Result.result(null);
+        }
+        LambdaQueryWrapper<SmtpPopSettingsEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SmtpPopSettingsEntity::getIsDelete, 0)
+                .eq(SmtpPopSettingsEntity::getScene, MailSceneEnum.MKT.getCode());
+        if (orgId != null) {
+            wrapper.eq(SmtpPopSettingsEntity::getOrgId, orgId);
+        } else {
+            wrapper.eq(SmtpPopSettingsEntity::getOwnerBy, currentUserId);
+        }
+        return Result.result(smtpPopSettingsService.list(wrapper));
+    }
+
 
     @PostMapping(value = "/isEnabledDelete")
     @ApiOperation(value = "是否开启删除服务器邮件;0 不开启,1:开启" )
@@ -264,9 +320,14 @@ public class SmtpPopSettingsApiController {
         if (Objects.isNull(id) || Objects.isNull(isEnabled)) {
             return Result.error("参数错误");
         }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (mailOwnershipGuard.getOwnedSmtpPop(id, currentUserId) == null) {
+            return Result.error("无权操作");
+        }
         LambdaUpdateWrapper<SmtpPopSettingsEntity> updateWrapper = new LambdaUpdateWrapper();
         updateWrapper.set(SmtpPopSettingsEntity::getIsDeleteMail,isEnabled);
         updateWrapper.eq(SmtpPopSettingsEntity::getId,id);
+        updateWrapper.eq(SmtpPopSettingsEntity::getOwnerBy, currentUserId);
         smtpPopSettingsService.update(updateWrapper);
         return Result.ok();
     }

+ 1 - 1
storlead-api/src/main/java/com/storlead/mail/ClientSentEmailsController.java → storlead-api/src/main/java/com/storlead/mail/crm/ClientSentEmailsController.java

@@ -1,4 +1,4 @@
-package com.storlead.mail;
+package com.storlead.mail.crm;
 
 
 import org.springframework.web.bind.annotation.RequestMapping;

+ 23 - 14
storlead-api/src/main/java/com/storlead/mail/EmailFolderRuleApiController.java → storlead-api/src/main/java/com/storlead/mail/crm/EmailFolderRuleApiController.java

@@ -1,4 +1,4 @@
-package com.storlead.mail;
+package com.storlead.mail.crm;
 
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -8,14 +8,15 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.storlead.framework.common.constant.CommonConstant;
 import com.storlead.framework.common.result.Result;
 import com.storlead.framework.util.LoginUserUtil;
-import com.storlead.sales.mail.entity.EmailFolderRuleEntity;
-import com.storlead.sales.mail.entity.EmailsEntity;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.enums.EmailFolderlRuleEnum;
-import com.storlead.sales.mail.pojo.dto.EmailTemplatesDTO;
-import com.storlead.sales.mail.pojo.dto.FolderRuleDTO;
-import com.storlead.sales.mail.service.EmailFolderRuleService;
-import com.storlead.sales.mail.service.EmailsService;
+import com.storlead.sales.mail.crm.entity.EmailFolderRuleEntity;
+import com.storlead.sales.mail.crm.entity.EmailsEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.crm.enums.EmailFolderlRuleEnum;
+import com.storlead.sales.mail.crm.pojo.dto.EmailTemplatesDTO;
+import com.storlead.sales.mail.crm.pojo.dto.FolderRuleDTO;
+import com.storlead.sales.mail.crm.service.EmailFolderRuleService;
+import com.storlead.sales.mail.crm.service.EmailsService;
+import com.storlead.sales.mail.crm.support.MailOwnershipGuard;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
@@ -50,6 +51,9 @@ public class EmailFolderRuleApiController {
     @Resource
     private EmailsService emailsService;
 
+    @Resource
+    private MailOwnershipGuard mailOwnershipGuard;
+
     @PostMapping(value = "/get_folder_rule")
     @ApiOperation(value = "获取规则" )
     public Result<?> getFolderRule() {
@@ -111,6 +115,9 @@ public class EmailFolderRuleApiController {
             }
         } else {
 
+            if (mailOwnershipGuard.getOwnedEntity(folderRuleService, entity.getId(), currentUserId) == null) {
+                return Result.error("无权操作");
+            }
             EmailFolderRuleEntity oldFolder = folderRuleService.getOne(w);
             if (Objects.nonNull(oldFolder)) {
                 if (!oldFolder.getId().equals(entity.getId())) {
@@ -119,6 +126,7 @@ public class EmailFolderRuleApiController {
             }
         }
 
+        entity.setOwnerBy(currentUserId);
         folderRuleService.saveOrUpdate(entity);
         return Result.ok();
     }
@@ -136,6 +144,7 @@ public class EmailFolderRuleApiController {
         LambdaQueryWrapper<EmailFolderRuleEntity> deleteW = new LambdaQueryWrapper<>();
         deleteW.eq(EmailFolderRuleEntity::getOwnerBy,currentUserId);
         folderRuleService.remove(deleteW);
+        dto.getFolderRules().forEach(rule -> rule.setOwnerBy(currentUserId));
         folderRuleService.saveOrUpdateBatch(dto.getFolderRules());
         return Result.ok();
     }
@@ -146,10 +155,12 @@ public class EmailFolderRuleApiController {
         if(Objects.isNull(ids)) {
             return Result.error("参数错误");
         }
-        folderRuleService.lgDelete(Arrays.asList(ids));
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        mailOwnershipGuard.softDeleteOwned(folderRuleService, Arrays.asList(ids), currentUserId);
 
         LambdaUpdateWrapper<EmailsEntity> updateWrapper = new LambdaUpdateWrapper<>();
         updateWrapper.in(EmailsEntity::getCustomFolderId,Arrays.asList(ids));
+        updateWrapper.eq(EmailsEntity::getOwnerBy, currentUserId);
         updateWrapper.set(EmailsEntity::getCustomFolderId,null);
         emailsService.update(updateWrapper);
         return Result.ok();
@@ -161,10 +172,8 @@ public class EmailFolderRuleApiController {
     @ApiOperation("禁用或启用")
     @PostMapping("enabled")
     public Result enabled(Long id,Boolean enable) {
-        LambdaUpdateWrapper<EmailFolderRuleEntity> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.set(EmailFolderRuleEntity::getEnabled,enable);
-        updateWrapper.eq(EmailFolderRuleEntity::getId,id);
-        folderRuleService.update(updateWrapper);
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        mailOwnershipGuard.updateEnabledOwned(folderRuleService, id, enable, currentUserId);
         return Result.ok();
     }
 }

+ 38 - 16
storlead-api/src/main/java/com/storlead/mail/MaiAttachmentApiController.java → storlead-api/src/main/java/com/storlead/mail/crm/MaiAttachmentApiController.java

@@ -1,15 +1,17 @@
-package com.storlead.mail;
+package com.storlead.mail.crm;
 
 import com.alibaba.fastjson.JSONObject;
 import com.storlead.framework.common.result.Result;
 import com.storlead.framework.common.util.DateUtils;
 import com.storlead.framework.util.LoginUserUtil;
-import com.storlead.sales.mail.entity.MailTempAttachmentEntity;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.properties.MailFileProperties;
-import com.storlead.sales.mail.service.MailTempAttachmentService;
-import com.storlead.sales.mail.service.SmtpPopSettingsService;
-import com.storlead.sales.mail.util.FileHelper;
+import com.storlead.sales.mail.crm.entity.MailTempAttachmentEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.common.properties.MailFileProperties;
+import com.storlead.sales.mail.crm.service.MailTempAttachmentService;
+import com.storlead.sales.mail.common.service.SmtpPopSettingsService;
+import com.storlead.sales.mail.crm.support.MailOwnershipGuard;
+import com.storlead.sales.mail.crm.util.FileHelper;
+import com.storlead.sales.mail.common.util.SafeFilePathResolver;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.log4j.Log4j2;
@@ -28,6 +30,8 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
 import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.*;
 
 /**
@@ -49,6 +53,9 @@ public class MaiAttachmentApiController {
     @Resource
     private MailTempAttachmentService tempAttachmentService;
 
+    @Resource
+    private MailOwnershipGuard mailOwnershipGuard;
+
     @PostMapping(value = "/cache_mail_file")
     @ApiOperation(value = "缓存需要上传的附件" )
     public Result<?> cacheMailFile(@RequestParam("files") List<MultipartFile> files) {
@@ -110,9 +117,14 @@ public class MaiAttachmentApiController {
     @ApiOperation(value = "下载临时附件" )
     public void downLoadMailFile(Long fileId, HttpServletResponse response) {
         try {
-            MailTempAttachmentEntity resource = tempAttachmentService.getById(fileId);
-            String downloadDir = mailFileProperties.getPath().getPath() +resource.getFilePath();
-            InputStream inputStream = new BufferedInputStream(new FileInputStream(downloadDir));
+            Long currentUserId = LoginUserUtil.getCurrentUserId();
+            MailTempAttachmentEntity resource = mailOwnershipGuard.getOwnedTempAttachment(fileId, currentUserId);
+            if (resource == null) {
+                return;
+            }
+            Path filePath = SafeFilePathResolver.resolveUnderBase(
+                    mailFileProperties.getPath().getPath(), resource.getFilePath());
+            InputStream inputStream = new BufferedInputStream(new FileInputStream(filePath.toFile()));
             response.reset();
             response.setContentType("application/octet-stream;charset=utf-8");
             /*
@@ -138,6 +150,8 @@ public class MaiAttachmentApiController {
             inputStream.close();
             outputStream.close();
 
+        } catch (IllegalArgumentException e) {
+            log.warn("download_mail_file rejected unsafe path, fileId={}", fileId);
         } catch (Exception e) {
             log.error("--upload -- error =", e);
         }
@@ -145,11 +159,19 @@ public class MaiAttachmentApiController {
 
     @GetMapping("/images/{imageName}")
     public ResponseEntity<FileSystemResource> getImage(@PathVariable String imageName) {
-
-        String downloadDir = mailFileProperties.getPath().getJpeg();
-        FileSystemResource resource = new FileSystemResource(downloadDir + imageName);
-        return ResponseEntity.ok()
-                .contentType(MediaType.IMAGE_JPEG)  // 根据图片类型调整
-                .body(resource);
+        try {
+            String jpegRoot = mailFileProperties.getPath().getJpeg();
+            Path filePath = SafeFilePathResolver.resolveFileNameUnderBase(jpegRoot, imageName);
+            if (!Files.exists(filePath) || !Files.isRegularFile(filePath)) {
+                return ResponseEntity.notFound().build();
+            }
+            FileSystemResource resource = new FileSystemResource(filePath.toFile());
+            return ResponseEntity.ok()
+                    .contentType(MediaType.IMAGE_JPEG)
+                    .body(resource);
+        } catch (IllegalArgumentException e) {
+            log.warn("getImage rejected unsafe name: {}", imageName);
+            return ResponseEntity.badRequest().build();
+        }
     }
 }

+ 113 - 47
storlead-api/src/main/java/com/storlead/mail/MailApiController.java → storlead-api/src/main/java/com/storlead/mail/crm/MailApiController.java

@@ -1,4 +1,11 @@
-package com.storlead.mail;
+package com.storlead.mail.crm;
+
+import com.storlead.mail.common.EmailServiceChecker;
+
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.common.service.SmtpPopSettingsService;
+import com.storlead.sales.mail.common.service.MailServerPortConfigService;
+import com.storlead.sales.mail.common.entity.MailServerPortConfigEntity;
 
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -12,14 +19,16 @@ import com.storlead.framework.common.util.encryptor.AccessKeyEncryptor;
 import com.storlead.framework.util.LoginUserUtil;
 import com.storlead.framework.common.constant.CommonConstant;
 import com.storlead.framework.common.result.Result;
-import com.storlead.sales.mail.entity.*;
-import com.storlead.sales.mail.enums.EmailBoxEnum;
-import com.storlead.sales.mail.enums.SendStatus;
-import com.storlead.sales.mail.pojo.*;
-import com.storlead.sales.mail.properties.MailFileProperties;
-import com.storlead.sales.mail.service.*;
-import com.storlead.sales.mail.util.FileHelper;
-import com.storlead.sales.mail.util.ZipUtility;
+import com.storlead.sales.mail.crm.entity.*;
+import com.storlead.sales.mail.crm.enums.EmailBoxEnum;
+import com.storlead.sales.mail.crm.enums.SendStatus;
+import com.storlead.sales.mail.crm.pojo.*;
+import com.storlead.sales.mail.common.properties.MailFileProperties;
+import com.storlead.sales.mail.crm.service.*;
+import com.storlead.sales.mail.crm.support.MailOwnershipGuard;
+import com.storlead.sales.mail.crm.util.FileHelper;
+import com.storlead.sales.mail.common.util.SafeFilePathResolver;
+import com.storlead.sales.mail.crm.util.ZipUtility;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
@@ -85,6 +94,9 @@ public class MailApiController {
     @Resource
     private Environment environment;
 
+    @Resource
+    private MailOwnershipGuard mailOwnershipGuard;
+
     @PostMapping(value = "/send_mail")
     @ApiOperation(value = "发送邮件")
     @ApiResponses({
@@ -149,6 +161,9 @@ public class MailApiController {
             entity.setRecipientBcc(org.apache.commons.lang3.StringUtils.join(dto.getRecipientBccls(), ","));
         }
         if (Objects.nonNull(dto.getId())) {
+            if (mailOwnershipGuard.getOwnedEmail(dto.getId(), currentUserId) == null) {
+                return Result.error("无权操作该邮件");
+            }
             entity.setId(dto.getId());
         }
 
@@ -162,12 +177,22 @@ public class MailApiController {
 
         emailsService.saveOrUpdate(entity);
         if (!CollectionUtils.isEmpty(dto.getFileIds())) {
+            for (Long fileId : dto.getFileIds()) {
+                if (mailOwnershipGuard.getOwnedTempAttachment(fileId, currentUserId) == null) {
+                    return Result.error("无权操作附件");
+                }
+            }
             LambdaUpdateWrapper<MailTempAttachmentEntity> fileWrapper = new LambdaUpdateWrapper<>();
             fileWrapper.set(MailTempAttachmentEntity::getEmailId, entity.getId());
             fileWrapper.in(MailTempAttachmentEntity::getId, dto.getFileIds());
             tempAttachmentService.update(fileWrapper);
         }
         if (!CollectionUtils.isEmpty(dto.getOldfileIds())) {
+            for (Long fileId : dto.getOldfileIds()) {
+                if (mailOwnershipGuard.getOwnedAttachment(fileId, currentUserId) == null) {
+                    return Result.error("无权操作附件");
+                }
+            }
             LambdaUpdateWrapper<MailAttachmentEntity> fileWrapper = new LambdaUpdateWrapper<>();
             fileWrapper.in(MailAttachmentEntity::getId, dto.getOldfileIds());
             List<MailAttachmentEntity> mailAttachments = mailAttachmentService.list(fileWrapper);
@@ -217,7 +242,7 @@ public class MailApiController {
         if (CollectionUtils.isEmpty(dto.getMailIds())) {
             return;
         }
-        List<EmailsEntity> entities = emailsService.list(new LambdaQueryWrapper<EmailsEntity>().in(EmailsEntity::getId, dto.getMailIds()));
+        List<EmailsEntity> entities = mailOwnershipGuard.listOwnedEmails(dto.getMailIds(), currentUserId);
         if (CollectionUtils.isEmpty(entities)) {
             return;
         }
@@ -285,7 +310,8 @@ public class MailApiController {
         if (Objects.isNull(dto.getMailId())) {
             return;
         }
-        EmailsEntity entitie = emailsService.getById(dto.getMailId());
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        EmailsEntity entitie = mailOwnershipGuard.getOwnedEmail(dto.getMailId(), currentUserId);
         if (Objects.isNull(entitie)) {
             return;
         }
@@ -402,7 +428,7 @@ public class MailApiController {
                 // 设置文本消息部分
                 for (MailTempAttachmentEntity attachment : tempAttachment) {
                     BodyPart messageBodyPart = new MimeBodyPart();
-                    String filePath = mailFileProperties.getPath().getPath() + attachment.getFilePath();
+                    String filePath = resolveMailFile(attachment.getFilePath()).toString();
                     messageBodyPart = new MimeBodyPart();
                     String fileName = attachment.getFileName() + "." + attachment.getFileExt();
                     DataSource fileSource = new FileDataSource(filePath);
@@ -479,9 +505,11 @@ public class MailApiController {
         if (Objects.isNull(ids)) {
             return Result.error("参数错误");
         }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
         LambdaUpdateWrapper<EmailsEntity> uWrapper = new LambdaUpdateWrapper<>();
         uWrapper.set(EmailsEntity::getIsDelete, Integer.valueOf(1));
         uWrapper.in(EmailsEntity::getId, Arrays.asList(ids));
+        uWrapper.eq(EmailsEntity::getOwnerBy, currentUserId);
         emailsService.update(uWrapper);
         return Result.ok();
     }
@@ -495,8 +523,10 @@ public class MailApiController {
         if (Objects.isNull(ids)) {
             return Result.error("删除草稿");
         }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
         LambdaUpdateWrapper<EmailsEntity> uWrapper = new LambdaUpdateWrapper<>();
         uWrapper.in(EmailsEntity::getId, Arrays.asList(ids));
+        uWrapper.eq(EmailsEntity::getOwnerBy, currentUserId);
         emailsService.remove(uWrapper);
         return Result.ok();
     }
@@ -510,8 +540,12 @@ public class MailApiController {
         if (Objects.isNull(mailId)) {
             return Result.error("参数错误!");
         }
-        EmailsEntity email = emailsService.getById(mailId);
-        if (Objects.nonNull(email) && EmailBoxEnum.DRAFT.code.equals(email.getFolder())) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        EmailsEntity email = mailOwnershipGuard.getOwnedEmail(mailId, currentUserId);
+        if (email == null) {
+            return Result.error("邮件不存在或无权访问");
+        }
+        if (EmailBoxEnum.DRAFT.code.equals(email.getFolder())) {
             List<MailTempAttachmentEntity> atts = tempAttachmentService.list(new LambdaQueryWrapper<MailTempAttachmentEntity>().eq(MailTempAttachmentEntity::getEmailId, mailId));
             if (!CollectionUtils.isEmpty(atts)) {
                 atts.forEach(e -> {
@@ -538,9 +572,17 @@ public class MailApiController {
         if (Objects.isNull(mailIds) || Objects.isNull(folderId)) {
             return Result.error("参数错误");
         }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (mailOwnershipGuard.getOwnedFolder(folderId, currentUserId) == null) {
+            return Result.error("文件夹不存在或无权访问");
+        }
+        if (!mailOwnershipGuard.ownsAllEmails(Arrays.asList(mailIds), currentUserId)) {
+            return Result.error("无权操作邮件");
+        }
         LambdaUpdateWrapper<EmailsEntity> updateWrapper = new LambdaUpdateWrapper<>();
         updateWrapper.set(EmailsEntity::getCustomFolderId, folderId);
         updateWrapper.in(EmailsEntity::getId, Arrays.asList(mailIds));
+        updateWrapper.eq(EmailsEntity::getOwnerBy, currentUserId);
         emailsService.update(updateWrapper);
         return Result.ok();
     }
@@ -551,8 +593,10 @@ public class MailApiController {
         if (Objects.isNull(mailIds)) {
             return Result.error("参数错误");
         }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
         LambdaUpdateWrapper<EmailsEntity> updateWrapper = new LambdaUpdateWrapper<>();
         updateWrapper.in(EmailsEntity::getId, Arrays.asList(mailIds));
+        updateWrapper.eq(EmailsEntity::getOwnerBy, currentUserId);
         updateWrapper.set(EmailsEntity::getCustomFolderId, null);
         emailsService.update(updateWrapper);
         return Result.ok();
@@ -589,8 +633,10 @@ public class MailApiController {
         if (Objects.isNull(dto.getEmailId()) && StringUtils.isEmpty(dto.getEmailIds())) {
             return Result.error("参数错误!");
         }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
         LambdaUpdateWrapper<EmailsEntity> uWrapper = new LambdaUpdateWrapper<>();
         uWrapper.set(EmailsEntity::getIsRead, dto.getIsRead());
+        uWrapper.eq(EmailsEntity::getOwnerBy, currentUserId);
         if (Objects.nonNull(dto.getEmailId())) {
             uWrapper.eq(EmailsEntity::getId, dto.getEmailId());
         } else {
@@ -609,8 +655,10 @@ public class MailApiController {
         if (Objects.isNull(dto.getEmailId()) && StringUtils.isEmpty(dto.getEmailIds())) {
             return Result.error("参数错误!");
         }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
         LambdaUpdateWrapper<EmailsEntity> uWrapper = new LambdaUpdateWrapper<>();
         uWrapper.set(EmailsEntity::getReplyMsgId, dto.getReplyMsgId());
+        uWrapper.eq(EmailsEntity::getOwnerBy, currentUserId);
         if (Objects.nonNull(dto.getEmailId())) {
             uWrapper.eq(EmailsEntity::getId, dto.getEmailId());
         } else {
@@ -704,12 +752,19 @@ public class MailApiController {
         if (Objects.isNull(dto.getMailId()) && CollectionUtils.isEmpty(dto.getAttachmentIds())) {
             return;
         }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
         String zipFilePath = mailFileProperties.getPath().getPath() + System.currentTimeMillis() + RandomGenerateHelper.generateRandomString(6) + ".zip";
         List<MailAttachmentEntity> attachments;
         if (Objects.nonNull(dto.getMailId())) {
+            if (mailOwnershipGuard.getOwnedEmail(dto.getMailId(), currentUserId) == null) {
+                return;
+            }
             attachments = mailAttachmentService.list(new LambdaQueryWrapper<MailAttachmentEntity>().eq(MailAttachmentEntity::getEmailId, dto.getMailId()).eq(MailAttachmentEntity::getDownload, Integer.valueOf(1)));
         } else {
             attachments = mailAttachmentService.list(new LambdaQueryWrapper<MailAttachmentEntity>().in(MailAttachmentEntity::getId, dto.getAttachmentIds()).eq(MailAttachmentEntity::getDownload, Integer.valueOf(1)));
+            attachments = attachments.stream()
+                    .filter(a -> mailOwnershipGuard.getOwnedAttachment(a.getId(), currentUserId) != null)
+                    .collect(Collectors.toList());
         }
         if (CollectionUtils.isEmpty(attachments)) {
             return;
@@ -754,36 +809,33 @@ public class MailApiController {
             if (attachmentId == null) {
                 return Result.error("附未找到");
             }
-            MailAttachmentEntity attachment = mailAttachmentService.getById(attachmentId);
+            Long currentUserId = LoginUserUtil.getCurrentUserId();
+            MailAttachmentEntity attachment = mailOwnershipGuard.getOwnedAttachment(attachmentId, currentUserId);
             if (attachment == null) {
                 return Result.error("附未找到");
             }
 
-            String url =  mailFileProperties.getPath().getPath() + File.separator + attachment.getFilePath();
-
+            Path filePath = resolveMailFile(attachment.getFilePath());
+            if (StrUtil.isNotBlank(attachment.getFileCode())) {
+                String alt = attachment.getFilePath().replace("." + attachment.getFileCode(), "");
+                if (!alt.equals(attachment.getFilePath())) {
+                    filePath = resolveMailFile(alt);
+                }
+            }
 
-            // String newFileName = attachment.getFilePath().replace("."+attachment.getFileCode(),"");
             File exportDir;
             String active = environment.getProperty("spring.profiles.active");
             String port =  environment.getProperty("server.port");
             if (active.equals("dev")) {
                 exportDir = new File("D:\\mail\\tempfiles");
             } else {
-                url = url.replace("\\", "/");
                 exportDir = new File("/app/tempfiles");
             }
-            Path filePath = Paths.get(url);
             if (!exportDir.exists()) {
                 exportDir.mkdirs();
             }
 
-            Path targetPath1;
-            if (StrUtil.isNotBlank(attachment.getFileCode())) {
-                targetPath1 = Paths.get(url.replace("."+attachment.getFileCode(),""));
-            } else {
-                targetPath1 = Paths.get(url);
-            }
-            String fileName = targetPath1.getFileName().toString();
+            String fileName = filePath.getFileName().toString();
 
             Path target = Paths.get(exportDir.getAbsolutePath());
             // 创建目标目录(如果不存在)
@@ -805,6 +857,9 @@ public class MailApiController {
                 domainUrl = "http://localhost:"+port+fileUrl;
             }
             return Result.result(domainUrl);
+        } catch (IllegalArgumentException e) {
+            log.warn("download_url rejected unsafe path, attachmentId={}", attachmentId);
+            return Result.error("附未找到");
         } catch (Exception e) {
             log.error("download--error", e);
             return Result.error("附未找到");
@@ -818,12 +873,19 @@ public class MailApiController {
             if (attachmentId == null) {
                 return Result.error("附未找到");
             }
-            MailTempAttachmentEntity attachment = tempAttachmentService.getById(attachmentId);
+            Long currentUserId = LoginUserUtil.getCurrentUserId();
+            MailTempAttachmentEntity attachment = mailOwnershipGuard.getOwnedTempAttachment(attachmentId, currentUserId);
             if (attachment == null) {
                 return Result.error("附未找到");
             }
 
-            String url =  mailFileProperties.getPath().getPath() + File.separator + attachment.getFilePath();
+            Path filePath = resolveMailFile(attachment.getFilePath());
+            if (StrUtil.isNotBlank(attachment.getFileCode())) {
+                String alt = attachment.getFilePath().replace("." + attachment.getFileCode(), "");
+                if (!alt.equals(attachment.getFilePath())) {
+                    filePath = resolveMailFile(alt);
+                }
+            }
 
             File exportDir;
             String active = environment.getProperty("spring.profiles.active");
@@ -831,20 +893,12 @@ public class MailApiController {
             if (active.equals("dev")) {
                 exportDir = new File("D:\\mail\\tempfiles");
             } else {
-                url = url.replace("\\", "/");
                 exportDir = new File("/app/tempfiles");
             }
-            Path filePath = Paths.get(url);
             if (!exportDir.exists()) {
                 exportDir.mkdirs();
             }
-            Path targetPath1;
-            if (StrUtil.isNotBlank(attachment.getFileCode())) {
-                targetPath1 = Paths.get(url.replace("."+attachment.getFileCode(),""));
-            } else {
-                targetPath1 = Paths.get(url);
-            }
-            String fileName = targetPath1.getFileName().toString();
+            String fileName = filePath.getFileName().toString();
 
             Path target = Paths.get(exportDir.getAbsolutePath());
             // 创建目标目录(如果不存在)
@@ -866,6 +920,9 @@ public class MailApiController {
                 domainUrl = "http://localhost:"+port+fileUrl;
             }
             return Result.result(domainUrl);
+        } catch (IllegalArgumentException e) {
+            log.warn("draft_download_url rejected unsafe path, attachmentId={}", attachmentId);
+            return Result.error("附未找到");
         } catch (Exception e) {
             log.error("download--error", e);
             return Result.error("附未找到");
@@ -879,13 +936,13 @@ public class MailApiController {
             if (attachmentId == null) {
                 return;
             }
-            MailTempAttachmentEntity attachment = tempAttachmentService.getById(attachmentId);
+            Long currentUserId = LoginUserUtil.getCurrentUserId();
+            MailTempAttachmentEntity attachment = mailOwnershipGuard.getOwnedTempAttachment(attachmentId, currentUserId);
             if (attachment == null) {
                 return;
             }
-            InputStream inputStream;
-            String url = mailFileProperties.getPath().getPath() + attachment.getFilePath();
-            inputStream = new BufferedInputStream(new FileInputStream(url));
+            Path filePath = resolveMailFile(attachment.getFilePath());
+            InputStream inputStream = new BufferedInputStream(new FileInputStream(filePath.toFile()));
             response.reset();
             response.setContentType("application/octet-stream;charset=utf-8");
             /*
@@ -909,6 +966,8 @@ public class MailApiController {
             }
             inputStream.close();
             outputStream.close();
+        } catch (IllegalArgumentException e) {
+            log.warn("draft_download rejected unsafe path, attachmentId={}", attachmentId);
         } catch (Exception e) {
             log.error("download--error", e);
         }
@@ -921,14 +980,16 @@ public class MailApiController {
             if (attachmentId == null) {
                 return;
             }
-            MailAttachmentEntity attachment = mailAttachmentService.getById(attachmentId);
+            Long currentUserId = LoginUserUtil.getCurrentUserId();
+            MailAttachmentEntity attachment = mailOwnershipGuard.getOwnedAttachment(attachmentId, currentUserId);
             if (attachment == null) {
                 return;
             }
             InputStream inputStream;
-            String url = mailFileProperties.getPath().getPath() + attachment.getFilePath();
+            Path filePath = resolveMailFile(attachment.getFilePath());
+            String url = filePath.toString();
             if (Integer.valueOf(0).equals(attachment.getDownload())) {
-                if (new File(url).exists()) {
+                if (Files.exists(filePath)) {
                     LambdaUpdateWrapper<MailAttachmentEntity> attachmentUpdate = new LambdaUpdateWrapper<>();
                     attachmentUpdate.set(MailAttachmentEntity::getDownload, Integer.valueOf(1));
                     attachmentUpdate.eq(MailAttachmentEntity::getId, attachment.getId());
@@ -941,8 +1002,7 @@ public class MailApiController {
                 if (Objects.isNull(inputStream)) {
                     return;
                 }
-                String path = mailFileProperties.getPath().getPath() + attachment.getFilePath();
-                File file = new File(path);
+                File file = filePath.toFile();
                 try (FileOutputStream output = new FileOutputStream(file)) {
                     inputStream.transferTo(output);
                 }
@@ -998,6 +1058,8 @@ public class MailApiController {
             }
             inputStream.close();
             outputStream.close();
+        } catch (IllegalArgumentException e) {
+            log.warn("download rejected unsafe path, attachmentId={}", attachmentId);
         } catch (Exception e) {
             log.error("download--error", e);
         }
@@ -1064,4 +1126,8 @@ public class MailApiController {
         return tempFilePath;
     }
 
+    private Path resolveMailFile(String relativePath) {
+        return SafeFilePathResolver.resolveUnderBase(mailFileProperties.getPath().getPath(), relativePath);
+    }
+
 }

+ 21 - 13
storlead-api/src/main/java/com/storlead/mail/MailBlacklistRecordApiController.java → storlead-api/src/main/java/com/storlead/mail/crm/MailBlacklistRecordApiController.java

@@ -1,4 +1,4 @@
-package com.storlead.mail;
+package com.storlead.mail.crm;
 
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -8,13 +8,14 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.storlead.framework.util.LoginUserUtil;
 import com.storlead.framework.common.constant.CommonConstant;
 import com.storlead.framework.common.result.Result;
-import com.storlead.sales.mail.entity.EmailBlacklistRecordEntity;
-import com.storlead.sales.mail.entity.EmailsEntity;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.enums.EmailBoxEnum;
-import com.storlead.sales.mail.pojo.dto.EmailTemplatesDTO;
-import com.storlead.sales.mail.service.EmailBlacklistRecordService;
-import com.storlead.sales.mail.service.EmailsService;
+import com.storlead.sales.mail.crm.entity.EmailBlacklistRecordEntity;
+import com.storlead.sales.mail.crm.entity.EmailsEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.crm.enums.EmailBoxEnum;
+import com.storlead.sales.mail.crm.pojo.dto.EmailTemplatesDTO;
+import com.storlead.sales.mail.crm.service.EmailBlacklistRecordService;
+import com.storlead.sales.mail.crm.service.EmailsService;
+import com.storlead.sales.mail.crm.support.MailOwnershipGuard;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
@@ -46,6 +47,9 @@ public class MailBlacklistRecordApiController {
     @Resource
     private EmailsService emailsService;
 
+    @Resource
+    private MailOwnershipGuard mailOwnershipGuard;
+
     @PostMapping(value = "/page_list")
     @ApiOperation(value = "获取邮件模板" )
     @ApiResponses({
@@ -97,6 +101,11 @@ public class MailBlacklistRecordApiController {
         if (record != null){
             return Result.error("该邮箱已在黑名单中已存在");
         }
+        if (Objects.nonNull(entity.getId())
+                && mailOwnershipGuard.getOwnedEntity(blacklistRecordService, entity.getId(), currentUserId) == null) {
+            return Result.error("无权操作");
+        }
+        entity.setOwnerBy(currentUserId);
         Boolean b = blacklistRecordService.saveOrUpdate(entity);
         if (b) {
             /** 将黑名单邮箱的邮件移到垃圾箱中 **/
@@ -116,7 +125,8 @@ public class MailBlacklistRecordApiController {
         if(Objects.isNull(ids)) {
             return Result.error("参数错误");
         }
-        blacklistRecordService.lgDelete(Arrays.asList(ids));
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        mailOwnershipGuard.softDeleteOwned(blacklistRecordService, Arrays.asList(ids), currentUserId);
         return Result.ok();
     }
 
@@ -124,10 +134,8 @@ public class MailBlacklistRecordApiController {
     @ApiOperation("禁用或启用")
     @PostMapping("enabled")
     public Result enabled(Long id,Boolean enable) {
-        LambdaUpdateWrapper<EmailBlacklistRecordEntity> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.set(EmailBlacklistRecordEntity::getEnabled,enable);
-        updateWrapper.eq(EmailBlacklistRecordEntity::getId,id);
-        blacklistRecordService.update(updateWrapper);
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        mailOwnershipGuard.updateEnabledOwned(blacklistRecordService, id, enable, currentUserId);
         return Result.ok();
     }
 }

+ 21 - 11
storlead-api/src/main/java/com/storlead/mail/MailTemplatesApiController.java → storlead-api/src/main/java/com/storlead/mail/crm/MailTemplatesApiController.java

@@ -1,4 +1,4 @@
-package com.storlead.mail;
+package com.storlead.mail.crm;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -7,10 +7,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.storlead.framework.util.LoginUserUtil;
 import com.storlead.framework.common.constant.CommonConstant;
 import com.storlead.framework.common.result.Result;
-import com.storlead.sales.mail.entity.EmailTemplatesEntity;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.pojo.dto.EmailTemplatesDTO;
-import com.storlead.sales.mail.service.EmailTemplatesService;
+import com.storlead.sales.mail.crm.entity.EmailTemplatesEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.crm.pojo.dto.EmailTemplatesDTO;
+import com.storlead.sales.mail.crm.service.EmailTemplatesService;
+import com.storlead.sales.mail.crm.support.MailOwnershipGuard;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
@@ -39,6 +40,9 @@ public class MailTemplatesApiController {
     @Resource
     private EmailTemplatesService templatesService;
 
+    @Resource
+    private MailOwnershipGuard mailOwnershipGuard;
+
     @PostMapping(value = "/page_list")
     @ApiOperation(value = "获取邮件模板" )
     @ApiResponses({
@@ -65,7 +69,8 @@ public class MailTemplatesApiController {
             @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
     })
     public Result<?> getById(Long id) {
-        EmailTemplatesEntity templatesEntity = templatesService.getById(id);
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        EmailTemplatesEntity templatesEntity = mailOwnershipGuard.getOwnedEntity(templatesService, id, currentUserId);
         return Result.result(templatesEntity);
     }
 
@@ -97,6 +102,12 @@ public class MailTemplatesApiController {
             @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
     })
     public Result<?> save(EmailTemplatesEntity entity) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (Objects.nonNull(entity.getId())
+                && mailOwnershipGuard.getOwnedEntity(templatesService, entity.getId(), currentUserId) == null) {
+            return Result.error("无权操作");
+        }
+        entity.setOwnerBy(currentUserId);
         templatesService.saveOrUpdate(entity);
         return Result.ok();
     }
@@ -107,7 +118,8 @@ public class MailTemplatesApiController {
         if(Objects.isNull(ids)) {
             return Result.error("参数错误");
         }
-        templatesService.lgDelete(Arrays.asList(ids));
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        mailOwnershipGuard.softDeleteOwned(templatesService, Arrays.asList(ids), currentUserId);
         return Result.ok();
     }
 
@@ -115,10 +127,8 @@ public class MailTemplatesApiController {
     @ApiOperation("禁用或启用")
     @PostMapping("enabled")
     public Result enabled(Long id,Boolean enable) {
-        LambdaUpdateWrapper<EmailTemplatesEntity> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.set(EmailTemplatesEntity::getEnabled,enable);
-        updateWrapper.eq(EmailTemplatesEntity::getId,id);
-        templatesService.update(updateWrapper);
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        mailOwnershipGuard.updateEnabledOwned(templatesService, id, enable, currentUserId);
         return Result.ok();
     }
 }

+ 24 - 11
storlead-api/src/main/java/com/storlead/mail/MailboxAutoReplySetController.java → storlead-api/src/main/java/com/storlead/mail/crm/MailboxAutoReplySetController.java

@@ -1,4 +1,4 @@
-package com.storlead.mail;
+package com.storlead.mail.crm;
 
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -8,11 +8,12 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.storlead.framework.util.LoginUserUtil;
 import com.storlead.framework.common.constant.CommonConstant;
 import com.storlead.framework.common.result.Result;
-import com.storlead.sales.mail.entity.MailboxAutoReplySetEntity;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.pojo.dto.EmailTemplatesDTO;
-import com.storlead.sales.mail.service.MailboxAutoReplySetService;
-import com.storlead.sales.mail.service.SmtpPopSettingsService;
+import com.storlead.sales.mail.crm.entity.MailboxAutoReplySetEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.crm.pojo.dto.EmailTemplatesDTO;
+import com.storlead.sales.mail.crm.service.MailboxAutoReplySetService;
+import com.storlead.sales.mail.common.service.SmtpPopSettingsService;
+import com.storlead.sales.mail.crm.support.MailOwnershipGuard;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
@@ -50,6 +51,9 @@ public class MailboxAutoReplySetController {
     @Resource
     private SmtpPopSettingsService popSettingsService;
 
+    @Resource
+    private MailOwnershipGuard mailOwnershipGuard;
+
     @PostMapping(value = "/page_list")
     @ApiOperation(value = "获取邮件自动回复配置" )
     @ApiResponses({
@@ -109,6 +113,16 @@ public class MailboxAutoReplySetController {
             @ApiResponse(code = 200, message = "", response = MailboxAutoReplySetEntity.class)
     })
     public Result<?> save(MailboxAutoReplySetEntity entity) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (Objects.nonNull(entity.getId())
+                && mailOwnershipGuard.getOwnedEntity(replySetService, entity.getId(), currentUserId) == null) {
+            return Result.error("无权操作");
+        }
+        if (Objects.nonNull(entity.getSmtpPopId())
+                && mailOwnershipGuard.getOwnedSmtpPop(entity.getSmtpPopId(), currentUserId) == null) {
+            return Result.error("无权操作");
+        }
+        entity.setOwnerBy(currentUserId);
         replySetService.saveOrUpdate(entity);
         return Result.ok();
     }
@@ -119,7 +133,8 @@ public class MailboxAutoReplySetController {
         if(Objects.isNull(ids)) {
             return Result.error("参数错误");
         }
-        replySetService.lgDelete(Arrays.asList(ids));
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        mailOwnershipGuard.softDeleteOwned(replySetService, Arrays.asList(ids), currentUserId);
         return Result.ok();
     }
 
@@ -127,10 +142,8 @@ public class MailboxAutoReplySetController {
     @ApiOperation("禁用或启用")
     @PostMapping("enabled")
     public Result enabled(Long id,Boolean enable) {
-        LambdaUpdateWrapper<MailboxAutoReplySetEntity> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.set(MailboxAutoReplySetEntity::getEnabled,enable);
-        updateWrapper.eq(MailboxAutoReplySetEntity::getId,id);
-        replySetService.update(updateWrapper);
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        mailOwnershipGuard.updateEnabledOwned(replySetService, id, enable, currentUserId);
         return Result.ok();
     }
 

+ 13 - 13
storlead-api/src/main/java/com/storlead/mail/SmtpPopMailApiController.java → storlead-api/src/main/java/com/storlead/mail/crm/SmtpPopMailApiController.java

@@ -1,4 +1,4 @@
-package com.storlead.mail;//package com.storlead.sales.mail;
+package com.storlead.mail.crm;//package com.storlead.sales.mail;
 //
 //import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 //import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -8,18 +8,18 @@ package com.storlead.mail;//package com.storlead.sales.mail;
 //import com.storlead.common.util.encryptor.AccessKeyEncryptor;
 //import com.storlead.frame.auth.util.LoginUserUtil;
 //import com.storlead.frame.core.assemble.Result;
-//import com.storlead.sales.mail.connection.MailConnection;
-//import com.storlead.sales.mail.connection.client.MailConnectionUtil;
-//import com.storlead.sales.mail.connection.config.MailProperties;
-//import com.storlead.sales.mail.entity.EmailsEntity;
-//import com.storlead.sales.mail.entity.MailAttachmentEntity;
-//import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-//import com.storlead.sales.mail.pojo.MailDTO;
-//import com.storlead.sales.mail.pojo.SendMailDTO;
-//import com.storlead.sales.mail.properties.MailFileProperties;
-//import com.storlead.sales.mail.service.EmailsService;
-//import com.storlead.sales.mail.service.MailAttachmentService;
-//import com.storlead.sales.mail.service.SmtpPopSettingsService;
+//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.crm.entity.EmailsEntity;
+//import com.storlead.sales.mail.crm.entity.MailAttachmentEntity;
+//import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+//import com.storlead.sales.mail.crm.pojo.MailDTO;
+//import com.storlead.sales.mail.crm.pojo.SendMailDTO;
+//import com.storlead.sales.mail.common.properties.MailFileProperties;
+//import com.storlead.sales.mail.crm.service.EmailsService;
+//import com.storlead.sales.mail.crm.service.MailAttachmentService;
+//import com.storlead.sales.mail.common.service.SmtpPopSettingsService;
 //import com.sun.mail.imap.IMAPFolder;
 //import io.swagger.annotations.Api;
 //import io.swagger.annotations.ApiOperation;

+ 9 - 8
storlead-api/src/main/java/com/storlead/mail/ThumbnailPreviewController.java → storlead-api/src/main/java/com/storlead/mail/crm/ThumbnailPreviewController.java

@@ -1,4 +1,4 @@
-package com.storlead.mail;
+package com.storlead.mail.crm;
 
 import com.storlead.framework.web.properties.FileProperties;
 import io.swagger.annotations.Api;
@@ -16,9 +16,12 @@ import javax.imageio.ImageWriteParam;
 import javax.imageio.ImageWriter;
 import javax.imageio.stream.ImageOutputStream;
 import java.awt.image.BufferedImage;
+import com.storlead.sales.mail.common.util.SafeFilePathResolver;
+
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.Path;
 import java.util.Iterator;
 
 /**
@@ -40,13 +43,8 @@ public class ThumbnailPreviewController {
     public ResponseEntity<byte[]> thumbnail(@RequestParam String url) throws Exception {
 
         try {
-            // 1. 构建文件路径
-            String fileUrl = fileProperties.getPath().getPath() + url;
-            String normalizedPath = fileUrl.replace('/', File.separatorChar)
-                    .replace('\\', File.separatorChar);
-
-            // 2. 读取原始图片
-            BufferedImage originalImage = ImageIO.read(new File(normalizedPath));
+            Path filePath = SafeFilePathResolver.resolveUnderBase(fileProperties.getPath().getPath(), url);
+            BufferedImage originalImage = ImageIO.read(filePath.toFile());
             if (originalImage == null) {
                 return ResponseEntity.notFound().build();
             }
@@ -57,6 +55,9 @@ public class ThumbnailPreviewController {
                     .contentType(MediaType.IMAGE_JPEG)
                     .body(compressedImage);
 
+        } catch (IllegalArgumentException e) {
+            log.warn("thumbnail rejected unsafe path: {}", url);
+            return ResponseEntity.badRequest().build();
         } catch (Exception e) {
             log.error("thumbnail error", e);
             return ResponseEntity.notFound().build();

+ 20 - 12
storlead-api/src/main/java/com/storlead/mail/UserEmailFolderApiController.java → storlead-api/src/main/java/com/storlead/mail/crm/UserEmailFolderApiController.java

@@ -1,4 +1,4 @@
-package com.storlead.mail;
+package com.storlead.mail.crm;
 
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -8,12 +8,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.storlead.framework.util.LoginUserUtil;
 import com.storlead.framework.common.constant.CommonConstant;
 import com.storlead.framework.common.result.Result;
-import com.storlead.sales.mail.entity.EmailsEntity;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.entity.UserEmailFolderEntity;
-import com.storlead.sales.mail.pojo.dto.EmailTemplatesDTO;
-import com.storlead.sales.mail.service.EmailsService;
-import com.storlead.sales.mail.service.UserEmailFolderService;
+import com.storlead.sales.mail.crm.entity.EmailsEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.crm.entity.UserEmailFolderEntity;
+import com.storlead.sales.mail.crm.pojo.dto.EmailTemplatesDTO;
+import com.storlead.sales.mail.crm.service.EmailsService;
+import com.storlead.sales.mail.crm.service.UserEmailFolderService;
+import com.storlead.sales.mail.crm.support.MailOwnershipGuard;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
@@ -45,6 +46,9 @@ public class UserEmailFolderApiController {
     @Resource
     private EmailsService emailsService;
 
+    @Resource
+    private MailOwnershipGuard mailOwnershipGuard;
+
     @PostMapping(value = "/page_list")
     @ApiOperation(value = "获取用户文件夹(分页)" )
     @ApiResponses({
@@ -94,6 +98,9 @@ public class UserEmailFolderApiController {
                 return Result.error("文件夹'"+ entity.getFolderName() +"'已存在!");
             }
         } else {
+            if (mailOwnershipGuard.getOwnedEntity(emailFolderService, entity.getId(), currentUserId) == null) {
+                return Result.error("无权操作");
+            }
             UserEmailFolderEntity oldFolder = emailFolderService.getOne(queryWrapper);
             if (Objects.nonNull(oldFolder)) {
                 if (!oldFolder.getId().equals(entity.getId())) {
@@ -101,6 +108,7 @@ public class UserEmailFolderApiController {
                 }
             }
         }
+        entity.setOwnerBy(currentUserId);
         emailFolderService.saveOrUpdate(entity);
         return Result.ok();
     }
@@ -111,13 +119,15 @@ public class UserEmailFolderApiController {
         if(Objects.isNull(ids)) {
             return Result.error("参数错误");
         }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
         /**
          * 需要修改邮件文件夹标记为''
          */
-        emailFolderService.lgDelete(Arrays.asList(ids));
+        mailOwnershipGuard.softDeleteOwned(emailFolderService, Arrays.asList(ids), currentUserId);
 
         LambdaUpdateWrapper<EmailsEntity> updateWrapper = new LambdaUpdateWrapper<>();
         updateWrapper.in(EmailsEntity::getCustomFolderId,Arrays.asList(ids));
+        updateWrapper.eq(EmailsEntity::getOwnerBy, currentUserId);
         updateWrapper.set(EmailsEntity::getCustomFolderId,null);
         emailsService.update(updateWrapper);
         return Result.ok();
@@ -127,10 +137,8 @@ public class UserEmailFolderApiController {
     @ApiOperation("禁用或启用")
     @PostMapping("enabled")
     public Result enabled(Long id,Boolean enable) {
-        LambdaUpdateWrapper<UserEmailFolderEntity> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.set(UserEmailFolderEntity::getEnabled,enable);
-        updateWrapper.eq(UserEmailFolderEntity::getId,id);
-        emailFolderService.update(updateWrapper);
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        mailOwnershipGuard.updateEnabledOwned(emailFolderService, id, enable, currentUserId);
         return Result.ok();
     }
 }

+ 65 - 0
storlead-api/src/main/java/com/storlead/mail/mkt/MktMailApiController.java

@@ -0,0 +1,65 @@
+package com.storlead.mail.mkt;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.storlead.framework.common.result.Result;
+import com.storlead.framework.util.LoginUserUtil;
+import com.storlead.sales.mail.mkt.entity.MktMailMessageEntity;
+import com.storlead.sales.mail.mkt.pojo.MktMailQueryDTO;
+import com.storlead.sales.mail.mkt.pojo.MktSendMailDTO;
+import com.storlead.sales.mail.mkt.service.MktMailMessageService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.Base64;
+import java.util.Objects;
+
+/**
+ * 营销邮件 API(与 CRM /mail 隔离)。
+ */
+@RestController
+@RequestMapping("/mail/mkt")
+@Api(tags = "021.营销邮件接口")
+public class MktMailApiController {
+
+    private static final byte[] PIXEL_GIF = Base64.getDecoder().decode(
+            "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
+
+    @Resource
+    private MktMailMessageService mktMailMessageService;
+
+    @PostMapping("/send")
+    @ApiOperation("发送营销邮件(单封)")
+    public Result<?> send(@RequestBody MktSendMailDTO dto) {
+        Long userId = LoginUserUtil.getCurrentUserId();
+        if (Objects.isNull(userId)) {
+            return Result.error("未登录");
+        }
+        MktMailMessageEntity entity = mktMailMessageService.send(dto, userId);
+        return Result.result(entity);
+    }
+
+    @PostMapping("/page_list")
+    @ApiOperation("营销邮件投递分页")
+    public Result<?> pageList(@RequestBody MktMailQueryDTO query) {
+        IPage<MktMailMessageEntity> page = mktMailMessageService.pageList(query);
+        return Result.result(page);
+    }
+
+    @PostMapping("/detail")
+    @ApiOperation("营销邮件详情")
+    public Result<?> detail(@RequestParam Long id) {
+        MktMailMessageEntity entity = mktMailMessageService.getById(id);
+        return Result.result(entity);
+    }
+
+    @GetMapping(value = "/track/{token}", produces = MediaType.IMAGE_GIF_VALUE)
+    @ApiOperation("打开追踪像素")
+    public ResponseEntity<byte[]> track(@PathVariable("token") String token) {
+        mktMailMessageService.markOpened(token);
+        return ResponseEntity.ok().contentType(MediaType.IMAGE_GIF).body(PIXEL_GIF);
+    }
+}

+ 19 - 10
storlead-api/src/main/resources/application-dev.yml

@@ -1,10 +1,10 @@
 server:
-  port: 10020
+  port: 10080
   tomcat:
     max-swallow-size: -1
     basedir: /app/temp
   servlet:
-    context-path: /router/rest
+    context-path: /router/rest/
   compression:
     enabled: true
     min-response-size: 1024
@@ -147,11 +147,20 @@ environment: test
 # 站内消息、邮件模板中的前端站点根地址(覆盖 application.yml 默认值)
 domainname: https://test1.storlead.com
 
-storlead:
-  es:
-    enabled: false
-    host: 39.108.252.62
-    port: 9200
-    scheme: http
-    username: elastic
-    password: storlead123456
+file:
+  mode: 1
+  filePath: /files
+  active: test
+  mac:
+    path: ~/file/
+    avatar: ~/avatar/
+  linux:
+    path: /mnt/vdb/storlead/sales/file/email/attachments/
+    avatar: /mnt/vdb/storlead/sales/file/avatar/
+    jpeg: /mnt/vdb/storlead/sales/file/email/image/
+  windows:
+    path: D:\images\file\
+    avatar: D:\images\
+  # 文件大小 /M
+  maxSize: 100
+  avatarMaxSize: 5

+ 30 - 17
storlead-api/src/main/resources/application-test.yml

@@ -1,5 +1,5 @@
 server:
-  port: 10020
+  port: 10080
   tomcat:
     max-swallow-size: -1
     basedir: /app/sp/smarttrade/temp/${spring.profiles.active}
@@ -42,9 +42,9 @@ spring:
       - classpath:/templates
   # 设置静态文件路径,js,css等  #redis 配置
   redis:
-    host: test1.storlead.com
+    host: test1.storlead.com #test1.storlead.com
     port: 59394
-    database: 14
+    database: 10
     lettuce:
       pool:
         max-wait: 100000
@@ -52,6 +52,7 @@ spring:
         max-active: 100
     timeout: 5000
     password: bnoCWkyDqYA*ecT7FoL7
+
   mvc:
     static-path-pattern: /**
   resource:
@@ -90,24 +91,14 @@ spring:
           username: root
           password: rCgRgLjH99Xvg5BN
           driver-class-name: com.mysql.jdbc.Driver
-        sales:
-          driver-class-name: com.mysql.jdbc.Driver
-          url: jdbc:mysql://mysql.test.storlead.com:39091/sp_sales_test?useSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
-          username: root
-          password: rCgRgLjH99Xvg5BN
-        management:
-          driver-class-name: com.mysql.jdbc.Driver
-          url: jdbc:mysql://mysql.test.storlead.com:39091/storlead_test?useSSL=false&autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&noDatetimeStringSync=true&serverTimezone=Asia/Shanghai
-          username: root
-          password: rCgRgLjH99Xvg5BN
 
 #mybatis plus 设置
 mybatis-plus:
   mapper-locations: classpath*:/mapper/*Mapper.xml,classpath*:/mapper/*/*Mapper.xml
   # 实体扫描,多个 package 用逗号或者分号分隔
-  type-aliases-package: com.storlead.tems.modules.*.entity
-  type-enums-package:
-    #  configuration:
+  type-aliases-package:
+  typeEnumsPackage:
+  #  configuration:
   #配置显示查询SQL
   #    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
   #    default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler
@@ -127,7 +118,7 @@ mybatis-plus:
 logging:
   file:
     # 日志存放目录
-    path: /app/sp/okr/${spring.profiles.active}/log
+    path: /app/sp/${spring.application.name}/log
   level:
     root: info
     io:
@@ -150,4 +141,26 @@ logging:
     com:
       storlead: debug
 
+
+environment: test
+
+# 站内消息、邮件模板中的前端站点根地址(覆盖 application.yml 默认值)
 domainname: https://test1.storlead.com
+
+file:
+  mode: 1
+  filePath: /files
+  active: test
+  mac:
+    path: ~/file/
+    avatar: ~/avatar/
+  linux:
+    path: /mnt/vdb/storlead/sales/file/email/attachments/
+    avatar: /mnt/vdb/storlead/sales/file/avatar/
+    jpeg: /mnt/vdb/storlead/sales/file/email/image/
+  windows:
+    path: D:\images\file\
+    avatar: D:\images\
+  # 文件大小 /M
+  maxSize: 100
+  avatarMaxSize: 5

+ 8 - 4
storlead-api/src/main/resources/application.yml

@@ -58,8 +58,12 @@ storlead:
     module-default-enabled: true
     module-defaults:
       - packages:
-          - com.storlead.sales.mail.service
-          - com.storlead.sales.mail.mapper
-          - com.storlead.sales.mail.integration.service
-          - com.storlead.sales.mail.integration.mapper
+          - com.storlead.sales.mail.common.service
+          - com.storlead.sales.mail.common.mapper
+          - com.storlead.sales.mail.crm.service
+          - com.storlead.sales.mail.crm.mapper
+          - com.storlead.sales.mail.crm.integration.service
+          - com.storlead.sales.mail.crm.integration.mapper
+          - com.storlead.sales.mail.mkt.service
+          - com.storlead.sales.mail.mkt.mapper
         datasource: master

+ 32 - 0
storlead-mail/README.md

@@ -0,0 +1,32 @@
+# storlead-mail 子模块说明
+
+邮件服务拆为三个 Maven 子模块,避免 CRM 与营销业务混在一起。
+
+## 模块
+
+| 模块 | Artifact | 职责 |
+|------|----------|------|
+| common | `storlead-mail-common` | 账户(`smtp_pop_settings`)、SMTP/IMAP 连接、公共投递、`MailSceneEnum` |
+| crm | `storlead-mail-crm` | CRM 个人邮箱:`emails` / `client_sent_emails`、收信、文件夹、CRM 集成任务 |
+| mkt | `storlead-mail-mkt` | 营销投递:`mkt_mail_message`、发送与打开追踪 |
+
+依赖方向:`crm` → `common`,`mkt` → `common`,**crm 与 mkt 互不依赖**。
+
+## 包名
+
+- `com.storlead.sales.mail.common.*`
+- `com.storlead.sales.mail.crm.*`
+- `com.storlead.sales.mail.mkt.*`
+
+API:
+
+- `com.storlead.mail.common` — 账户配置
+- `com.storlead.mail.crm` — CRM 邮件接口(原 `/mail/**`)
+- `com.storlead.mail.mkt` — 营销接口(`/mail/mkt/**`)
+
+## 库表变更
+
+执行:`storlead-mail-common/src/main/resources/sql/mail_scene_and_mkt.sql`
+
+- `smtp_pop_settings` 增加 `scene` / `account_scope` / `org_id` 等
+- 新建 `mkt_mail_message`

+ 7 - 39
storlead-mail/pom.xml

@@ -12,45 +12,13 @@
     </parent>
 
     <artifactId>storlead-mail</artifactId>
-    <packaging>jar</packaging>
+    <packaging>pom</packaging>
     <name>storlead-mail</name>
+    <description>Mail service aggregator: common / crm / mkt</description>
 
-    <dependencies>
-        <dependency>
-            <groupId>com.storlead.boot</groupId>
-            <artifactId>storlead-mybatis</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.storlead.boot</groupId>
-            <artifactId>storlead-redis</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.storlead.boot</groupId>
-            <artifactId>storlead-common</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.storlead.boot</groupId>
-            <artifactId>storlead-core</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.storlead.boot</groupId>
-            <artifactId>storlead-web</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.sun.mail</groupId>
-            <artifactId>javax.mail</artifactId>
-            <version>1.6.2</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <scope>provided</scope>
-        </dependency>
-    </dependencies>
+    <modules>
+        <module>storlead-mail-common</module>
+        <module>storlead-mail-crm</module>
+        <module>storlead-mail-mkt</module>
+    </modules>
 </project>

+ 0 - 85
storlead-mail/src/main/java/com/storlead/sales/mail/integration/scheduler/MailIntegrationTaskScheduler.java

@@ -1,85 +0,0 @@
-package com.storlead.sales.mail.integration.scheduler;
-
-import cn.hutool.core.util.StrUtil;
-import com.storlead.sales.mail.integration.config.MailIntegrationProperties;
-import com.storlead.sales.mail.integration.entity.MailIntegrationTaskEntity;
-import com.storlead.sales.mail.integration.enums.MailIntegrationTaskStatus;
-import com.storlead.sales.mail.integration.enums.MailIntegrationTaskType;
-import com.storlead.sales.mail.integration.handler.CrmMailSyncHandler;
-import com.storlead.sales.mail.integration.handler.NewMailRemindHandler;
-import com.storlead.sales.mail.integration.mapper.MailIntegrationTaskMapper;
-import lombok.extern.log4j.Log4j2;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-import org.springframework.util.CollectionUtils;
-
-import javax.annotation.Resource;
-import java.util.Date;
-import java.util.List;
-
-@Log4j2
-@Component
-public class MailIntegrationTaskScheduler {
-
-    @Resource
-    private MailIntegrationProperties properties;
-    @Resource
-    private MailIntegrationTaskMapper mailIntegrationTaskMapper;
-    @Resource
-    private CrmMailSyncHandler crmMailSyncHandler;
-    @Resource
-    private NewMailRemindHandler newMailRemindHandler;
-
-    @Scheduled(fixedDelayString = "${storlead.mail.integration.poll-interval-ms:30000}")
-    public void processPendingTasks() {
-        if (!properties.isEnabled() || !properties.isInvokeExternalBeans()) {
-            return;
-        }
-        List<MailIntegrationTaskEntity> tasks =
-                mailIntegrationTaskMapper.selectPendingTasks(properties.getBatchSize());
-        if (CollectionUtils.isEmpty(tasks)) {
-            return;
-        }
-        for (MailIntegrationTaskEntity task : tasks) {
-            processOne(task);
-        }
-    }
-
-    private void processOne(MailIntegrationTaskEntity task) {
-        int claimed = mailIntegrationTaskMapper.claimTask(
-                task.getId(),
-                MailIntegrationTaskStatus.PENDING.getCode(),
-                MailIntegrationTaskStatus.PROCESSING.getCode());
-        if (claimed == 0) {
-            return;
-        }
-        try {
-            MailIntegrationTaskType type = MailIntegrationTaskType.fromCode(task.getTaskType());
-            switch (type) {
-                case CRM_SYNC:
-                    crmMailSyncHandler.execute(task.getMailIds(), task.getOwnerBy());
-                    break;
-                case NEW_REMIND:
-                    newMailRemindHandler.execute(task.getMailIds(), task.getOwnerBy());
-                    break;
-                default:
-                    throw new IllegalStateException("Unsupported task type: " + task.getTaskType());
-            }
-            markFinished(task.getId(), MailIntegrationTaskStatus.SUCCESS, null);
-        } catch (Exception e) {
-            log.error("mail integration task failed, id={}, type={}", task.getId(), task.getTaskType(), e);
-            String msg = StrUtil.sub(e.getMessage(), 0, 1900);
-            markFinished(task.getId(), MailIntegrationTaskStatus.FAILED, msg);
-        }
-    }
-
-    private void markFinished(Long id, MailIntegrationTaskStatus status, String errorMsg) {
-        MailIntegrationTaskEntity update = new MailIntegrationTaskEntity();
-        update.setId(id);
-        update.setTaskStatus(status.getCode());
-        update.setErrorMsg(errorMsg);
-        update.setProcessedAt(new Date());
-        update.setUpdateTime(new Date());
-        mailIntegrationTaskMapper.updateById(update);
-    }
-}

+ 0 - 67
storlead-mail/src/main/java/com/storlead/sales/mail/service/impl/SmtpPopSettingsServiceImpl.java

@@ -1,67 +0,0 @@
-package com.storlead.sales.mail.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.storlead.framework.common.constant.CommonConstant;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.mapper.SmtpPopSettingsMapper;
-import com.storlead.sales.mail.service.SmtpPopSettingsService;
-import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * <p>
- * 邮箱smtp_setting 服务实现类
- * </p>
- *
- * @author chenkq
- * @since 2024-05-28
- */
-@Service
-public class SmtpPopSettingsServiceImpl extends MyBaseServiceImpl<SmtpPopSettingsMapper, SmtpPopSettingsEntity> implements SmtpPopSettingsService {
-
-    @Override
-    public SmtpPopSettingsEntity getDefaultSmtpPop(Long userId) {
-        LambdaQueryWrapper<SmtpPopSettingsEntity> wrapper = new LambdaQueryWrapper();
-        wrapper.eq(SmtpPopSettingsEntity::getOwnerBy,userId);
-        wrapper.eq(SmtpPopSettingsEntity::getIsDelete,CommonConstant.DEL_FLAG_0);
-        wrapper.eq(SmtpPopSettingsEntity::getUseDefault,Integer.valueOf(1));
-        wrapper.last(" limit 1");
-        SmtpPopSettingsEntity entity = this.getOne(wrapper);
-        return entity;
-    }
-
-    @Override
-    public SmtpPopSettingsEntity getSystemSmtpPop(Long popId) {
-        SmtpPopSettingsEntity entity = this.getById(popId);
-        return entity;
-    }
-
-    @Override
-    public List<SmtpPopSettingsEntity> getDefaultSmtpPopls(Set userIds){
-        LambdaQueryWrapper<SmtpPopSettingsEntity> wrapper = new LambdaQueryWrapper();
-        wrapper.in(SmtpPopSettingsEntity::getOwnerBy,userIds);
-        wrapper.eq(SmtpPopSettingsEntity::getUseDefault,Integer.valueOf(1));
-        List<SmtpPopSettingsEntity> entityls = this.list(wrapper);
-        return entityls;
-    }
-    @Override
-    public List<SmtpPopSettingsEntity> getEmailAccount(Long userId) {
-        LambdaQueryWrapper<SmtpPopSettingsEntity> wrapper = new LambdaQueryWrapper();
-        wrapper.eq(SmtpPopSettingsEntity::getOwnerBy,userId);
-        wrapper.eq(SmtpPopSettingsEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
-        return this.list(wrapper);
-    }
-
-    @Override
-    public SmtpPopSettingsEntity getEmailByAccountPopId(Long userId, Long popId) {
-        LambdaQueryWrapper<SmtpPopSettingsEntity> wrapper = new LambdaQueryWrapper();
-        wrapper.eq(SmtpPopSettingsEntity::getOwnerBy,userId);
-        wrapper.eq(SmtpPopSettingsEntity::getId,popId);
-        wrapper.eq(SmtpPopSettingsEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
-        wrapper.last("limit 1");
-        return this.getOne(wrapper);
-    }
-}

+ 0 - 2
storlead-mail/src/main/resources/META-INF/spring.factories

@@ -1,2 +0,0 @@
-#org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-#  com.storlead.sales.mail.properties.FileProperties

+ 51 - 0
storlead-mail/storlead-mail-common/pom.xml

@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.storlead.boot</groupId>
+        <artifactId>storlead-mail</artifactId>
+        <version>1.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>storlead-mail-common</artifactId>
+    <packaging>jar</packaging>
+    <name>storlead-mail-common</name>
+    <description>Shared mail account, connection and transport capabilities</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.storlead.boot</groupId>
+            <artifactId>storlead-mybatis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.storlead.boot</groupId>
+            <artifactId>storlead-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.storlead.boot</groupId>
+            <artifactId>storlead-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.storlead.boot</groupId>
+            <artifactId>storlead-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.storlead.boot</groupId>
+            <artifactId>storlead-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.mail</groupId>
+            <artifactId>javax.mail</artifactId>
+            <version>1.6.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/connection/IMAPConnection.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/IMAPConnection.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.connection;
+package com.storlead.sales.mail.common.connection;
 
 import com.sun.mail.imap.IMAPFolder;
 import lombok.extern.log4j.Log4j2;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/connection/IMAPConnectionFactory.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/IMAPConnectionFactory.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.connection;
+package com.storlead.sales.mail.common.connection;
 
 /**
  * @program: sp-sales-platform

+ 1 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/connection/MailConnection.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/MailConnection.java

@@ -1,6 +1,5 @@
-package com.storlead.sales.mail.connection;
+package com.storlead.sales.mail.common.connection;
 
-import com.storlead.sales.mail.entity.EmailsEntity;
 import com.sun.mail.pop3.POP3Folder;
 
 import javax.mail.Folder;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/connection/MailConnectionFactory.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/MailConnectionFactory.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.connection;
+package com.storlead.sales.mail.common.connection;
 
 /**
  * @program: sp-sales-platform

+ 1 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/connection/POP3Connection.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/POP3Connection.java

@@ -1,6 +1,5 @@
-package com.storlead.sales.mail.connection;
+package com.storlead.sales.mail.common.connection;
 
-import com.storlead.sales.mail.entity.EmailsEntity;
 import com.sun.mail.imap.IMAPFolder;
 import com.sun.mail.pop3.POP3Folder;
 import com.sun.mail.pop3.POP3Store;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/connection/POP3ConnectionFactory.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/POP3ConnectionFactory.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.connection;
+package com.storlead.sales.mail.common.connection;
 
 /**
  * @program: sp-sales-platform

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/connection/SMTPConnection.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/SMTPConnection.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.connection;
+package com.storlead.sales.mail.common.connection;
 
 /**
  * @program: sp-sales-platform

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/connection/SMTPConnectionFactory.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/SMTPConnectionFactory.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.connection;
+package com.storlead.sales.mail.common.connection;
 
 /**
  * @program: sp-sales-platform

+ 3 - 3
storlead-mail/src/main/java/com/storlead/sales/mail/connection/client/MailConnectionUtil.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/client/MailConnectionUtil.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.connection.client;
+package com.storlead.sales.mail.common.connection.client;
 
 /**
  * @program: sp-sales-platform
@@ -6,8 +6,8 @@ package com.storlead.sales.mail.connection.client;
  * @author: chenkq
  * @create: 2024-05-30 16:26
  */
-import com.storlead.sales.mail.connection.*;
-import com.storlead.sales.mail.connection.config.MailProperties;
+import com.storlead.sales.mail.common.connection.*;
+import com.storlead.sales.mail.common.connection.config.MailProperties;
 import lombok.extern.log4j.Log4j2;
 
 import javax.mail.*;

+ 3 - 3
storlead-mail/src/main/java/com/storlead/sales/mail/connection/client/MailReceiverUtil.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/client/MailReceiverUtil.java

@@ -1,7 +1,7 @@
-package com.storlead.sales.mail.connection.client;
+package com.storlead.sales.mail.common.connection.client;
 
-import com.storlead.sales.mail.connection.MailConnection;
-import com.storlead.sales.mail.connection.MailConnectionFactory;
+import com.storlead.sales.mail.common.connection.MailConnection;
+import com.storlead.sales.mail.common.connection.MailConnectionFactory;
 
 import javax.mail.*;
 import java.util.Arrays;

+ 4 - 4
storlead-mail/src/main/java/com/storlead/sales/mail/connection/client/MailSenderUtil.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/client/MailSenderUtil.java

@@ -1,8 +1,8 @@
-package com.storlead.sales.mail.connection.client;
+package com.storlead.sales.mail.common.connection.client;
 
-import com.storlead.sales.mail.connection.MailConnectionFactory;
-import com.storlead.sales.mail.connection.SMTPConnection;
-import com.storlead.sales.mail.connection.SMTPConnectionFactory;
+import com.storlead.sales.mail.common.connection.MailConnectionFactory;
+import com.storlead.sales.mail.common.connection.SMTPConnection;
+import com.storlead.sales.mail.common.connection.SMTPConnectionFactory;
 
 import javax.mail.MessagingException;
 

+ 2 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/connection/config/MailProperties.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/connection/config/MailProperties.java

@@ -1,7 +1,7 @@
-package com.storlead.sales.mail.connection.config;
+package com.storlead.sales.mail.common.connection.config;
 
 import com.storlead.framework.common.util.encryptor.AccessKeyEncryptor;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
 import lombok.Data;
 
 /**

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/MailServerPortConfigEntity.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/entity/MailServerPortConfigEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.common.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 21 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/SmtpPopSettingsEntity.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/entity/SmtpPopSettingsEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.common.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;
@@ -113,4 +113,24 @@ public class SmtpPopSettingsEntity extends SysBaseField {
     @ApiModelProperty(value = "错误次数")
     @TableField("connect_error_count")
     private Integer connectErrorCount;
+
+    @ApiModelProperty(value = "场景:CRM / MKT")
+    @TableField("scene")
+    private String scene;
+
+    @ApiModelProperty(value = "账户范围:PERSONAL / ORG")
+    @TableField("account_scope")
+    private String accountScope;
+
+    @ApiModelProperty(value = "组织ID(组织级营销账号)")
+    @TableField("org_id")
+    private Long orgId;
+
+    @ApiModelProperty(value = "日发送上限,空表示不限制")
+    @TableField("daily_send_limit")
+    private Integer dailySendLimit;
+
+    @ApiModelProperty(value = "是否允许收信:1是 0否")
+    @TableField("enable_receive")
+    private Integer enableReceive;
 }

+ 33 - 0
storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/enums/AccountScopeEnum.java

@@ -0,0 +1,33 @@
+package com.storlead.sales.mail.common.enums;
+
+import lombok.Getter;
+
+/**
+ * 邮箱账户归属范围。
+ */
+@Getter
+public enum AccountScopeEnum {
+
+    PERSONAL("PERSONAL", "个人账户"),
+    ORG("ORG", "组织账户");
+
+    private final String code;
+    private final String desc;
+
+    AccountScopeEnum(String code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public static AccountScopeEnum of(String code) {
+        if (code == null || code.trim().isEmpty()) {
+            return PERSONAL;
+        }
+        for (AccountScopeEnum value : values()) {
+            if (value.code.equalsIgnoreCase(code.trim())) {
+                return value;
+            }
+        }
+        return PERSONAL;
+    }
+}

+ 41 - 0
storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/enums/MailSceneEnum.java

@@ -0,0 +1,41 @@
+package com.storlead.sales.mail.common.enums;
+
+import lombok.Getter;
+
+/**
+ * 邮件场景:区分 CRM 个人邮箱与营销发信通道。
+ */
+@Getter
+public enum MailSceneEnum {
+
+    CRM("CRM", "CRM业务邮件"),
+    MKT("MKT", "营销邮件");
+
+    private final String code;
+    private final String desc;
+
+    MailSceneEnum(String code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public static MailSceneEnum of(String code) {
+        if (code == null || code.trim().isEmpty()) {
+            return CRM;
+        }
+        for (MailSceneEnum value : values()) {
+            if (value.code.equalsIgnoreCase(code.trim())) {
+                return value;
+            }
+        }
+        return CRM;
+    }
+
+    public static boolean isCrm(String code) {
+        return CRM == of(code);
+    }
+
+    public static boolean isMkt(String code) {
+        return MKT == of(code);
+    }
+}

+ 2 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/mapper/MailServerPortConfigMapper.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/mapper/MailServerPortConfigMapper.java

@@ -1,6 +1,6 @@
-package com.storlead.sales.mail.mapper;
+package com.storlead.sales.mail.common.mapper;
 
-import com.storlead.sales.mail.entity.MailServerPortConfigEntity;
+import com.storlead.sales.mail.common.entity.MailServerPortConfigEntity;
 import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 
 /**

+ 2 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/mapper/SmtpPopSettingsMapper.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/mapper/SmtpPopSettingsMapper.java

@@ -1,6 +1,6 @@
-package com.storlead.sales.mail.mapper;
+package com.storlead.sales.mail.common.mapper;
 
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
 import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 
 /**

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/properties/MailFileProperties.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/properties/MailFileProperties.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.properties;
+package com.storlead.sales.mail.common.properties;
 
 import lombok.Data;
 import org.springframework.boot.context.properties.ConfigurationProperties;

+ 37 - 0
storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/MailAccountBizService.java

@@ -0,0 +1,37 @@
+package com.storlead.sales.mail.common.service;
+
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.common.enums.MailSceneEnum;
+
+import java.util.List;
+
+/**
+ * 公共邮箱账户业务:按场景查询与校验,供 CRM / MKT 复用。
+ */
+public interface MailAccountBizService {
+
+    /**
+     * 获取用户默认账户(指定场景,默认 CRM)。
+     */
+    SmtpPopSettingsEntity getDefaultAccount(Long userId, String scene);
+
+    /**
+     * 获取用户账户列表(指定场景)。
+     */
+    List<SmtpPopSettingsEntity> listAccounts(Long userId, String scene);
+
+    /**
+     * 按组织获取营销账户。
+     */
+    List<SmtpPopSettingsEntity> listOrgAccounts(Long orgId, String scene);
+
+    /**
+     * 校验账户存在、未删除,且场景匹配。
+     */
+    SmtpPopSettingsEntity requireAccount(Long accountId, MailSceneEnum scene);
+
+    /**
+     * 校验用户对账户的个人归属,且场景匹配。
+     */
+    SmtpPopSettingsEntity requireOwnedAccount(Long accountId, Long userId, MailSceneEnum scene);
+}

+ 2 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/service/MailServerPortConfigService.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/MailServerPortConfigService.java

@@ -1,6 +1,6 @@
-package com.storlead.sales.mail.service;
+package com.storlead.sales.mail.common.service;
 
-import com.storlead.sales.mail.entity.MailServerPortConfigEntity;
+import com.storlead.sales.mail.common.entity.MailServerPortConfigEntity;
 import com.storlead.framework.mybatis.service.MyBaseService;
 
 /**

+ 12 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/service/SmtpPopSettingsService.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/SmtpPopSettingsService.java

@@ -1,6 +1,6 @@
-package com.storlead.sales.mail.service;
+package com.storlead.sales.mail.common.service;
 
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
 import com.storlead.framework.mybatis.service.MyBaseService;
 
 import java.util.List;
@@ -16,13 +16,23 @@ import java.util.Set;
  */
 public interface SmtpPopSettingsService extends MyBaseService<SmtpPopSettingsEntity> {
 
+    /**
+     * 默认取 CRM 场景账户(兼容存量调用)。
+     */
     SmtpPopSettingsEntity getDefaultSmtpPop(Long userId);
 
+    SmtpPopSettingsEntity getDefaultSmtpPop(Long userId, String scene);
+
     SmtpPopSettingsEntity getSystemSmtpPop(Long popId);
 
     List<SmtpPopSettingsEntity> getDefaultSmtpPopls(Set<Long> userIds);
 
+    /**
+     * 默认取 CRM 场景账户列表(兼容存量调用)。
+     */
     List<SmtpPopSettingsEntity> getEmailAccount(Long userId);
 
+    List<SmtpPopSettingsEntity> getEmailAccount(Long userId, String scene);
+
     SmtpPopSettingsEntity getEmailByAccountPopId(Long userId,Long popId);
 }

+ 107 - 0
storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/impl/MailAccountBizServiceImpl.java

@@ -0,0 +1,107 @@
+package com.storlead.sales.mail.common.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.storlead.framework.common.constant.CommonConstant;
+import com.storlead.framework.web.exception.WebException;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.common.enums.MailSceneEnum;
+import com.storlead.sales.mail.common.service.MailAccountBizService;
+import com.storlead.sales.mail.common.service.SmtpPopSettingsService;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+
+@Service
+public class MailAccountBizServiceImpl implements MailAccountBizService {
+
+    @Resource
+    private SmtpPopSettingsService smtpPopSettingsService;
+
+    @Override
+    public SmtpPopSettingsEntity getDefaultAccount(Long userId, String scene) {
+        String sceneCode = MailSceneEnum.of(scene).getCode();
+        LambdaQueryWrapper<SmtpPopSettingsEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SmtpPopSettingsEntity::getOwnerBy, userId)
+                .eq(SmtpPopSettingsEntity::getIsDelete, CommonConstant.DEL_FLAG_0)
+                .eq(SmtpPopSettingsEntity::getUseDefault, 1)
+                .eq(SmtpPopSettingsEntity::getScene, sceneCode)
+                .last("limit 1");
+        SmtpPopSettingsEntity entity = smtpPopSettingsService.getOne(wrapper);
+        if (entity != null) {
+            return entity;
+        }
+        // 兼容未刷 scene 的存量数据:仅 CRM 场景回退查空 scene
+        if (MailSceneEnum.isCrm(sceneCode)) {
+            wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(SmtpPopSettingsEntity::getOwnerBy, userId)
+                    .eq(SmtpPopSettingsEntity::getIsDelete, CommonConstant.DEL_FLAG_0)
+                    .eq(SmtpPopSettingsEntity::getUseDefault, 1)
+                    .and(w -> w.isNull(SmtpPopSettingsEntity::getScene)
+                            .or().eq(SmtpPopSettingsEntity::getScene, "")
+                            .or().eq(SmtpPopSettingsEntity::getScene, MailSceneEnum.CRM.getCode()))
+                    .last("limit 1");
+            return smtpPopSettingsService.getOne(wrapper);
+        }
+        return null;
+    }
+
+    @Override
+    public List<SmtpPopSettingsEntity> listAccounts(Long userId, String scene) {
+        String sceneCode = MailSceneEnum.of(scene).getCode();
+        LambdaQueryWrapper<SmtpPopSettingsEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SmtpPopSettingsEntity::getOwnerBy, userId)
+                .eq(SmtpPopSettingsEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+        if (MailSceneEnum.isCrm(sceneCode)) {
+            wrapper.and(w -> w.isNull(SmtpPopSettingsEntity::getScene)
+                    .or().eq(SmtpPopSettingsEntity::getScene, "")
+                    .or().eq(SmtpPopSettingsEntity::getScene, MailSceneEnum.CRM.getCode()));
+        } else {
+            wrapper.eq(SmtpPopSettingsEntity::getScene, sceneCode);
+        }
+        return smtpPopSettingsService.list(wrapper);
+    }
+
+    @Override
+    public List<SmtpPopSettingsEntity> listOrgAccounts(Long orgId, String scene) {
+        String sceneCode = MailSceneEnum.of(scene).getCode();
+        return smtpPopSettingsService.list(new LambdaQueryWrapper<SmtpPopSettingsEntity>()
+                .eq(SmtpPopSettingsEntity::getOrgId, orgId)
+                .eq(SmtpPopSettingsEntity::getScene, sceneCode)
+                .eq(SmtpPopSettingsEntity::getIsDelete, CommonConstant.DEL_FLAG_0));
+    }
+
+    @Override
+    public SmtpPopSettingsEntity requireAccount(Long accountId, MailSceneEnum scene) {
+        if (accountId == null) {
+            throw new WebException("邮箱账户不能为空");
+        }
+        SmtpPopSettingsEntity account = smtpPopSettingsService.getById(accountId);
+        if (account == null || !Objects.equals(account.getIsDelete(), CommonConstant.DEL_FLAG_0)) {
+            throw new WebException("邮箱账户不存在");
+        }
+        assertScene(account, scene);
+        return account;
+    }
+
+    @Override
+    public SmtpPopSettingsEntity requireOwnedAccount(Long accountId, Long userId, MailSceneEnum scene) {
+        SmtpPopSettingsEntity account = requireAccount(accountId, scene);
+        if (userId == null || !Objects.equals(account.getOwnerBy(), userId)) {
+            throw new WebException("无权使用该邮箱账户");
+        }
+        return account;
+    }
+
+    private void assertScene(SmtpPopSettingsEntity account, MailSceneEnum expected) {
+        MailSceneEnum actual = MailSceneEnum.of(account.getScene());
+        if (expected != null && actual != expected) {
+            throw new WebException("邮箱账户场景不匹配,期望 " + expected.getCode() + ",实际 " + actual.getCode());
+        }
+        if (!StringUtils.hasText(account.getScene()) && expected == MailSceneEnum.CRM) {
+            return;
+        }
+    }
+}

+ 4 - 4
storlead-mail/src/main/java/com/storlead/sales/mail/service/impl/MailServerPortConfigServiceImpl.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/impl/MailServerPortConfigServiceImpl.java

@@ -1,8 +1,8 @@
-package com.storlead.sales.mail.service.impl;
+package com.storlead.sales.mail.common.service.impl;
 
-import com.storlead.sales.mail.entity.MailServerPortConfigEntity;
-import com.storlead.sales.mail.mapper.MailServerPortConfigMapper;
-import com.storlead.sales.mail.service.MailServerPortConfigService;
+import com.storlead.sales.mail.common.entity.MailServerPortConfigEntity;
+import com.storlead.sales.mail.common.mapper.MailServerPortConfigMapper;
+import com.storlead.sales.mail.common.service.MailServerPortConfigService;
 import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
 import org.springframework.stereotype.Service;
 

+ 95 - 0
storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/service/impl/SmtpPopSettingsServiceImpl.java

@@ -0,0 +1,95 @@
+package com.storlead.sales.mail.common.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.storlead.framework.common.constant.CommonConstant;
+import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.common.enums.MailSceneEnum;
+import com.storlead.sales.mail.common.mapper.SmtpPopSettingsMapper;
+import com.storlead.sales.mail.common.service.SmtpPopSettingsService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * <p>
+ * 邮箱smtp_setting 服务实现类
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-05-28
+ */
+@Service
+public class SmtpPopSettingsServiceImpl extends MyBaseServiceImpl<SmtpPopSettingsMapper, SmtpPopSettingsEntity> implements SmtpPopSettingsService {
+
+    @Override
+    public SmtpPopSettingsEntity getDefaultSmtpPop(Long userId) {
+        return getDefaultSmtpPop(userId, MailSceneEnum.CRM.getCode());
+    }
+
+    @Override
+    public SmtpPopSettingsEntity getDefaultSmtpPop(Long userId, String scene) {
+        String sceneCode = MailSceneEnum.of(scene).getCode();
+        LambdaQueryWrapper<SmtpPopSettingsEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SmtpPopSettingsEntity::getOwnerBy, userId);
+        wrapper.eq(SmtpPopSettingsEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+        wrapper.eq(SmtpPopSettingsEntity::getUseDefault, 1);
+        if (MailSceneEnum.isCrm(sceneCode)) {
+            wrapper.and(w -> w.isNull(SmtpPopSettingsEntity::getScene)
+                    .or().eq(SmtpPopSettingsEntity::getScene, "")
+                    .or().eq(SmtpPopSettingsEntity::getScene, MailSceneEnum.CRM.getCode()));
+        } else {
+            wrapper.eq(SmtpPopSettingsEntity::getScene, sceneCode);
+        }
+        wrapper.last(" limit 1");
+        return this.getOne(wrapper);
+    }
+
+    @Override
+    public SmtpPopSettingsEntity getSystemSmtpPop(Long popId) {
+        return this.getById(popId);
+    }
+
+    @Override
+    public List<SmtpPopSettingsEntity> getDefaultSmtpPopls(Set userIds) {
+        LambdaQueryWrapper<SmtpPopSettingsEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.in(SmtpPopSettingsEntity::getOwnerBy, userIds);
+        wrapper.eq(SmtpPopSettingsEntity::getUseDefault, 1);
+        wrapper.and(w -> w.isNull(SmtpPopSettingsEntity::getScene)
+                .or().eq(SmtpPopSettingsEntity::getScene, "")
+                .or().eq(SmtpPopSettingsEntity::getScene, MailSceneEnum.CRM.getCode()));
+        return this.list(wrapper);
+    }
+
+    @Override
+    public List<SmtpPopSettingsEntity> getEmailAccount(Long userId) {
+        return getEmailAccount(userId, MailSceneEnum.CRM.getCode());
+    }
+
+    @Override
+    public List<SmtpPopSettingsEntity> getEmailAccount(Long userId, String scene) {
+        String sceneCode = MailSceneEnum.of(scene).getCode();
+        LambdaQueryWrapper<SmtpPopSettingsEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SmtpPopSettingsEntity::getOwnerBy, userId);
+        wrapper.eq(SmtpPopSettingsEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+        if (MailSceneEnum.isCrm(sceneCode)) {
+            wrapper.and(w -> w.isNull(SmtpPopSettingsEntity::getScene)
+                    .or().eq(SmtpPopSettingsEntity::getScene, "")
+                    .or().eq(SmtpPopSettingsEntity::getScene, MailSceneEnum.CRM.getCode()));
+        } else {
+            wrapper.eq(SmtpPopSettingsEntity::getScene, sceneCode);
+        }
+        return this.list(wrapper);
+    }
+
+    @Override
+    public SmtpPopSettingsEntity getEmailByAccountPopId(Long userId, Long popId) {
+        LambdaQueryWrapper<SmtpPopSettingsEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SmtpPopSettingsEntity::getOwnerBy, userId);
+        wrapper.eq(SmtpPopSettingsEntity::getId, popId);
+        wrapper.eq(SmtpPopSettingsEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+        wrapper.last("limit 1");
+        return this.getOne(wrapper);
+    }
+}

+ 46 - 0
storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/transport/MailTransportSupport.java

@@ -0,0 +1,46 @@
+package com.storlead.sales.mail.common.transport;
+
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+
+import javax.mail.Authenticator;
+import javax.mail.PasswordAuthentication;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.MimeMessage;
+import java.util.Properties;
+
+/**
+ * 公共 SMTP 投递能力,不包含 CRM / 营销业务落库逻辑。
+ */
+public final class MailTransportSupport {
+
+    private MailTransportSupport() {
+    }
+
+    public static Session createSmtpSession(SmtpPopSettingsEntity account) {
+        Properties props = new Properties();
+        props.put("mail.smtp.host", account.getSmtpServer());
+        props.put("mail.smtp.port", account.getSmtpPort());
+        props.put("mail.smtp.auth", "true");
+        if (Integer.valueOf(1).equals(account.getSmtpSsl())) {
+            props.put("mail.smtp.ssl.enable", "true");
+            props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
+            props.put("mail.smtp.socketFactory.port", account.getSmtpPort());
+        }
+        if (Integer.valueOf(1).equals(account.getSmtpTls())) {
+            props.put("mail.smtp.starttls.enable", "true");
+        }
+        final String user = account.getEmailAddress();
+        final String password = account.getEmailPassword();
+        return Session.getInstance(props, new Authenticator() {
+            @Override
+            protected PasswordAuthentication getPasswordAuthentication() {
+                return new PasswordAuthentication(user, password);
+            }
+        });
+    }
+
+    public static void send(MimeMessage message) throws Exception {
+        Transport.send(message);
+    }
+}

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/util/EmailHelper.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/util/EmailHelper.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.util;
+package com.storlead.sales.mail.common.util;
 
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.io.FilenameUtils;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/util/MailFormatPartUtil.java → storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/util/MailFormatPartUtil.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.util;
+package com.storlead.sales.mail.common.util;
 
 import javax.mail.BodyPart;
 import javax.mail.Multipart;

+ 74 - 0
storlead-mail/storlead-mail-common/src/main/java/com/storlead/sales/mail/common/util/SafeFilePathResolver.java

@@ -0,0 +1,74 @@
+package com.storlead.sales.mail.common.util;
+
+import cn.hutool.core.util.StrUtil;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * 安全文件路径解析:规范化后必须落在指定根目录内,禁止路径穿越。
+ */
+public final class SafeFilePathResolver {
+
+    private SafeFilePathResolver() {
+    }
+
+    /**
+     * 将相对路径解析为根目录下的绝对路径。
+     */
+    public static Path resolveUnderBase(String baseDir, String relativePath) {
+        if (StrUtil.isBlank(baseDir)) {
+            throw new IllegalArgumentException("文件根目录未配置");
+        }
+        if (StrUtil.isBlank(relativePath)) {
+            throw new IllegalArgumentException("文件路径不能为空");
+        }
+        String cleaned = sanitizeRelativePath(relativePath);
+        Path base = Paths.get(baseDir).toAbsolutePath().normalize();
+        Path resolved = base.resolve(cleaned).normalize();
+        if (!resolved.startsWith(base)) {
+            throw new IllegalArgumentException("非法文件路径");
+        }
+        return resolved;
+    }
+
+    /**
+     * 解析单文件名(不允许目录分隔符与 ..)。
+     */
+    public static Path resolveFileNameUnderBase(String baseDir, String fileName) {
+        if (StrUtil.isBlank(fileName)) {
+            throw new IllegalArgumentException("文件名不能为空");
+        }
+        String name = fileName.replace('\\', '/').trim();
+        if (name.contains("/") || name.contains("..")) {
+            throw new IllegalArgumentException("非法文件名");
+        }
+        return resolveUnderBase(baseDir, name);
+    }
+
+    private static String sanitizeRelativePath(String relativePath) {
+        String cleaned = relativePath.replace('\\', '/').trim();
+        if (cleaned.contains("\0")) {
+            throw new IllegalArgumentException("非法文件路径");
+        }
+        if (isAbsolutePath(cleaned)) {
+            throw new IllegalArgumentException("非法文件路径");
+        }
+        while (cleaned.startsWith("/")) {
+            cleaned = cleaned.substring(1);
+        }
+        for (String segment : cleaned.split("/")) {
+            if ("..".equals(segment)) {
+                throw new IllegalArgumentException("非法文件路径");
+            }
+        }
+        return cleaned;
+    }
+
+    private static boolean isAbsolutePath(String path) {
+        if (path.startsWith("/")) {
+            return true;
+        }
+        return path.length() >= 2 && Character.isLetter(path.charAt(0)) && path.charAt(1) == ':';
+    }
+}

+ 2 - 2
storlead-mail/src/main/resources/mapper/MailServerPortConfigMapper.xml → storlead-mail/storlead-mail-common/src/main/resources/mapper/MailServerPortConfigMapper.xml

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.storlead.sales.mail.mapper.MailServerPortConfigMapper">
+<mapper namespace="com.storlead.sales.mail.common.mapper.MailServerPortConfigMapper">
 
         <!-- 通用查询映射结果 -->
-        <resultMap id="BaseResultMap" type="com.storlead.sales.mail.entity.MailServerPortConfigEntity" extends="com.storlead.framework.mybatis.mapper.SysBaseFieldMapper.BaseResultMap">
+        <resultMap id="BaseResultMap" type="com.storlead.sales.mail.common.entity.MailServerPortConfigEntity" extends="com.storlead.framework.mybatis.mapper.SysBaseFieldMapper.BaseResultMap">
             <id column="id" property="id" />
             <result column="mail_server_suffix" property="mailServerSuffix" />
             <result column="pop_port_ssl" property="popPortSsl" />

+ 7 - 2
storlead-mail/src/main/resources/mapper/SmtpPopSettingsMapper.xml → storlead-mail/storlead-mail-common/src/main/resources/mapper/SmtpPopSettingsMapper.xml

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.storlead.sales.mail.mapper.SmtpPopSettingsMapper">
+<mapper namespace="com.storlead.sales.mail.common.mapper.SmtpPopSettingsMapper">
 
         <!-- 通用查询映射结果 -->
-        <resultMap id="BaseResultMap" type="com.storlead.sales.mail.entity.SmtpPopSettingsEntity" extends="com.storlead.framework.mybatis.mapper.SysBaseFieldMapper.BaseResultMap">
+        <resultMap id="BaseResultMap" type="com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity" extends="com.storlead.framework.mybatis.mapper.SysBaseFieldMapper.BaseResultMap">
             <id column="id" property="id" />
             <result column="smtp_server" property="smtpServer" />
             <result column="smtp_port" property="smtpPort" />
@@ -24,6 +24,11 @@
             <result column="is_auto_reply" property="isAutoReply" />
             <result column="reply_on_time" property="replyOnTime" />
             <result column="is_delete_mail" property="isDeleteMail" />
+            <result column="scene" property="scene" />
+            <result column="account_scope" property="accountScope" />
+            <result column="org_id" property="orgId" />
+            <result column="daily_send_limit" property="dailySendLimit" />
+            <result column="enable_receive" property="enableReceive" />
         </resultMap>
 
         <!-- 通用查询结果列 -->

+ 49 - 0
storlead-mail/storlead-mail-common/src/main/resources/sql/mail_scene_and_mkt.sql

@@ -0,0 +1,49 @@
+-- 账户场景字段(存量默认 CRM)
+ALTER TABLE smtp_pop_settings
+    ADD COLUMN scene varchar(16) NOT NULL DEFAULT 'CRM' COMMENT '场景:CRM/MKT' AFTER connect_error_count,
+    ADD COLUMN account_scope varchar(16) NOT NULL DEFAULT 'PERSONAL' COMMENT 'PERSONAL/ORG' AFTER scene,
+    ADD COLUMN org_id bigint NULL COMMENT '组织ID' AFTER account_scope,
+    ADD COLUMN daily_send_limit int NULL COMMENT '日发送上限' AFTER org_id,
+    ADD COLUMN enable_receive tinyint NOT NULL DEFAULT 1 COMMENT '是否允许收信' AFTER daily_send_limit;
+
+CREATE INDEX idx_smtp_pop_owner_scene ON smtp_pop_settings (owner_by, scene, is_delete);
+CREATE INDEX idx_smtp_pop_org_scene ON smtp_pop_settings (org_id, scene, is_delete);
+
+-- 营销邮件投递表(与 CRM emails 分表)
+CREATE TABLE IF NOT EXISTS mkt_mail_message (
+    id              bigint       NOT NULL AUTO_INCREMENT,
+    account_id      bigint       NOT NULL COMMENT 'smtp_pop_settings.id',
+    org_id          bigint       NULL,
+    biz_ref         varchar(64)  NULL COMMENT '调用方业务单号',
+    biz_batch_no    varchar(64)  NULL,
+    message_id      varchar(255) NULL,
+    track_token     varchar(64)  NULL,
+    subject         varchar(512) NULL,
+    from_addr       varchar(255) NULL,
+    from_name       varchar(255) NULL,
+    recipient       varchar(512) NOT NULL,
+    recipient_cc    text         NULL,
+    recipient_bcc   text         NULL,
+    content         mediumtext   NULL,
+    status          tinyint      NOT NULL DEFAULT 0 COMMENT '-1待定时 0发送中 1成功 2失败',
+    fail_reason     varchar(512) NULL,
+    is_track        tinyint      NOT NULL DEFAULT 0,
+    opened          tinyint      NOT NULL DEFAULT 0,
+    first_open_time datetime     NULL,
+    open_count      int          NOT NULL DEFAULT 0,
+    sent_time       datetime     NULL,
+    delay_send_time datetime     NULL,
+    owner_by        bigint       NULL,
+    create_by       bigint       NULL,
+    update_by       bigint       NULL,
+    create_time     datetime     NULL,
+    update_time     datetime     NULL,
+    is_delete       tinyint      NOT NULL DEFAULT 0,
+    enabled         tinyint      NOT NULL DEFAULT 1,
+    sort            int          NULL,
+    PRIMARY KEY (id),
+    UNIQUE KEY uk_mkt_track_token (track_token),
+    KEY idx_mkt_biz_ref (biz_ref, status),
+    KEY idx_mkt_account_sent (account_id, sent_time),
+    KEY idx_mkt_org_sent (org_id, sent_time)
+) COMMENT='营销邮件投递记录';

+ 31 - 0
storlead-mail/storlead-mail-crm/pom.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.storlead.boot</groupId>
+        <artifactId>storlead-mail</artifactId>
+        <version>1.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>storlead-mail-crm</artifactId>
+    <packaging>jar</packaging>
+    <name>storlead-mail-crm</name>
+    <description>CRM personal mailbox business (send/receive/folder/integration)</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.storlead.boot</groupId>
+            <artifactId>storlead-mail-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 0 - 0
storlead-mail/src/main/java/com/storlead/sales/Main.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/Main.java


+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/QQEmailReceiver.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/QQEmailReceiver.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail;
+package com.storlead.sales.mail.crm;
 
 import com.sun.mail.imap.DefaultFolder;
 import com.sun.mail.imap.IMAPFolder;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/QQEmailSender.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/QQEmailSender.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail;
+package com.storlead.sales.mail.crm;
 
 /**
  * @program: sp-sales-platform

+ 7 - 7
storlead-mail/src/main/java/com/storlead/sales/mail/dispatch/AutoSendDelayEmailTaskJob.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/dispatch/AutoSendDelayEmailTaskJob.java

@@ -1,14 +1,14 @@
-package com.storlead.sales.mail.dispatch;
+package com.storlead.sales.mail.crm.dispatch;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.storlead.framework.common.constant.CommonConstant;
 import com.storlead.framework.common.util.encryptor.AccessKeyEncryptor;
-import com.storlead.sales.mail.entity.EmailsEntity;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.enums.EmailBoxEnum;
-import com.storlead.sales.mail.service.EmailsService;
-import com.storlead.sales.mail.service.SmtpPopSettingsService;
+import com.storlead.sales.mail.crm.entity.EmailsEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.crm.enums.EmailBoxEnum;
+import com.storlead.sales.mail.crm.service.EmailsService;
+import com.storlead.sales.mail.common.service.SmtpPopSettingsService;
 import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.core.env.Environment;
@@ -36,7 +36,7 @@ public class AutoSendDelayEmailTaskJob {
     @Resource
     private SmtpPopSettingsService smtpPopSettingsService;
 
-    @Scheduled(cron = "${storlead.mail.scheduler.delay-send-cron:0 * * * * ?}")
+    // @Scheduled(cron = "${storlead.mail.scheduler.delay-send-cron:0 * * * * ?}")
     public void sendDelayEmailTask() {
         String active = environment.getProperty("spring.profiles.active");
         if ("dev".equals(active)) {

+ 7 - 7
storlead-mail/src/main/java/com/storlead/sales/mail/dispatch/DelayDeleteServerEmailTaskJob.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/dispatch/DelayDeleteServerEmailTaskJob.java

@@ -1,13 +1,13 @@
-package com.storlead.sales.mail.dispatch;
+package com.storlead.sales.mail.crm.dispatch;
 
 import cn.hutool.core.collection.CollectionUtil;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.storlead.framework.common.util.encryptor.AccessKeyEncryptor;
-import com.storlead.sales.mail.connection.config.MailProperties;
-import com.storlead.sales.mail.entity.EmailsEntity;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.service.EmailsService;
-import com.storlead.sales.mail.service.SmtpPopSettingsService;
+import com.storlead.sales.mail.common.connection.config.MailProperties;
+import com.storlead.sales.mail.crm.entity.EmailsEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.crm.service.EmailsService;
+import com.storlead.sales.mail.common.service.SmtpPopSettingsService;
 import com.sun.mail.imap.IMAPFolder;
 import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -46,7 +46,7 @@ public class DelayDeleteServerEmailTaskJob {
     /**
      * 定时执行:从邮件服务器延迟删除已标记过期的邮件。
      */
-    @Scheduled(cron = "${storlead.mail.scheduler.delay-delete-cron:0 0 2 * * ?}")
+    // @Scheduled(cron = "${storlead.mail.scheduler.delay-delete-cron:0 0 2 * * ?}")
     public void delayDeleteServerEmailTask() {
         List<EmailsEntity> taskEntities = emailsService.getDelayDeleteMail();
         if (CollectionUtil.isEmpty(taskEntities)) {

+ 12 - 6
storlead-mail/src/main/java/com/storlead/sales/mail/dispatch/EmailPullHeadContentTaskJob.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/dispatch/EmailPullHeadContentTaskJob.java

@@ -1,12 +1,12 @@
-package com.storlead.sales.mail.dispatch;
+package com.storlead.sales.mail.crm.dispatch;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.service.EmailsService;
-import com.storlead.sales.mail.service.SmtpPopSettingsService;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.common.enums.MailSceneEnum;
+import com.storlead.sales.mail.common.service.SmtpPopSettingsService;
+import com.storlead.sales.mail.crm.service.EmailsService;
 import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
@@ -24,12 +24,18 @@ public class EmailPullHeadContentTaskJob {
     @Resource
     private EmailsService emailsService;
 
-    @Scheduled(cron = "${storlead.mail.scheduler.pull-email-cron:0 */5 * * * ?}")
+    //@Scheduled(cron = "${storlead.mail.scheduler.pull-email-cron:0 */5 * * * ?}")
     public void pullHeadMailTask() {
+        // 仅拉取 CRM 个人邮箱,营销账户不进收信任务
         LambdaQueryWrapper<SmtpPopSettingsEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
         lambdaQueryWrapper.eq(SmtpPopSettingsEntity::getIsDelete, 0);
         lambdaQueryWrapper.eq(SmtpPopSettingsEntity::getEnabled, 1);
         lambdaQueryWrapper.ne(SmtpPopSettingsEntity::getEmailAddress, "system@storlead.com");
+        lambdaQueryWrapper.and(w -> w.isNull(SmtpPopSettingsEntity::getScene)
+                .or().eq(SmtpPopSettingsEntity::getScene, "")
+                .or().eq(SmtpPopSettingsEntity::getScene, MailSceneEnum.CRM.getCode()));
+        lambdaQueryWrapper.and(w -> w.isNull(SmtpPopSettingsEntity::getEnableReceive)
+                .or().eq(SmtpPopSettingsEntity::getEnableReceive, 1));
         List<SmtpPopSettingsEntity> settingsEntities = smtpPopSettingsService.list(lambdaQueryWrapper);
         if (CollectionUtils.isEmpty(settingsEntities)) {
             return;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/AttachmentEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/AttachmentEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/ClientSentEmailsEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/ClientSentEmailsEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/EmailBlacklistRecordEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailBlacklistRecordEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/EmailFileFolderEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailFileFolderEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/EmailFolderRuleEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailFolderRuleEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/EmailFoldersEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailFoldersEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/EmailTemplatesEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailTemplatesEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/EmailsEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/EmailsEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.alibaba.fastjson.annotation.JSONField;
 import com.baomidou.mybatisplus.annotation.*;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/FoldersEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/FoldersEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/MailAttachmentEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/MailAttachmentEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/MailDelayPullRecordEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/MailDelayPullRecordEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/MailTempAttachmentEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/MailTempAttachmentEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/MailboxAutoReplySetEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/MailboxAutoReplySetEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/UserEmailFolderEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/UserEmailFolderEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/entity/UserMailTrackRecordEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/entity/UserMailTrackRecordEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.entity;
+package com.storlead.sales.mail.crm.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/enums/EmailBoxEnum.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/enums/EmailBoxEnum.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.enums;
+package com.storlead.sales.mail.crm.enums;
 
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.annotation.EnumValue;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/enums/EmailFileFolderEnum.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/enums/EmailFileFolderEnum.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.enums;
+package com.storlead.sales.mail.crm.enums;
 
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.annotation.EnumValue;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/enums/EmailFolderlRuleEnum.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/enums/EmailFolderlRuleEnum.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.enums;
+package com.storlead.sales.mail.crm.enums;
 
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.annotation.EnumValue;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/enums/SendStatus.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/enums/SendStatus.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.enums;
+package com.storlead.sales.mail.crm.enums;
 
 import com.baomidou.mybatisplus.annotation.EnumValue;
 import com.fasterxml.jackson.annotation.JsonValue;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/integration/config/MailIntegrationConfiguration.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/config/MailIntegrationConfiguration.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.integration.config;
+package com.storlead.sales.mail.crm.integration.config;
 
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Configuration;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/integration/config/MailIntegrationProperties.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/config/MailIntegrationProperties.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.integration.config;
+package com.storlead.sales.mail.crm.integration.config;
 
 import lombok.Data;
 import org.springframework.boot.context.properties.ConfigurationProperties;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/integration/entity/MailIntegrationTaskEntity.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/entity/MailIntegrationTaskEntity.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.integration.entity;
+package com.storlead.sales.mail.crm.integration.entity;
 
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/integration/enums/MailIntegrationTaskStatus.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/enums/MailIntegrationTaskStatus.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.integration.enums;
+package com.storlead.sales.mail.crm.integration.enums;
 
 import lombok.Getter;
 

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/integration/enums/MailIntegrationTaskType.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/enums/MailIntegrationTaskType.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.integration.enums;
+package com.storlead.sales.mail.crm.integration.enums;
 
 import lombok.Getter;
 

+ 2 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/integration/external/IntegrationExternalInvoker.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/external/IntegrationExternalInvoker.java

@@ -1,8 +1,8 @@
-package com.storlead.sales.mail.integration.external;
+package com.storlead.sales.mail.crm.integration.external;
 
 import cn.hutool.core.util.StrUtil;
 import com.storlead.framework.common.util.SpringContextUtils;
-import com.storlead.sales.mail.pojo.vo.CustomerMailVO;
+import com.storlead.sales.mail.crm.pojo.vo.CustomerMailVO;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;

+ 5 - 5
storlead-mail/src/main/java/com/storlead/sales/mail/integration/handler/CrmMailSyncHandler.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/handler/CrmMailSyncHandler.java

@@ -1,10 +1,10 @@
-package com.storlead.sales.mail.integration.handler;
+package com.storlead.sales.mail.crm.integration.handler;
 
 import cn.hutool.core.util.StrUtil;
-import com.storlead.sales.mail.entity.EmailsEntity;
-import com.storlead.sales.mail.integration.external.IntegrationExternalInvoker;
-import com.storlead.sales.mail.integration.support.MailEntityResolver;
-import com.storlead.sales.mail.integration.util.MailIdsParser;
+import com.storlead.sales.mail.crm.entity.EmailsEntity;
+import com.storlead.sales.mail.crm.integration.external.IntegrationExternalInvoker;
+import com.storlead.sales.mail.crm.integration.support.MailEntityResolver;
+import com.storlead.sales.mail.crm.integration.util.MailIdsParser;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;

+ 9 - 9
storlead-mail/src/main/java/com/storlead/sales/mail/integration/handler/NewMailRemindHandler.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/handler/NewMailRemindHandler.java

@@ -1,13 +1,13 @@
-package com.storlead.sales.mail.integration.handler;
+package com.storlead.sales.mail.crm.integration.handler;
 
-import com.storlead.sales.mail.entity.EmailsEntity;
-import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
-import com.storlead.sales.mail.integration.external.IntegrationExternalInvoker;
-import com.storlead.sales.mail.integration.support.MailEntityResolver;
-import com.storlead.sales.mail.integration.util.MailIdsParser;
-import com.storlead.sales.mail.mapper.EmailsMapper;
-import com.storlead.sales.mail.pojo.vo.CustomerMailVO;
-import com.storlead.sales.mail.service.SmtpPopSettingsService;
+import com.storlead.sales.mail.crm.entity.EmailsEntity;
+import com.storlead.sales.mail.common.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.crm.integration.external.IntegrationExternalInvoker;
+import com.storlead.sales.mail.crm.integration.support.MailEntityResolver;
+import com.storlead.sales.mail.crm.integration.util.MailIdsParser;
+import com.storlead.sales.mail.crm.mapper.EmailsMapper;
+import com.storlead.sales.mail.crm.pojo.vo.CustomerMailVO;
+import com.storlead.sales.mail.common.service.SmtpPopSettingsService;
 import cn.hutool.core.util.StrUtil;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.stereotype.Component;

+ 2 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/integration/mapper/MailIntegrationTaskMapper.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/mapper/MailIntegrationTaskMapper.java

@@ -1,7 +1,7 @@
-package com.storlead.sales.mail.integration.mapper;
+package com.storlead.sales.mail.crm.integration.mapper;
 
 import com.storlead.framework.mybatis.mapper.MyBaseMapper;
-import com.storlead.sales.mail.integration.entity.MailIntegrationTaskEntity;
+import com.storlead.sales.mail.crm.integration.entity.MailIntegrationTaskEntity;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;

+ 2 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/integration/service/MailIntegrationTaskService.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/service/MailIntegrationTaskService.java

@@ -1,7 +1,7 @@
-package com.storlead.sales.mail.integration.service;
+package com.storlead.sales.mail.crm.integration.service;
 
 import com.storlead.framework.mybatis.service.MyBaseService;
-import com.storlead.sales.mail.integration.entity.MailIntegrationTaskEntity;
+import com.storlead.sales.mail.crm.integration.entity.MailIntegrationTaskEntity;
 
 import java.util.List;
 

+ 8 - 8
storlead-mail/src/main/java/com/storlead/sales/mail/integration/service/impl/MailIntegrationTaskServiceImpl.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/service/impl/MailIntegrationTaskServiceImpl.java

@@ -1,14 +1,14 @@
-package com.storlead.sales.mail.integration.service.impl;
+package com.storlead.sales.mail.crm.integration.service.impl;
 
 import cn.hutool.core.util.IdUtil;
 import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
-import com.storlead.sales.mail.integration.config.MailIntegrationProperties;
-import com.storlead.sales.mail.integration.entity.MailIntegrationTaskEntity;
-import com.storlead.sales.mail.integration.enums.MailIntegrationTaskStatus;
-import com.storlead.sales.mail.integration.enums.MailIntegrationTaskType;
-import com.storlead.sales.mail.integration.mapper.MailIntegrationTaskMapper;
-import com.storlead.sales.mail.integration.service.MailIntegrationTaskService;
-import com.storlead.sales.mail.integration.util.MailIdsParser;
+import com.storlead.sales.mail.crm.integration.config.MailIntegrationProperties;
+import com.storlead.sales.mail.crm.integration.entity.MailIntegrationTaskEntity;
+import com.storlead.sales.mail.crm.integration.enums.MailIntegrationTaskStatus;
+import com.storlead.sales.mail.crm.integration.enums.MailIntegrationTaskType;
+import com.storlead.sales.mail.crm.integration.mapper.MailIntegrationTaskMapper;
+import com.storlead.sales.mail.crm.integration.service.MailIntegrationTaskService;
+import com.storlead.sales.mail.crm.integration.util.MailIdsParser;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;

+ 5 - 5
storlead-mail/src/main/java/com/storlead/sales/mail/integration/support/MailEntityResolver.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/support/MailEntityResolver.java

@@ -1,9 +1,9 @@
-package com.storlead.sales.mail.integration.support;
+package com.storlead.sales.mail.crm.integration.support;
 
-import com.storlead.sales.mail.entity.ClientSentEmailsEntity;
-import com.storlead.sales.mail.entity.EmailsEntity;
-import com.storlead.sales.mail.service.ClientSentEmailsService;
-import com.storlead.sales.mail.service.EmailsService;
+import com.storlead.sales.mail.crm.entity.ClientSentEmailsEntity;
+import com.storlead.sales.mail.crm.entity.EmailsEntity;
+import com.storlead.sales.mail.crm.service.ClientSentEmailsService;
+import com.storlead.sales.mail.crm.service.EmailsService;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;

+ 1 - 1
storlead-mail/src/main/java/com/storlead/sales/mail/integration/util/MailIdsParser.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/integration/util/MailIdsParser.java

@@ -1,4 +1,4 @@
-package com.storlead.sales.mail.integration.util;
+package com.storlead.sales.mail.crm.integration.util;
 
 import cn.hutool.core.util.StrUtil;
 import org.springframework.util.CollectionUtils;

+ 2 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/mapper/AttachmentMapper.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/mapper/AttachmentMapper.java

@@ -1,6 +1,6 @@
-package com.storlead.sales.mail.mapper;
+package com.storlead.sales.mail.crm.mapper;
 
-import com.storlead.sales.mail.entity.AttachmentEntity;
+import com.storlead.sales.mail.crm.entity.AttachmentEntity;
 import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 
 /**

+ 2 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/mapper/ClientSentEmailsMapper.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/mapper/ClientSentEmailsMapper.java

@@ -1,6 +1,6 @@
-package com.storlead.sales.mail.mapper;
+package com.storlead.sales.mail.crm.mapper;
 
-import com.storlead.sales.mail.entity.ClientSentEmailsEntity;
+import com.storlead.sales.mail.crm.entity.ClientSentEmailsEntity;
 import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 
 /**

+ 2 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/mapper/EmailBlacklistRecordMapper.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/mapper/EmailBlacklistRecordMapper.java

@@ -1,6 +1,6 @@
-package com.storlead.sales.mail.mapper;
+package com.storlead.sales.mail.crm.mapper;
 
-import com.storlead.sales.mail.entity.EmailBlacklistRecordEntity;
+import com.storlead.sales.mail.crm.entity.EmailBlacklistRecordEntity;
 import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 
 /**

+ 2 - 2
storlead-mail/src/main/java/com/storlead/sales/mail/mapper/EmailFileFolderMapper.java → storlead-mail/storlead-mail-crm/src/main/java/com/storlead/sales/mail/crm/mapper/EmailFileFolderMapper.java

@@ -1,6 +1,6 @@
-package com.storlead.sales.mail.mapper;
+package com.storlead.sales.mail.crm.mapper;
 
-import com.storlead.sales.mail.entity.EmailFileFolderEntity;
+import com.storlead.sales.mail.crm.entity.EmailFileFolderEntity;
 import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 
 /**

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff