Browse Source

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

1811872455@163.com 3 weeks ago
parent
commit
4c18487586

+ 19 - 0
storlead-api/src/main/java/com/storlead/mail/ClientSentEmailsController.java

@@ -0,0 +1,19 @@
+package com.storlead.mail;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 邮件表 前端控制器
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-12-04
+ */
+@RestController
+@RequestMapping("/client-sent-emails-entity")
+public class ClientSentEmailsController {
+
+}

+ 170 - 0
storlead-api/src/main/java/com/storlead/mail/EmailFolderRuleApiController.java

@@ -0,0 +1,170 @@
+package com.storlead.mail;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+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 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.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+/**
+ * <p>
+ * 用户邮件文件夹出入规则 前端控制器
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-11-12
+ */
+@RestController
+@Log4j2
+@RequestMapping("/email/folder/rule")
+@Api(tags = "邮件:邮件自定义入站规则")
+public class EmailFolderRuleApiController {
+
+    @Resource
+    private EmailFolderRuleService folderRuleService;
+
+    @Resource
+    private EmailsService emailsService;
+
+    @PostMapping(value = "/get_folder_rule")
+    @ApiOperation(value = "获取规则" )
+    public Result<?> getFolderRule() {
+        List<EmailFolderlRuleEnum>  ls = Arrays.asList(EmailFolderlRuleEnum.values());
+        List<Map>  enumls = new ArrayList<>();
+        for (EmailFolderlRuleEnum e : ls) {
+            Map<String,String> stringMap = new HashMap<>();
+            stringMap.put("code",e.getCode());
+            stringMap.put("desc",e.getDesc());
+            enumls.add(stringMap);
+        }
+        return Result.result(enumls);
+    }
+
+
+    @PostMapping(value = "/page_list")
+    @ApiOperation(value = "获取文件夹入站规则配置(分页)" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> pageList(EmailTemplatesDTO dto) {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        Page<EmailFolderRuleEntity> page = new Page<>(dto.getPageIndex(),dto.getPageSize());
+        LambdaQueryWrapper<EmailFolderRuleEntity> queryWrapper = new LambdaQueryWrapper();
+        queryWrapper.eq(EmailFolderRuleEntity::getOwnerBy,currentUserId);
+        queryWrapper.eq(EmailFolderRuleEntity::getIsDelete,Integer.valueOf(0));
+        IPage<EmailFolderRuleEntity> pageList = folderRuleService.page(page,queryWrapper);
+        return Result.result(pageList);
+    }
+
+    @PostMapping(value = "/list")
+    @ApiOperation(value = "获取文件夹入站规则" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> list() {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        List<EmailFolderRuleEntity> list = folderRuleService.getUserFolderRules(currentUserId);
+        return Result.result(list);
+    }
+
+    @PostMapping(value = "/save")
+    @ApiOperation(value = "保存用户规则配置" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> save(EmailFolderRuleEntity entity) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        LambdaQueryWrapper<EmailFolderRuleEntity> w = new LambdaQueryWrapper<>();
+        w.eq(EmailFolderRuleEntity::getFolderRuleCode,entity.getFolderRuleCode());
+        w.eq(EmailFolderRuleEntity::getCompareContent,entity.getCompareContent());
+        w.eq(EmailFolderRuleEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+        w.eq(EmailFolderRuleEntity::getOwnerBy,currentUserId);
+        if (Objects.isNull(entity.getId())) {
+            Integer exit = folderRuleService.count(w);
+            if (exit > 0) {
+                return Result.error("已存在同样的规则,不能新增同样的入站规则!");
+            }
+        } else {
+
+            EmailFolderRuleEntity oldFolder = folderRuleService.getOne(w);
+            if (Objects.nonNull(oldFolder)) {
+                if (!oldFolder.getId().equals(entity.getId())) {
+                    return Result.error("已存在同样的入站规则,无法修改!");
+                }
+            }
+        }
+
+        folderRuleService.saveOrUpdate(entity);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/saveBatch")
+    @ApiOperation(value = "保存用户规则配置" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> save(@RequestBody FolderRuleDTO dto) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (CollectionUtils.isEmpty(dto.getFolderRules())) {
+            return Result.error("参数错误");
+        }
+        LambdaQueryWrapper<EmailFolderRuleEntity> deleteW = new LambdaQueryWrapper<>();
+        deleteW.eq(EmailFolderRuleEntity::getOwnerBy,currentUserId);
+        folderRuleService.remove(deleteW);
+        folderRuleService.saveOrUpdateBatch(dto.getFolderRules());
+        return Result.ok();
+    }
+
+    @ApiOperation(value = "删除")
+    @PostMapping("deleteIds")
+    public Result delete(Long [] ids) {
+        if(Objects.isNull(ids)) {
+            return Result.error("参数错误");
+        }
+        folderRuleService.lgDelete(Arrays.asList(ids));
+
+        LambdaUpdateWrapper<EmailsEntity> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.in(EmailsEntity::getCustomFolderId,Arrays.asList(ids));
+        updateWrapper.set(EmailsEntity::getCustomFolderId,null);
+        emailsService.update(updateWrapper);
+        return Result.ok();
+    }
+
+
+
+
+    @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);
+        return Result.ok();
+    }
+}

+ 94 - 0
storlead-api/src/main/java/com/storlead/mail/EmailServiceChecker.java

@@ -0,0 +1,94 @@
+package com.storlead.mail;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-08-08 17:46
+ */
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import java.util.Hashtable;
+
+public class EmailServiceChecker {
+    public static void main(String[] args) {
+//        String email = "chenkaiqiang@lcjs43.wecom.work";
+        String email = "fan@storlead.com";
+        String emailService = getEmailService(email);
+        System.out.println("邮箱服务提供商: " + emailService);
+    }
+
+    public static String getEmailService(String email) {
+        if (email == null || !email.contains("@")) {
+            return "";
+        }
+
+        String domain = email.substring(email.indexOf("@") + 1);
+
+        // 使用域名匹配常见邮箱服务提供商
+        switch (domain) {
+            case "gmail.com":
+                return "Google Gmail";
+            case "yahoo.com":
+            case "yahoo.co.jp":
+                return "yahoo.com";
+            case "outlook.com":
+                return "outlook.com";
+            case "hotmail.com":
+                return "hotmail.com";
+            case "qq.com":
+                return "qq.com";
+            case "exmail.qq.com":
+                return "exmail.qq.com";
+            case "163.com":
+                return "163.com";
+            case "storlead.com":
+                return "exmail.qq.com";
+            case "renice-tech.com":
+                return "exmail.qq.com";
+            // 添加其他常见的邮箱服务提供商...
+            default:
+                return checkMXRecords(domain);
+        }
+    }
+
+    public static String checkMXRecords(String domain) {
+        try {
+            Hashtable<String, String> env = new Hashtable<>();
+            env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
+            DirContext ctx = new InitialDirContext(env);
+            Attributes attrs = ctx.getAttributes(domain, new String[]{"MX"});
+            Attribute attr = attrs.get("MX");
+
+            if (attr == null) {
+                return "";
+            }
+
+            for (int i = 0; i < attr.size(); i++) {
+                String mxRecord = (String) attr.get(i);
+                if (mxRecord.contains("google.com")) {
+                    return "gmail.com";
+                } else if (mxRecord.contains("outlook.com")) {
+                    return "outlook.com";
+                } else if (mxRecord.contains("hotmail.com")) {
+                    return "hotmail.com";
+                }  else if (mxRecord.contains("qq.com") && (mxRecord.contains("mx1") || mxRecord.contains("mx2"))) {
+                    return "qq.com";
+                } else if (mxRecord.contains("qq.com") && mxRecord.contains("mxbiz")) {
+                    return "exmail.qq.com";
+                } else if (mxRecord.contains("yahoo.com")) {
+                    return "yahoo.com";
+                }
+            }
+        } catch (NamingException e) {
+            e.printStackTrace();
+            return "";
+        }
+        return "";
+    }
+}

+ 155 - 0
storlead-api/src/main/java/com/storlead/mail/MaiAttachmentApiController.java

@@ -0,0 +1,155 @@
+package com.storlead.mail;
+
+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 io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.util.*;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-08-10 09:14
+ */
+@RestController
+@RequestMapping("/mail/file")
+@Api(tags = "020.邮件管理相关接口")
+@Log4j2
+public class MaiAttachmentApiController {
+
+    @Resource
+    private MailFileProperties mailFileProperties;
+    @Resource
+    private SmtpPopSettingsService smtpPopSettingsService;
+    @Resource
+    private MailTempAttachmentService tempAttachmentService;
+
+    @PostMapping(value = "/cache_mail_file")
+    @ApiOperation(value = "缓存需要上传的附件" )
+    public Result<?> cacheMailFile(@RequestParam("files") List<MultipartFile> files) {
+        Result result = new Result();
+
+        try {
+            List<JSONObject> res = new ArrayList<>();
+
+            for (MultipartFile file : files) {
+                Long currentUserId = LoginUserUtil.getCurrentUserId();
+                SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getDefaultSmtpPop(currentUserId);
+                String recipient = DateUtils.date2Str(new Date(), DateUtils.yyyyMMdd);
+                String downloadDir = mailFileProperties.getPath().getPath() + File.separator + smtpPop.getEmailAddress() + File.separator + recipient + File.separator;
+                JSONObject jsonObject = new JSONObject();
+                Long fileId = tempAttachmentService.saveTempAttachment(file, downloadDir, null);
+                if (Objects.isNull(fileId)) {
+                    return Result.error("上传错误");
+                }
+                jsonObject.put("id", fileId);
+                jsonObject.put("fileShowName", file.getOriginalFilename());
+                jsonObject.put("fileName", FilenameUtils.getBaseName(file.getOriginalFilename()));
+                jsonObject.put("fileSize", file.getSize());
+                jsonObject.put("fileSizeName", FileHelper.formatFileSize(file.getSize()));
+                jsonObject.put("fileExt", FilenameUtils.getExtension(file.getOriginalFilename()));
+                res.add(jsonObject);
+            }
+            return Result.result(res);
+
+        } catch (Exception e) {
+            log.error("--upload -- error =", e);
+            return Result.error("上传错误");
+        }
+    }
+
+    @PostMapping(value = "/cache_image_file")
+    @ApiOperation(value = "缓存图片文件" )
+    public Map cacheImageFile(@RequestParam("upload") MultipartFile file) {
+        Map jsonObject = new HashMap();
+        try {
+            Long currentUserId = LoginUserUtil.getCurrentUserId();
+            String downloadDir = mailFileProperties.getPath().getJpeg();
+            MailTempAttachmentEntity tempAttachment = tempAttachmentService.saveTempImageAttachment(file, downloadDir);
+            if (Objects.isNull(tempAttachment) || Objects.isNull(tempAttachment.getId())) {
+                return jsonObject;
+            }
+            String fileName =  tempAttachment.getFileName()+"."+tempAttachment.getFileExt();
+            jsonObject.put("id", tempAttachment.getId());
+            jsonObject.put("fileName", fileName);
+            jsonObject.put("uploaded", 1);
+            jsonObject.put("url", "/sales/mail/file/images/"+fileName);
+            return jsonObject;
+        } catch (Exception e) {
+            log.error("--upload -- error =", e);
+            return jsonObject;
+        }
+    }
+
+    @PostMapping(value = "/download_mail_file")
+    @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));
+            response.reset();
+            response.setContentType("application/octet-stream;charset=utf-8");
+            /*
+             * 跨域配置
+             * */
+            response.addHeader("Access-Control-Allow-Origin", "*");
+            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
+            response.addHeader("Access-Control-Allow-Headers", "Content-Type");
+
+            String filename = resource.getFileName()+"."+resource.getFileExt();
+            filename = filename.replace(" ","");
+            response.addHeader("content-disposition",
+                    "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")
+                            + ";filename*=utf-8''" + URLEncoder.encode(filename, "UTF-8"));
+
+            ServletOutputStream outputStream = response.getOutputStream();
+            byte[] b = new byte[1024];
+            int len;
+//从输入流中读取一定数量的字节,并将其存储在缓冲区字节数组中,读到末尾返回-1
+            while ((len = inputStream.read(b)) > 0) {
+                outputStream.write(b, 0, len);
+            }
+            inputStream.close();
+            outputStream.close();
+
+        } catch (Exception e) {
+            log.error("--upload -- error =", e);
+        }
+    }
+
+    @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);
+    }
+}

+ 1067 - 0
storlead-api/src/main/java/com/storlead/mail/MailApiController.java

@@ -0,0 +1,1067 @@
+package com.storlead.mail;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import com.storlead.framework.common.util.RandomGenerateHelper;
+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 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 ma.glasnost.orika.impl.DefaultMapperFactory;
+import org.springframework.beans.BeanUtils;
+import org.springframework.core.env.Environment;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.activation.FileDataSource;
+import javax.annotation.Resource;
+import javax.mail.*;
+import javax.mail.internet.*;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-05-29 16:02
+ */
+@RestController
+@RequestMapping("/mail")
+@Api(tags = "020.邮件管理相关接口")
+@Log4j2
+public class MailApiController {
+
+    @Resource
+    private EmailsService emailsService;
+    @Resource
+    private MailFileProperties mailFileProperties;
+    @Resource
+    private MailAttachmentService mailAttachmentService;
+    @Resource
+    private SmtpPopSettingsService smtpPopSettingsService;
+    @Resource
+    private MailServerPortConfigService serverPortConfigService;
+
+    @Resource
+    private MailTempAttachmentService tempAttachmentService;
+
+    @Resource
+    private UserMailTrackRecordService mailTrackRecordService;
+
+
+    @Resource
+    private Environment environment;
+
+    @PostMapping(value = "/send_mail")
+    @ApiOperation(value = "发送邮件")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> sendMail(SendMailDTO dto) {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getDefaultSmtpPop(currentUserId);
+        AccessKeyEncryptor accessKeyEncryptor = AccessKeyEncryptor.getAccessKeyEncryptor("");
+        String pass = accessKeyEncryptor.decrypt(smtpPop.getEmailPassword());
+        smtpPop.setEmailPassword(pass);
+        if (Objects.isNull(currentUserId) && Objects.nonNull(smtpPop)) {
+            return Result.result(null);
+        }
+        SendStatus result = emailsService.sendEmail(dto, smtpPop);
+        if (result.code == SendStatus.SUCCESS.code || result.code == SendStatus.PARTIAL_SUCCESS.code) {
+            return Result.ok();
+        } else {
+            return Result.error(result.getDesc());
+        }
+    }
+
+    @PostMapping(value = "/asyn_send_mail")
+    @ApiOperation(value = "发送邮件")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> asynSendMail(SendMailDTO dto) {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getDefaultSmtpPop(currentUserId);
+        AccessKeyEncryptor accessKeyEncryptor = AccessKeyEncryptor.getAccessKeyEncryptor("");
+        String pass = accessKeyEncryptor.decrypt(smtpPop.getEmailPassword());
+        smtpPop.setEmailPassword(pass);
+        if (Objects.isNull(currentUserId) && Objects.nonNull(smtpPop)) {
+            return Result.result(null);
+        }
+        emailsService.sendEmail(dto, smtpPop);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/save_draft")
+    @ApiOperation(value = "保存草稿")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> saveDraft(SendMailDTO dto) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getDefaultSmtpPop(currentUserId);
+        if (Objects.isNull(currentUserId) || Objects.isNull(smtpPop)) {
+            return Result.error("请先设置邮箱账号!");
+        }
+        EmailsEntity entity = new EmailsEntity();
+        if (!CollectionUtils.isEmpty(dto.getRecipientls())) {
+            entity.setRecipient(org.apache.commons.lang3.StringUtils.join(dto.getRecipientls(), ","));
+        }
+        if (!CollectionUtils.isEmpty(dto.getRecipientCcls())) {
+            entity.setRecipientCc(org.apache.commons.lang3.StringUtils.join(dto.getRecipientCcls(), ","));
+        }
+        if (!CollectionUtils.isEmpty(dto.getRecipientBccls())) {
+            entity.setRecipientBcc(org.apache.commons.lang3.StringUtils.join(dto.getRecipientBccls(), ","));
+        }
+        if (Objects.nonNull(dto.getId())) {
+            entity.setId(dto.getId());
+        }
+
+        entity.setSubject(dto.getSubject());
+        entity.setContent(dto.getContent());
+        entity.setReplyMsgId(dto.getReplyMsgId());
+        entity.setOwnerBy(currentUserId);
+        entity.setSmtpPopId(smtpPop.getId());
+        entity.setFolder(EmailBoxEnum.DRAFT.code);
+        entity.setEmailSize(Long.valueOf(entity.getContent().length()));
+
+        emailsService.saveOrUpdate(entity);
+        if (!CollectionUtils.isEmpty(dto.getFileIds())) {
+            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())) {
+            LambdaUpdateWrapper<MailAttachmentEntity> fileWrapper = new LambdaUpdateWrapper<>();
+            fileWrapper.in(MailAttachmentEntity::getId, dto.getOldfileIds());
+            List<MailAttachmentEntity> mailAttachments = mailAttachmentService.list(fileWrapper);
+            if (!CollectionUtils.isEmpty(mailAttachments)) {
+                List<MailTempAttachmentEntity> files = new ArrayList<>();
+                for(MailAttachmentEntity attachment : mailAttachments) {
+                    MailTempAttachmentEntity tempAttachment = new MailTempAttachmentEntity();
+                    BeanUtils.copyProperties(attachment,tempAttachment);
+                    tempAttachment.setId(entity.getId());
+                    tempAttachment.setOwnerBy(entity.getOwnerBy());
+                    files.add(tempAttachment);
+                }
+                if (!CollectionUtils.isEmpty(files)) {
+                    tempAttachmentService.saveBatch(files);
+                }
+            }
+        }
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/receive_mail")
+    @ApiOperation(value = "接收邮件")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> receiveMail() {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getDefaultSmtpPop(currentUserId);
+        if (Objects.isNull(currentUserId) || Objects.isNull(smtpPop)) {
+            return Result.error("请先设置邮箱账号!");
+        }
+        AccessKeyEncryptor accessKeyEncryptor = AccessKeyEncryptor.getAccessKeyEncryptor("");
+        String pass = accessKeyEncryptor.decrypt(smtpPop.getEmailPassword());
+        smtpPop.setEmailPassword(pass);
+        emailsService.receiveEmails(smtpPop);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/download_mail_eml_zip")
+    @ApiOperation(value = "下载邮件")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public void downloadMailEmlZip(MailDTO dto, HttpServletResponse response) throws MessagingException {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+
+        if (CollectionUtils.isEmpty(dto.getMailIds())) {
+            return;
+        }
+        List<EmailsEntity> entities = emailsService.list(new LambdaQueryWrapper<EmailsEntity>().in(EmailsEntity::getId, dto.getMailIds()));
+        if (CollectionUtils.isEmpty(entities)) {
+            return;
+        }
+        String zipFilePath = mailFileProperties.getPath().getPath() + "temp_eml_files";
+        File tempDir = new File(zipFilePath + File.separator + "temp");
+//        if (tempDir.exists()) {
+//
+//        }
+        if (!tempDir.exists()) {
+            tempDir.mkdirs();
+        }
+
+        List<Message> messages = new ArrayList<>();
+
+        entities.forEach(e -> {
+            Message message = mailVoToMessages(e);
+            if (Objects.nonNull(message)) {
+                messages.add(message);
+            }
+        });
+        for (int i = 0; i < messages.size(); i++) {
+            Message message = messages.get(i);
+            String subject = StrUtil.isNotBlank(message.getSubject()) ? message.getSubject() : "未命名";
+            ZipUtility.saveEmlFile(messages.get(i), tempDir.getPath() + "/" + subject + (i + 1) + ".eml");
+        }
+        File downloadFile = new File(tempDir.getPath());
+        if (!downloadFile.exists()) {
+            downloadFile.mkdirs();
+        }
+        File zipFile = new File(zipFilePath + File.separator + "emails" + currentUserId + ".zip");
+        try {
+            ZipUtility.zipFiles(tempDir, zipFile);
+        } catch (IOException e) {
+            return;
+        }
+        try {
+            FileInputStream inStream = new FileInputStream(zipFile);
+            // 设置响应头
+            response.setContentType("application/zip");
+            response.setContentLength((int) zipFile.length());
+            response.setHeader("Content-Disposition", "attachment; filename=\"" + zipFile.getName() + "\"");
+            // 获取输出流
+            OutputStream outStream = response.getOutputStream();
+            byte[] buffer = new byte[1024];
+            int bytesRead;
+
+            // 写入响应输出流
+            while ((bytesRead = inStream.read(buffer)) != -1) {
+                outStream.write(buffer, 0, bytesRead);
+            }
+        } catch (Exception e) {
+            log.error("Error occurred while downloading the file: ", e);
+        } finally {
+            ZipUtility.deleteDirectory(tempDir);
+        }
+    }
+
+
+    @PostMapping(value = "/download_mail_eml")
+    @ApiOperation(value = "下载邮件")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public void downloadMail(MailDTO dto, HttpServletResponse response) throws MessagingException {
+        if (Objects.isNull(dto.getMailId())) {
+            return;
+        }
+        EmailsEntity entitie = emailsService.getById(dto.getMailId());
+        if (Objects.isNull(entitie)) {
+            return;
+        }
+        String zipFilePath = mailFileProperties.getPath().getPath() + "temp_eml_files";
+        File tempDir = new File(zipFilePath + File.separator + "temp");
+        if (!tempDir.exists()) {
+            tempDir.mkdirs();
+        }
+
+        Message message = mailVoToMessages(entitie);
+        String subject = StrUtil.isNotBlank(message.getSubject()) ? message.getSubject() : "未命名";
+        String tempPath = tempDir.getPath() + "/" + subject + ".eml";
+        ZipUtility.saveEmlFile(message, tempPath);
+
+        File downloadFile = new File(tempPath);
+        if (!downloadFile.exists()) {
+            downloadFile.mkdirs();
+        }
+        try {
+            FileInputStream inStream = new FileInputStream(downloadFile);
+            // 设置响应头
+            response.reset();
+            response.setContentType("application/octet-stream;charset=utf-8");
+            /*
+             * 跨域配置
+             * */
+            response.addHeader("Access-Control-Allow-Origin", "*");
+            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
+            response.addHeader("Access-Control-Allow-Headers", "Content-Type");
+//        String filename = "测试.docx";
+            String filename = downloadFile.getName();
+            response.addHeader("content-disposition",
+                    "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")
+                            + ";filename*=utf-8''" + URLEncoder.encode(filename, "UTF-8"));
+//		response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
+            byte[] b = new byte[1024];
+            int len;
+//从输入流中读取一定数量的字节,并将其存储在缓冲区字节数组中,读到末尾返回-1
+            ServletOutputStream outputStream = response.getOutputStream();
+            while ((len = inStream.read(b)) > 0) {
+                outputStream.write(b, 0, len);
+            }
+            inStream.close();
+            outputStream.close();
+        } catch (Exception e) {
+            log.error("Error occurred while downloading the file: ", e);
+        } finally {
+            ZipUtility.deleteDirectory(tempDir);
+        }
+    }
+
+    public Message mailVoToMessages(EmailsEntity emails) {
+        try {
+            List<String> recipientls = new ArrayList<>();
+            if (StrUtil.isNotBlank(emails.getRecipient())) {
+                recipientls = Arrays.asList(emails.getRecipient().split(","));
+            }
+
+            List<String> recipientCcls = new ArrayList<>();
+            if (StrUtil.isNotBlank(emails.getRecipientCc())) {
+                recipientCcls = Arrays.asList(emails.getRecipientCc().split(","));
+            }
+            List<String> recipientBccls = new ArrayList<>();
+            if (StrUtil.isNotBlank(emails.getRecipientBcc())) {
+                recipientBccls = Arrays.asList(emails.getRecipientBcc().split(","));
+            }
+
+            String fromAddress = emails.getFrom();
+
+            InternetAddress[] froms = new InternetAddress[recipientls.size()];
+            for (int i = 0; i < recipientls.size(); i++) {
+                froms[i] = new InternetAddress(recipientls.get(i));
+            }
+            InternetAddress[] fromsCC = new InternetAddress[recipientCcls.size()];
+            for (int i = 0; i < recipientCcls.size(); i++) {
+                fromsCC[i] = new InternetAddress(recipientCcls.get(i));
+            }
+            InternetAddress[] fromsBCC = new InternetAddress[recipientBccls.size()];
+            for (int i = 0; i < recipientBccls.size(); i++) {
+                fromsBCC[i] = new InternetAddress(recipientBccls.get(i));
+            }
+
+            Message message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+            if (Objects.nonNull(froms) && froms.length > 0) {
+                message.setRecipients(Message.RecipientType.TO, froms);
+            }
+            if (Objects.nonNull(fromsCC) && fromsCC.length > 0) {
+                message.setRecipients(Message.RecipientType.CC, fromsCC);
+            }
+            if (Objects.nonNull(fromsBCC) && fromsBCC.length > 0) {
+                message.setRecipients(Message.RecipientType.BCC, fromsBCC);
+            }
+
+            LambdaQueryWrapper fileWrapper = new LambdaQueryWrapper<MailTempAttachmentEntity>().in(MailTempAttachmentEntity::getEmailId, emails.getId());
+            List<MailTempAttachmentEntity> tempAttachment = tempAttachmentService.list(fileWrapper);
+            if (CollectionUtils.isEmpty(tempAttachment)) {
+                message.setFrom(new InternetAddress(fromAddress));
+                message.setSubject(emails.getSubject());
+                message.setContent(emails.getContent(), "text/html; charset=UTF-8");
+            } else {
+                message.setFrom(new InternetAddress(fromAddress));
+                message.setDescription(emails.getRemark());
+                // 设置邮件主题
+                message.setSubject(emails.getSubject());
+                // 创建消息部分
+                Multipart multipart = new MimeMultipart();
+//                    // 消息正文
+                BodyPart messageBodyPart1 = new MimeBodyPart();
+                messageBodyPart1.setContent(emails.getContent(), "text/html; charset=UTF-8");
+                multipart.addBodyPart(messageBodyPart1);
+//                    message.add(dto.getContent(), "UTF-8","text/html");
+                // 创建一个多部分消息
+
+                // 设置文本消息部分
+                for (MailTempAttachmentEntity attachment : tempAttachment) {
+                    BodyPart messageBodyPart = new MimeBodyPart();
+                    String filePath = mailFileProperties.getPath().getPath() + attachment.getFilePath();
+                    messageBodyPart = new MimeBodyPart();
+                    String fileName = attachment.getFileName() + "." + attachment.getFileExt();
+                    DataSource fileSource = new FileDataSource(filePath);
+                    messageBodyPart.setDataHandler(new DataHandler(fileSource));
+                    messageBodyPart.setFileName(fileName);
+                    multipart.addBodyPart(messageBodyPart);
+                }
+                // 发送完整的消息部分
+                message.setContent(multipart);
+                // 获取邮件大小
+            }
+            return message;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    @PostMapping(value = "/mv_mail_box")
+    @ApiOperation(value = "移动邮件")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> mvMailBox(MailMoveDTO dto) {
+        if (Objects.isNull(dto.getEmailId()) || Objects.isNull(dto.getBoxCode())) {
+            return Result.error("参数错误!");
+        }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        EmailBoxEnum boxEnum = EmailBoxEnum.getEnumByCode(dto.getBoxCode());
+        if (Objects.isNull(boxEnum)) {
+            return Result.error("参数错误!");
+        }
+        EmailsEntity entity = emailsService.getById(dto.getEmailId());
+        if (Objects.nonNull(entity) && entity.getOwnerBy().equals(currentUserId)) {
+            entity.setFolder(boxEnum.code);
+            entity.setUpdateBy(currentUserId);
+            emailsService.updateById(entity);
+            return Result.ok();
+        } else {
+            return Result.error("参数错误!");
+        }
+    }
+
+
+
+
+    @PostMapping(value = "/mark_trash")
+    @ApiOperation(value = "垃圾箱")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> mvTrashBox(MailMoveDTO dto) {
+        if (Objects.isNull(dto.getEmailId()) && StringUtils.isEmpty(dto.getEmailIds())) {
+            return Result.error("参数错误!");
+        }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        LambdaUpdateWrapper<EmailsEntity> uWrapper = new LambdaUpdateWrapper<>();
+        uWrapper.set(EmailsEntity::getIsTrash, dto.getIsTrash());
+        uWrapper.eq(EmailsEntity::getOwnerBy, currentUserId);
+        if (Objects.nonNull(dto.getEmailId())) {
+            uWrapper.eq(EmailsEntity::getId, dto.getEmailId());
+        } else {
+            uWrapper.in(EmailsEntity::getId, dto.getEmailIds());
+        }
+        emailsService.update(uWrapper);
+        return Result.ok();
+    }
+
+    @ApiOperation(value = "彻底删除")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = Result.class)
+    })
+    @PostMapping("/deleteIds")
+    public Result<?> deleteIds(Long[] ids) {
+        if (Objects.isNull(ids)) {
+            return Result.error("参数错误");
+        }
+        LambdaUpdateWrapper<EmailsEntity> uWrapper = new LambdaUpdateWrapper<>();
+        uWrapper.set(EmailsEntity::getIsDelete, Integer.valueOf(1));
+        uWrapper.in(EmailsEntity::getId, Arrays.asList(ids));
+        emailsService.update(uWrapper);
+        return Result.ok();
+    }
+
+    @ApiOperation(value = "彻底删除草稿")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = Result.class)
+    })
+    @PostMapping("/deleteDraftIds")
+    public Result<?> deleteDraftIds(Long[] ids) {
+        if (Objects.isNull(ids)) {
+            return Result.error("删除草稿");
+        }
+        LambdaUpdateWrapper<EmailsEntity> uWrapper = new LambdaUpdateWrapper<>();
+        uWrapper.in(EmailsEntity::getId, Arrays.asList(ids));
+        emailsService.remove(uWrapper);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/get_mail_detial")
+    @ApiOperation(value = "获取详情接口")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> getMailDetial(Long mailId) {
+        if (Objects.isNull(mailId)) {
+            return Result.error("参数错误!");
+        }
+        EmailsEntity email = emailsService.getById(mailId);
+        if (Objects.nonNull(email) && 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 -> {
+                    e.setFileSizeName(FileHelper.formatFileSize(e.getFileSize()));
+                });
+            }
+            email.setAttachments(atts);
+        } else {
+            List<MailAttachmentEntity> atts = mailAttachmentService.list(new LambdaQueryWrapper<MailAttachmentEntity>().eq(MailAttachmentEntity::getEmailId, mailId));
+            if (!CollectionUtils.isEmpty(atts)) {
+                atts.forEach(e -> {
+                    e.setFileSizeName(FileHelper.formatFileSize(e.getFileSize()));
+                });
+            }
+            email.setAttachments(atts);
+        }
+
+        return Result.result(email);
+    }
+
+    @PostMapping(value = "/mv_custom_folder")
+    @ApiOperation(value = "迁移邮件到自定义文件夹", notes = "迁移邮件到自定义文件夹")
+    public Result getMailPortConfig(Long[] mailIds, Long folderId) {
+        if (Objects.isNull(mailIds) || Objects.isNull(folderId)) {
+            return Result.error("参数错误");
+        }
+        LambdaUpdateWrapper<EmailsEntity> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.set(EmailsEntity::getCustomFolderId, folderId);
+        updateWrapper.in(EmailsEntity::getId, Arrays.asList(mailIds));
+        emailsService.update(updateWrapper);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/del_custom_folder_mail")
+    @ApiOperation(value = "获取邮箱端口配置", notes = "获取邮箱端口配置")
+    public Result delCustomFolderMail(Long[] mailIds) {
+        if (Objects.isNull(mailIds)) {
+            return Result.error("参数错误");
+        }
+        LambdaUpdateWrapper<EmailsEntity> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.in(EmailsEntity::getId, Arrays.asList(mailIds));
+        updateWrapper.set(EmailsEntity::getCustomFolderId, null);
+        emailsService.update(updateWrapper);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/mark_star")
+    @ApiOperation(value = "星标")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> takeStar(MailMoveDTO dto) {
+        if (Objects.isNull(dto.getEmailId()) && StringUtils.isEmpty(dto.getEmailIds())) {
+            return Result.error("参数错误!");
+        }
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        LambdaUpdateWrapper<EmailsEntity> uWrapper = new LambdaUpdateWrapper<>();
+        uWrapper.set(EmailsEntity::getIsStar, dto.getIsStar());
+        uWrapper.eq(EmailsEntity::getOwnerBy, currentUserId);
+        if (Objects.nonNull(dto.getEmailId())) {
+            uWrapper.eq(EmailsEntity::getId, dto.getEmailId());
+        } else {
+            uWrapper.in(EmailsEntity::getId, dto.getEmailIds());
+        }
+        emailsService.update(uWrapper);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/mark_read")
+    @ApiOperation(value = "已读未读标记")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> markRead(MailMoveDTO dto) {
+        if (Objects.isNull(dto.getEmailId()) && StringUtils.isEmpty(dto.getEmailIds())) {
+            return Result.error("参数错误!");
+        }
+        LambdaUpdateWrapper<EmailsEntity> uWrapper = new LambdaUpdateWrapper<>();
+        uWrapper.set(EmailsEntity::getIsRead, dto.getIsRead());
+        if (Objects.nonNull(dto.getEmailId())) {
+            uWrapper.eq(EmailsEntity::getId, dto.getEmailId());
+        } else {
+            uWrapper.in(EmailsEntity::getId, dto.getEmailIds());
+        }
+        emailsService.update(uWrapper);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/mark_reply_msg_id")
+    @ApiOperation(value = "标记陌生客户回复不回复")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> markReplyMsgId(MailMoveDTO dto) {
+        if (Objects.isNull(dto.getEmailId()) && StringUtils.isEmpty(dto.getEmailIds())) {
+            return Result.error("参数错误!");
+        }
+        LambdaUpdateWrapper<EmailsEntity> uWrapper = new LambdaUpdateWrapper<>();
+        uWrapper.set(EmailsEntity::getReplyMsgId, dto.getReplyMsgId());
+        if (Objects.nonNull(dto.getEmailId())) {
+            uWrapper.eq(EmailsEntity::getId, dto.getEmailId());
+        } else {
+            uWrapper.in(EmailsEntity::getId, dto.getEmailIds());
+        }
+        emailsService.update(uWrapper);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/mark_all_read")
+    @ApiOperation(value = "已读未读标记")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> markAllRead() {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (Objects.isNull(currentUserId)) {
+            return Result.error("登录失效,请重新登陆!");
+        }
+        LambdaUpdateWrapper<EmailsEntity> uWrapper = new LambdaUpdateWrapper<>();
+        uWrapper.set(EmailsEntity::getIsRead, Integer.valueOf(1));
+        uWrapper.eq(EmailsEntity::getOwnerBy, currentUserId);
+        uWrapper.eq(EmailsEntity::getIsRead, Integer.valueOf(0));
+        emailsService.update(uWrapper);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/list_mail_attachment")
+    @ApiOperation(value = "邮件附件")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result listMailAttachment(AttachmentDTO dto) {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        SmtpPopSettingsEntity emailPop = smtpPopSettingsService.getDefaultSmtpPop(currentUserId);
+        if (Objects.isNull(emailPop)) {
+            return Result.result(null);
+        }
+
+        QueryWrapper<MailAttachmentEntity> queryWrapper = new QueryWrapper();
+        queryWrapper.eq("att.smtp_pop_id", emailPop.getId());
+
+        if (StrUtil.isNotBlank(dto.getFileExt())) {
+            if ("png".equals(dto.getFileExt())) {
+                queryWrapper.in("att.file_ext", Arrays.asList("png", "jpg"));
+            } else if ("video".equals(dto.getFileExt())) {
+                queryWrapper.in("att.file_ext", Arrays.asList("mp4", "video"));
+            } else if ("zip".equals(dto.getFileExt())) {
+                queryWrapper.in("att.file_ext", Arrays.asList("zip", "rar", "7z"));
+            } else if ("txt".equals(dto.getFileExt())) {
+                queryWrapper.in("att.file_ext", Arrays.asList("pdf", "word", "excel"));
+            } else {
+                queryWrapper.eq("att.file_ext", dto.getFileExt());
+            }
+        }
+        Page<MailAttachmentEntity> page = new Page<>(dto.getPageIndex(), dto.getPageSize());
+
+        queryWrapper.eq("att.is_delete", CommonConstant.DEL_FLAG_0);
+        queryWrapper.eq("e.smtp_pop_id", emailPop.getId());
+
+        queryWrapper.orderByDesc("e.sent_date");
+
+        IPage<MailAttachmentEntity> pageList = mailAttachmentService.pateList(page, queryWrapper);
+
+        Map<Long, String> emailMap = new HashMap<>();
+        if (!CollectionUtils.isEmpty(pageList.getRecords())) {
+            List<Long> mailIds = pageList.getRecords().stream().map(MailAttachmentEntity::getEmailId).collect(Collectors.toList());
+            LambdaQueryWrapper<EmailsEntity> eQueryWrapper = new LambdaQueryWrapper<>();
+            eQueryWrapper.in(EmailsEntity::getId, mailIds);
+            List<EmailsEntity> emails = emailsService.list(eQueryWrapper);
+            if (!CollectionUtils.isEmpty(emails)) {
+                emailMap = emails.stream().collect(Collectors.toMap(EmailsEntity::getId, EmailsEntity::getSubject));
+            }
+            Map<Long, String> finalEmailMap = emailMap;
+            pageList.getRecords().forEach(e -> {
+                e.setFileSizeName(FileHelper.formatFileSize(e.getFileSize()));
+                e.setSubject(finalEmailMap.get(e.getEmailId()));
+            });
+        }
+        return Result.result(pageList);
+    }
+
+
+    @PostMapping(value = "/download_zip")
+    @ApiOperation(value = "打包下载")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public void downloadZip(AttachmentDTO dto, HttpServletResponse response) {
+        if (Objects.isNull(dto.getMailId()) && CollectionUtils.isEmpty(dto.getAttachmentIds())) {
+            return;
+        }
+        String zipFilePath = mailFileProperties.getPath().getPath() + System.currentTimeMillis() + RandomGenerateHelper.generateRandomString(6) + ".zip";
+        List<MailAttachmentEntity> attachments;
+        if (Objects.nonNull(dto.getMailId())) {
+            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)));
+        }
+        if (CollectionUtils.isEmpty(attachments)) {
+            return;
+        }
+        try {
+            ZipUtility.zipFiles(attachments, zipFilePath, mailFileProperties);
+        } catch (IOException e) {
+            return;
+        }
+        File downloadFile = new File(zipFilePath);
+        try {
+            FileInputStream inStream = new FileInputStream(downloadFile);
+            // 设置响应头
+            response.setContentType("application/zip");
+            response.setContentLength((int) downloadFile.length());
+            response.setHeader("Content-Disposition", "attachment; filename=\"" + downloadFile.getName() + "\"");
+            // 获取输出流
+            OutputStream outStream = response.getOutputStream();
+            byte[] buffer = new byte[1024];
+            int bytesRead;
+
+            // 写入响应输出流
+            while ((bytesRead = inStream.read(buffer)) != -1) {
+                outStream.write(buffer, 0, bytesRead);
+            }
+        } catch (Exception e) {
+            log.error("Error occurred while downloading the file: ", e);
+        } finally {
+            // 下载完成后删除临时ZIP文件
+            if (downloadFile.exists()) {
+                if (!downloadFile.delete()) {
+                    System.err.println("Failed to delete the temporary file: " + zipFilePath);
+                }
+            }
+        }
+    }
+
+    @PostMapping(value = "/download_url")
+    @ApiOperation(value = "下载", notes = "下载")
+    public Result downloadUrl(Long attachmentId) throws IOException {
+        try {
+            if (attachmentId == null) {
+                return Result.error("附未找到");
+            }
+            MailAttachmentEntity attachment = mailAttachmentService.getById(attachmentId);
+            if (attachment == null) {
+                return Result.error("附未找到");
+            }
+
+            String url =  mailFileProperties.getPath().getPath() + File.separator + attachment.getFilePath();
+
+
+            // 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();
+
+            Path target = Paths.get(exportDir.getAbsolutePath());
+            // 创建目标目录(如果不存在)
+            if (!Files.exists(target.getParent())) {
+                Files.createDirectories(target.getParent());
+            }
+            Path targetPath = target.resolve(fileName);
+            Files.copy(filePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
+
+            // 2. 拼接 URL(这里假设映射后访问路径是 /export/)
+            String fileUrl = "/static/file/" + targetPath.getFileName();
+
+            String domainUrl = "";
+            if(active.equals("prod")) {
+                domainUrl = "https://sales.storlead.com"+fileUrl;
+            } else if (active.equals("test")){
+                domainUrl = "https://sales.test.storlead.com"+fileUrl;
+            } else if (active.equals("dev")){
+                domainUrl = "http://localhost:"+port+fileUrl;
+            }
+            return Result.result(domainUrl);
+        } catch (Exception e) {
+            log.error("download--error", e);
+            return Result.error("附未找到");
+        }
+    }
+
+    @PostMapping(value = "/draft_download_url")
+    @ApiOperation(value = "下载", notes = "下载")
+    public Result draft_download(Long attachmentId) throws IOException {
+        try {
+            if (attachmentId == null) {
+                return Result.error("附未找到");
+            }
+            MailTempAttachmentEntity attachment = tempAttachmentService.getById(attachmentId);
+            if (attachment == null) {
+                return Result.error("附未找到");
+            }
+
+            String url =  mailFileProperties.getPath().getPath() + File.separator + attachment.getFilePath();
+
+            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();
+
+            Path target = Paths.get(exportDir.getAbsolutePath());
+            // 创建目标目录(如果不存在)
+            if (!Files.exists(target.getParent())) {
+                Files.createDirectories(target.getParent());
+            }
+            Path targetPath = target.resolve(fileName);
+            Files.copy(filePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
+
+            // 2. 拼接 URL(这里假设映射后访问路径是 /export/)
+            String fileUrl = "/static/file/" + targetPath.getFileName();
+
+            String domainUrl = "";
+            if(active.equals("prod")) {
+                domainUrl = "https://sales.storlead.com"+fileUrl;
+            } else if (active.equals("test")){
+                domainUrl = "https://sales.test.storlead.com"+fileUrl;
+            } else if (active.equals("dev")){
+                domainUrl = "http://localhost:"+port+fileUrl;
+            }
+            return Result.result(domainUrl);
+        } catch (Exception e) {
+            log.error("download--error", e);
+            return Result.error("附未找到");
+        }
+    }
+
+    @PostMapping(value = "/draft_download")
+    @ApiOperation(value = "下载", notes = "下载")
+    public void draft_download(Long attachmentId, HttpServletResponse response) throws IOException {
+        try {
+            if (attachmentId == null) {
+                return;
+            }
+            MailTempAttachmentEntity attachment = tempAttachmentService.getById(attachmentId);
+            if (attachment == null) {
+                return;
+            }
+            InputStream inputStream;
+            String url = mailFileProperties.getPath().getPath() + attachment.getFilePath();
+            inputStream = new BufferedInputStream(new FileInputStream(url));
+            response.reset();
+            response.setContentType("application/octet-stream;charset=utf-8");
+            /*
+             * 跨域配置
+             * */
+            response.addHeader("Access-Control-Allow-Origin", "*");
+            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
+            response.addHeader("Access-Control-Allow-Headers", "Content-Type");
+//        String filename = "测试.docx";
+            String filename = attachment.getFileName() + "." + attachment.getFileExt();
+            response.addHeader("content-disposition",
+                    "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")
+                            + ";filename*=utf-8''" + URLEncoder.encode(filename, "UTF-8"));
+//		response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
+            byte[] b = new byte[1024];
+            int len;
+//从输入流中读取一定数量的字节,并将其存储在缓冲区字节数组中,读到末尾返回-1
+            ServletOutputStream outputStream = response.getOutputStream();
+            while ((len = inputStream.read(b)) > 0) {
+                outputStream.write(b, 0, len);
+            }
+            inputStream.close();
+            outputStream.close();
+        } catch (Exception e) {
+            log.error("download--error", e);
+        }
+    }
+
+    @RequestMapping(value = "/download")
+    @ApiOperation(value = "下载", notes = "下载")
+    public void download(Long attachmentId, HttpServletResponse response) throws IOException {
+        try {
+            if (attachmentId == null) {
+                return;
+            }
+            MailAttachmentEntity attachment = mailAttachmentService.getById(attachmentId);
+            if (attachment == null) {
+                return;
+            }
+            InputStream inputStream;
+            String url = mailFileProperties.getPath().getPath() + attachment.getFilePath();
+            if (Integer.valueOf(0).equals(attachment.getDownload())) {
+                if (new File(url).exists()) {
+                    LambdaUpdateWrapper<MailAttachmentEntity> attachmentUpdate = new LambdaUpdateWrapper<>();
+                    attachmentUpdate.set(MailAttachmentEntity::getDownload, Integer.valueOf(1));
+                    attachmentUpdate.eq(MailAttachmentEntity::getId, attachment.getId());
+                    mailAttachmentService.update(attachmentUpdate);
+                }
+                //没有下载
+                EmailsEntity email = emailsService.getById(attachment.getEmailId());
+                SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getById(email.getSmtpPopId());
+                inputStream = emailsService.loadEmailsFile(smtpPop, email, attachment.getFileName() + "." + attachment.getFileExt());
+                if (Objects.isNull(inputStream)) {
+                    return;
+                }
+                String path = mailFileProperties.getPath().getPath() + attachment.getFilePath();
+                File file = new File(path);
+                try (FileOutputStream output = new FileOutputStream(file)) {
+                    inputStream.transferTo(output);
+                }
+                LambdaUpdateWrapper<MailAttachmentEntity> attachmentUpdate = new LambdaUpdateWrapper<>();
+                attachmentUpdate.set(MailAttachmentEntity::getDownload, Integer.valueOf(1));
+                attachmentUpdate.set(MailAttachmentEntity::getFileSize, file.length());
+                attachmentUpdate.eq(MailAttachmentEntity::getId, attachment.getId());
+                mailAttachmentService.update(attachmentUpdate);
+            }
+            inputStream = new BufferedInputStream(new FileInputStream(url));
+            response.reset();
+            /*
+             * 跨域配置
+             * */
+            response.addHeader("Access-Control-Allow-Origin", "*");
+            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
+            response.addHeader("Access-Control-Allow-Headers", "Content-Type");
+//        String filename = "测试.docx";
+            String filename = attachment.getFileName() + "." + attachment.getFileExt();
+
+            String ext = attachment.getFileExt().toLowerCase();
+            boolean inline = ext.equals("pdf")
+                    || ext.equals("png")
+                    || ext.equals("jpg")
+                    || ext.equals("jpeg")
+                    || ext.equals("gif");
+            if (inline) {
+                if ("pdf".equals(ext)) {
+                    response.setContentType("application/pdf");
+                } else {
+                    response.setContentType("image/" + ext);
+                }
+            } else {
+//                response.setContentType("application/octet-stream");
+                response.setContentType("application/octet-stream;charset=utf-8");
+            }
+            String dispositionType = inline ? "inline" : "attachment";
+            response.setHeader(
+                    "Content-Disposition",
+                    dispositionType + "; filename=" + URLEncoder.encode(filename, "UTF-8")
+                            + ";filename*=utf-8''" + URLEncoder.encode(filename, "UTF-8"));
+
+//            response.addHeader("content-disposition",
+//                    "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")
+//                            + ";filename*=utf-8''" + URLEncoder.encode(filename, "UTF-8"));
+//		response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
+            byte[] b = new byte[1024];
+            int len;
+//从输入流中读取一定数量的字节,并将其存储在缓冲区字节数组中,读到末尾返回-1
+            ServletOutputStream outputStream = response.getOutputStream();
+            while ((len = inputStream.read(b)) > 0) {
+                outputStream.write(b, 0, len);
+            }
+            inputStream.close();
+            outputStream.close();
+        } catch (Exception e) {
+            log.error("download--error", e);
+        }
+    }
+
+    // 读取 InputStream 并计算其大小
+    public int getAttachmentSize(InputStream inputStream) throws Exception {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        byte[] buffer = new byte[4096];
+        int bytesRead;
+        while ((bytesRead = inputStream.read(buffer)) != -1) {
+            byteArrayOutputStream.write(buffer, 0, bytesRead);
+        }
+        return byteArrayOutputStream.size();
+    }
+
+    public InputStream copyInputStream(InputStream original) throws IOException {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        byte[] buffer = new byte[4096];
+        int bytesRead;
+        while ((bytesRead = original.read(buffer)) != -1) {
+            byteArrayOutputStream.write(buffer, 0, bytesRead);
+        }
+        // 生成的字节数组可以用来创建多个 InputStream 副本
+        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
+    }
+
+    @PostMapping(value = "/mail_port_config")
+    @ApiOperation(value = "获取邮箱端口配置", notes = "获取邮箱端口配置")
+    public Result getMailPortConfig(String mailAccount) throws IOException {
+        if (StrUtil.isBlank(mailAccount)) {
+            return Result.result("参数错误");
+        }
+        LambdaQueryWrapper<MailServerPortConfigEntity> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(MailServerPortConfigEntity::getMailServerSuffix, EmailServiceChecker.getEmailService(mailAccount));
+        queryWrapper.last("limit 1");
+        MailServerPortConfigEntity portConfig = serverPortConfigService.getOne(queryWrapper);
+        return Result.result(portConfig);
+    }
+
+
+    private static String formatDate(Date date) {
+        if (date == null) return "N/A";
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        return sdf.format(date);
+    }
+
+    private static String decodeAddresses(Address[] addresses) throws MessagingException {
+        try {
+            if (addresses == null) return "[]";
+            String[] decodedAddresses = new String[addresses.length];
+            for (int i = 0; i < addresses.length; i++) {
+                decodedAddresses[i] = MimeUtility.decodeText(addresses[i].toString());
+            }
+            return Arrays.toString(decodedAddresses);
+        } catch (Exception e) {
+            return "";
+        }
+    }
+
+    private Path saveTempFile(MultipartFile file) throws IOException {
+        Path tempFilePath = Files.createTempFile("upload", ".zip");
+        file.transferTo(tempFilePath.toFile());
+        return tempFilePath;
+    }
+
+}

+ 133 - 0
storlead-api/src/main/java/com/storlead/mail/MailBlacklistRecordApiController.java

@@ -0,0 +1,133 @@
+package com.storlead.mail;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+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 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.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-10-31 10:51
+ */
+@RestController
+@RequestMapping("/email/blacklist")
+@Api(tags = "邮件系统:黑名单")
+@Log4j2
+public class MailBlacklistRecordApiController {
+
+    @Resource
+    private EmailBlacklistRecordService blacklistRecordService;
+
+    @Resource
+    private EmailsService emailsService;
+
+    @PostMapping(value = "/page_list")
+    @ApiOperation(value = "获取邮件模板" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> pageList(EmailTemplatesDTO dto) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        Page<EmailBlacklistRecordEntity> page = new Page<>(dto.getPageIndex(),dto.getPageSize());
+        LambdaQueryWrapper<EmailBlacklistRecordEntity> queryWrapper = new LambdaQueryWrapper();
+        queryWrapper.eq(EmailBlacklistRecordEntity::getOwnerBy,currentUserId);
+        queryWrapper.eq(EmailBlacklistRecordEntity::getIsDelete,Integer.valueOf(0));
+        IPage<EmailBlacklistRecordEntity> pageList = blacklistRecordService.page(page,queryWrapper);
+        return Result.result(pageList);
+    }
+
+    @PostMapping(value = "/list")
+    @ApiOperation(value = "获取邮件模板" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> list(EmailTemplatesDTO dto) {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        Page<EmailBlacklistRecordEntity> page = new Page<>(dto.getPageIndex(),dto.getPageSize());
+        LambdaQueryWrapper<EmailBlacklistRecordEntity> queryWrapper = new LambdaQueryWrapper();
+        queryWrapper.eq(EmailBlacklistRecordEntity::getOwnerBy,currentUserId);
+        queryWrapper.eq(EmailBlacklistRecordEntity::getIsDelete,Integer.valueOf(0));
+        queryWrapper.eq(EmailBlacklistRecordEntity::getEnabled,dto.getEnabled());
+        IPage<EmailBlacklistRecordEntity> pageList = blacklistRecordService.page(page,queryWrapper);
+        return Result.result(pageList);
+    }
+
+    @PostMapping(value = "/save")
+    @ApiOperation(value = "保存模板" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> save(EmailBlacklistRecordEntity entity) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (StrUtil.isBlank(entity.getEmailAddress())) {
+            return Result.error("邮箱不能为空");
+        }
+        LambdaQueryWrapper<EmailBlacklistRecordEntity> wrapper =new LambdaQueryWrapper<>();
+        wrapper.eq(EmailBlacklistRecordEntity::getEmailAddress,entity.getEmailAddress());
+        wrapper.eq(EmailBlacklistRecordEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+        wrapper.eq(EmailBlacklistRecordEntity::getOwnerBy,currentUserId);
+        wrapper.last(" limit 1");
+        EmailBlacklistRecordEntity record = blacklistRecordService.getOne(wrapper);
+        if (record != null){
+            return Result.error("该邮箱已在黑名单中已存在");
+        }
+        Boolean b = blacklistRecordService.saveOrUpdate(entity);
+        if (b) {
+            /** 将黑名单邮箱的邮件移到垃圾箱中 **/
+            LambdaUpdateWrapper<EmailsEntity> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(EmailsEntity::getOwnerBy,currentUserId);
+            updateWrapper.eq(EmailsEntity::getFolder, EmailBoxEnum.INBOX);
+            updateWrapper.eq(EmailsEntity::getFrom,entity.getEmailAddress());
+            updateWrapper.set(EmailsEntity::getIsTrash,1);
+            emailsService.update(updateWrapper);
+        }
+        return Result.ok();
+    }
+
+    @ApiOperation(value = "删除")
+    @PostMapping("deleteIds")
+    public Result delete(Long [] ids) {
+        if(Objects.isNull(ids)) {
+            return Result.error("参数错误");
+        }
+        blacklistRecordService.lgDelete(Arrays.asList(ids));
+        return Result.ok();
+    }
+
+
+    @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);
+        return Result.ok();
+    }
+}

+ 124 - 0
storlead-api/src/main/java/com/storlead/mail/MailTemplatesApiController.java

@@ -0,0 +1,124 @@
+package com.storlead.mail;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+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 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.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-05-29 16:02
+ */
+@RestController
+@RequestMapping("/email/templates")
+@Api(tags = "邮件系统:邮件模板")
+@Log4j2
+public class MailTemplatesApiController {
+
+    @Resource
+    private EmailTemplatesService templatesService;
+
+    @PostMapping(value = "/page_list")
+    @ApiOperation(value = "获取邮件模板" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> pageList(EmailTemplatesDTO dto) {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        Page<EmailTemplatesEntity> page = new Page<>(dto.getPageIndex(),dto.getPageSize());
+        LambdaQueryWrapper<EmailTemplatesEntity> queryWrapper = new LambdaQueryWrapper();
+        // queryWrapper.select(EmailTemplatesEntity::getId,EmailTemplatesEntity::getIsDelete,EmailTemplatesEntity::getTemplateTitle,EmailTemplatesEntity::getTemplateType,EmailTemplatesEntity::getCreateTime,EmailTemplatesEntity::getUpdateTime);
+        queryWrapper.eq(EmailTemplatesEntity::getOwnerBy,currentUserId);
+        if (Objects.nonNull(dto.getTemplateType())) {
+            queryWrapper.eq(EmailTemplatesEntity::getTemplateType,dto.getTemplateType());
+        }
+        queryWrapper.eq(EmailTemplatesEntity::getIsDelete,Integer.valueOf(0));
+        IPage<EmailTemplatesEntity> pageList = templatesService.page(page,queryWrapper);
+        return Result.result(pageList);
+    }
+
+    @PostMapping(value = "/getById")
+    @ApiOperation(value = "获取邮件模板详情" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> getById(Long id) {
+        EmailTemplatesEntity templatesEntity = templatesService.getById(id);
+        return Result.result(templatesEntity);
+    }
+
+
+    @PostMapping(value = "/list")
+    @ApiOperation(value = "获取邮件模板" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> list(EmailTemplatesDTO dto) {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        Page<EmailTemplatesEntity> page = new Page<>(dto.getPageIndex(),dto.getPageSize());
+        LambdaQueryWrapper<EmailTemplatesEntity> queryWrapper = new LambdaQueryWrapper();
+        queryWrapper.select(EmailTemplatesEntity::getId,EmailTemplatesEntity::getIsDelete,EmailTemplatesEntity::getTemplateTitle,EmailTemplatesEntity::getTemplateType,EmailTemplatesEntity::getCreateTime,EmailTemplatesEntity::getUpdateTime);
+        queryWrapper.eq(EmailTemplatesEntity::getOwnerBy,currentUserId);
+        queryWrapper.eq(EmailTemplatesEntity::getIsDelete,Integer.valueOf(0));
+        if (Objects.nonNull(dto.getTemplateType())) {
+            queryWrapper.eq(EmailTemplatesEntity::getTemplateType,dto.getTemplateType());
+        }
+        queryWrapper.eq(EmailTemplatesEntity::getEnabled,dto.getEnabled());
+        IPage<EmailTemplatesEntity> pageList = templatesService.page(page,queryWrapper);
+        return Result.result(pageList);
+    }
+
+    @PostMapping(value = "/save")
+    @ApiOperation(value = "保存模板" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> save(EmailTemplatesEntity entity) {
+        templatesService.saveOrUpdate(entity);
+        return Result.ok();
+    }
+
+    @ApiOperation(value = "删除")
+    @PostMapping("deleteIds")
+    public Result delete(Long [] ids) {
+        if(Objects.isNull(ids)) {
+            return Result.error("参数错误");
+        }
+        templatesService.lgDelete(Arrays.asList(ids));
+        return Result.ok();
+    }
+
+
+    @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);
+        return Result.ok();
+    }
+}

+ 137 - 0
storlead-api/src/main/java/com/storlead/mail/MailboxAutoReplySetController.java

@@ -0,0 +1,137 @@
+package com.storlead.mail;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+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 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.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 邮箱自动回复内容 前端控制器
+ * </p>
+ *
+ * @author chenkq
+ * @since 2025-02-24
+ */
+@RestController
+@RequestMapping("/mail/mailbox/reply")
+@Api(tags = "020.邮件管理相关接口")
+@Log4j2
+public class MailboxAutoReplySetController {
+
+    @Resource
+    private MailboxAutoReplySetService replySetService;
+
+    @Resource
+    private SmtpPopSettingsService popSettingsService;
+
+    @PostMapping(value = "/page_list")
+    @ApiOperation(value = "获取邮件自动回复配置" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = MailboxAutoReplySetEntity.class)
+    })
+    public Result<?> pageList(EmailTemplatesDTO dto) {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        Page<MailboxAutoReplySetEntity> page = new Page<>(dto.getPageIndex(),dto.getPageSize());
+        LambdaQueryWrapper<MailboxAutoReplySetEntity> queryWrapper = new LambdaQueryWrapper();
+        queryWrapper.eq(MailboxAutoReplySetEntity::getOwnerBy,currentUserId);
+        queryWrapper.eq(MailboxAutoReplySetEntity::getIsDelete,Integer.valueOf(0));
+        IPage<MailboxAutoReplySetEntity> pageList = replySetService.page(page,queryWrapper);
+        if (!CollectionUtils.isEmpty(pageList.getRecords())) {
+            List<Long> popIds = pageList.getRecords().stream().map(MailboxAutoReplySetEntity::getSmtpPopId).collect(Collectors.toList());
+            List<SmtpPopSettingsEntity> smtpPopSettings = popSettingsService.list(new LambdaQueryWrapper<SmtpPopSettingsEntity>().in(SmtpPopSettingsEntity::getId, popIds));
+            if (!CollectionUtils.isEmpty(smtpPopSettings)) {
+                Map<Long,String> smtpPopMap =  smtpPopSettings.stream().collect(Collectors.toMap(SmtpPopSettingsEntity::getId,SmtpPopSettingsEntity::getEmailAddress, (existing, replacement) -> existing));
+                pageList.getRecords().forEach(e -> {
+                    e.setMailAddress(smtpPopMap.get(e.getSmtpPopId()));
+                });
+            }
+        }
+        return Result.result(pageList);
+    }
+
+    @PostMapping(value = "/list")
+    @ApiOperation(value = "获取邮件模板" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = MailboxAutoReplySetEntity.class)
+    })
+    public Result<?> list(EmailTemplatesDTO dto) {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        Page<MailboxAutoReplySetEntity> page = new Page<>(dto.getPageIndex(),dto.getPageSize());
+        LambdaQueryWrapper<MailboxAutoReplySetEntity> queryWrapper = new LambdaQueryWrapper();
+        queryWrapper.eq(MailboxAutoReplySetEntity::getOwnerBy,currentUserId);
+        queryWrapper.eq(MailboxAutoReplySetEntity::getIsDelete,Integer.valueOf(0));
+        queryWrapper.eq(MailboxAutoReplySetEntity::getEnabled,dto.getEnabled());
+        IPage<MailboxAutoReplySetEntity> pageList = replySetService.page(page,queryWrapper);
+        if (!CollectionUtils.isEmpty(pageList.getRecords())) {
+           List<Long> popIds = pageList.getRecords().stream().map(MailboxAutoReplySetEntity::getSmtpPopId).collect(Collectors.toList());
+           List<SmtpPopSettingsEntity> smtpPopSettings = popSettingsService.list(new LambdaQueryWrapper<SmtpPopSettingsEntity>().in(SmtpPopSettingsEntity::getId, popIds));
+           if (!CollectionUtils.isEmpty(smtpPopSettings)) {
+              Map<Long,String> smtpPopMap =  smtpPopSettings.stream().collect(Collectors.toMap(SmtpPopSettingsEntity::getId,SmtpPopSettingsEntity::getEmailAddress, (existing, replacement) -> existing));
+               pageList.getRecords().forEach(e -> {
+                   e.setMailAddress(smtpPopMap.get(e.getSmtpPopId()));
+               });
+           }
+        }
+        return Result.result(pageList);
+    }
+
+    @PostMapping(value = "/save")
+    @ApiOperation(value = "保存" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = MailboxAutoReplySetEntity.class)
+    })
+    public Result<?> save(MailboxAutoReplySetEntity entity) {
+        replySetService.saveOrUpdate(entity);
+        return Result.ok();
+    }
+
+    @ApiOperation(value = "删除")
+    @PostMapping("deleteIds")
+    public Result delete(Long [] ids) {
+        if(Objects.isNull(ids)) {
+            return Result.error("参数错误");
+        }
+        replySetService.lgDelete(Arrays.asList(ids));
+        return Result.ok();
+    }
+
+
+    @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);
+        return Result.ok();
+    }
+
+}

+ 442 - 0
storlead-api/src/main/java/com/storlead/mail/SmtpPopMailApiController.java

@@ -0,0 +1,442 @@
+package com.storlead.mail;//package com.storlead.sales.mail;
+//
+//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+//import com.baomidou.mybatisplus.core.metadata.IPage;
+//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+//import com.storlead.common.util.DateUtils;
+//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.sun.mail.imap.IMAPFolder;
+//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.mail.javamail.JavaMailSender;
+//import org.springframework.mail.javamail.MimeMessageHelper;
+//import org.springframework.util.CollectionUtils;
+//import org.springframework.web.bind.annotation.*;
+//import org.springframework.web.multipart.MultipartFile;
+//
+//import javax.annotation.Resource;
+//import javax.mail.*;
+//import javax.mail.internet.InternetAddress;
+//import javax.mail.internet.MimeMessage;
+//import javax.mail.internet.MimeUtility;
+//import javax.mail.search.ComparisonTerm;
+//import javax.mail.search.ReceivedDateTerm;
+//import javax.mail.search.SearchTerm;
+//import java.io.File;
+//import java.io.FileOutputStream;
+//import java.io.IOException;
+//import java.text.SimpleDateFormat;
+//import java.util.*;
+//import java.util.stream.Collectors;
+//
+///**
+// * @program: sp-sales-platform
+// * @description:
+// * @author: chenkq
+// * @create: 2024-05-29 16:02
+// */
+//@RestController
+//@RequestMapping("/mail")
+//@Api(tags = "020.邮件管理相关接口")
+//public class SmtpPopMailApiController {
+//
+////    @Resource
+////    private JavaMailSender mailSender;
+//
+//    @Resource
+//    private EmailsService emailsService;
+//
+//    @Resource
+//    private MailFileProperties mailFileProperties;
+//
+//    @Resource
+//    private MailAttachmentService mailAttachmentService;
+//
+//    @Resource
+//    private SmtpPopSettingsService smtpPopSettingsService;
+//
+//
+//    @PostMapping(value = "/pageList")
+//    @ApiOperation(value = "获取邮件" )
+//    @ApiResponses({
+//            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+//    })
+//    public Result<?> pageList(com.storlead.common.object.Page dto) {
+//        Long currentUserId = LoginUserUtil.getCurrentUserId();
+//        SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getDefaultSmtpPop(currentUserId);
+//
+//        if (Objects.isNull(currentUserId) && Objects.nonNull(smtpPop)) {
+//            return Result.result(null);
+//        }
+//        Page<EmailsEntity> page = new Page<>(dto.getPageIndex(),dto.getPageSize());
+//        LambdaQueryWrapper<EmailsEntity> queryWrapper = new LambdaQueryWrapper();
+//        queryWrapper.eq(EmailsEntity::getOwnerBy,currentUserId);
+//        queryWrapper.eq(EmailsEntity::getFrom,smtpPop.getEmailAddress());
+//        IPage<EmailsEntity> pageList = emailsService.page(page,queryWrapper);
+//        return Result.result(pageList);
+//    }
+//
+//    @PostMapping(value = "/sendMail")
+//    @ApiOperation(value = "发送邮件" )
+//    @ApiResponses({
+//            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+//    })
+//    public Result<?> sendMail(SendMailDTO dto) {
+//        Long currentUserId = LoginUserUtil.getCurrentUserId();
+//        SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getDefaultSmtpPop(currentUserId);
+//        AccessKeyEncryptor accessKeyEncryptor = AccessKeyEncryptor.getAccessKeyEncryptor("");
+//        String pass = accessKeyEncryptor.decrypt(smtpPop.getEmailPassword());
+//        smtpPop.setEmailPassword(pass);
+//        if (Objects.isNull(currentUserId) && Objects.nonNull(smtpPop)) {
+//            return Result.result(null);
+//        }
+//        try {
+//           Session session = getSendEmailsSession(smtpPop);
+//            try {
+//
+//                InternetAddress [] froms = new InternetAddress[dto.getRecipientls().size()];
+//                for (int i = 0; i < dto.getRecipientls().size(); i++) {
+//                    froms[i] = new InternetAddress(dto.getRecipientls().get(i));
+//                }
+//                if (CollectionUtils.isEmpty(dto.getFiles())) {
+//                    Message message = new MimeMessage(session);
+//                    message.setFrom(new InternetAddress(smtpPop.getEmailAddress()));
+//                    message.setRecipients(Message.RecipientType.TO, froms);
+//                    message.setSubject(dto.getSubject());
+//                    message.setText(dto.getContent());
+//                    Transport.send(message);
+//                } else {
+////                    MimeMessage message = mailSender.createMimeMessage();
+////                    MimeMessageHelper helper = new MimeMessageHelper(message, true);
+////                    helper.setFrom(new InternetAddress(smtpPop.getEmailAddress()));
+////                    helper.setTo(froms);
+////                    helper.setSubject(dto.getSubject());
+////                    helper.setText(dto.getContent());
+////                    List<MultipartFile> files = dto.getFiles();
+////                    for (MultipartFile multipartFile : files) {
+////                        File file = multipartFile.getResource().getFile();
+////                        helper.addAttachment(file.getName(), file);
+////                    }
+//                }
+//            }catch (Exception e) {
+//                log.error("getSendEmailsSession -error",e);
+//            }
+//            return Result.ok();
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//            log.error("send sendMail -error",e);
+//        }
+//        return Result.ok();
+//    }
+//
+//
+//    @PostMapping(value = "/receiveMail")
+//    @ApiOperation(value = "接收邮件" )
+//    @ApiResponses({
+//            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+//    })
+//    public Result<?> receiveMail(MailDTO dto) {
+//        Long currentUserId = LoginUserUtil.getCurrentUserId();
+//        SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getDefaultSmtpPop(currentUserId);
+//        if (Objects.isNull(currentUserId) && Objects.nonNull(smtpPop)) {
+//            return Result.error("请先设置邮箱账号!");
+//        }
+//
+//        AccessKeyEncryptor accessKeyEncryptor = AccessKeyEncryptor.getAccessKeyEncryptor("");
+//        String pass = accessKeyEncryptor.decrypt(smtpPop.getEmailPassword());
+//        smtpPop.setEmailPassword(pass);
+//        receiveEmails(smtpPop, "INBOX");
+////        receiveEmails(smtpPop, "Sent Items");
+////        receiveEmails(smtpPop, "Drafts");
+////        receiveEmails(smtpPop, "Trash");
+//        return Result.ok();
+//    }
+//
+//
+//    @PostMapping(value = "/receiveMail1")
+//    @ApiOperation(value = "接收邮件" )
+//    @ApiResponses({
+//            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+//    })
+//    public Result<?> receiveMail1(MailDTO dto) {
+//        Long currentUserId = LoginUserUtil.getCurrentUserId();
+//        SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getDefaultSmtpPop(currentUserId);
+//        if (Objects.isNull(currentUserId) && Objects.nonNull(smtpPop)) {
+//            return Result.error("请先设置邮箱账号!");
+//        }
+//        return Result.ok();
+//    }
+//
+//    private void receiveEmails(SmtpPopSettingsEntity smtpPop, String folderName) {
+//        MailProperties properties = new MailProperties(smtpPop);
+//        MailConnection mailConnection = MailConnectionUtil.receiveEmailsConnection(properties);
+//        if (Objects.isNull(mailConnection)) {
+//            return;
+//        }
+//        List<EmailsEntity> entities = new ArrayList<>();
+//
+//        QueryWrapper queryWrapper = new QueryWrapper<>();
+//        queryWrapper.eq("smtp_pop_id",smtpPop.getId());
+//        queryWrapper.eq("folder",folderName);
+//        queryWrapper.select("max(recipient_date) as recipientDate");
+//        Map<String, Date> qv = emailsService.getMap(queryWrapper);
+//
+//        QueryWrapper queryMsgIdWp = new QueryWrapper<>();
+//        queryMsgIdWp.select("msg_uid");
+//        queryMsgIdWp.eq("folder",folderName);
+//        queryMsgIdWp.eq("smtp_pop_id",smtpPop.getId());
+//        queryMsgIdWp.last("order by msg_uid desc limit 100");
+//
+//        List<String> dis = emailsService.listObjs(queryMsgIdWp);
+//        List<Long> msgUids = new ArrayList<>();
+//        if (!CollectionUtils.isEmpty(dis)) {
+//            msgUids = dis.stream().map(Long::valueOf).collect(Collectors.toList());
+//        }
+//        try {
+//            Store store = mailConnection.getStore();
+//            Folder inbox = store.getFolder(folderName);
+//            inbox.open(Folder.READ_WRITE);
+//            Date beginDate = null;
+//            if (!CollectionUtils.isEmpty(qv) && Objects.nonNull(qv.get("recipientDate"))) {
+//                beginDate = qv.get("recipientDate");
+//            }
+//            if (beginDate == null) {
+//                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+//                String dateStr = "2024-03-28"; // 替换为你需要的日期
+//                beginDate = dateFormat.parse(dateStr);
+//            }
+//
+//            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+//            Date date = dateFormat.parse("2024-05-28");
+//
+//            SearchTerm searchTerm = new ReceivedDateTerm(ComparisonTerm.GT, date);
+//            Message[] messages = inbox.search(searchTerm);
+//            for (Message message : messages) {
+//                Long mesId = getMessageId(message,inbox);
+//                if (!CollectionUtils.isEmpty(msgUids) && msgUids.contains(mesId)) {
+//                    continue;
+//                }
+//                msgUids.add(mesId);
+//                EmailsEntity entity = convertMessageToEmailVo(message,smtpPop);
+//                entity.setSmtpPopId(smtpPop.getId());
+//                entity.setMsgUid(mesId);
+//                entity.setFolder(folderName);
+//                entities.add(entity);
+//                emailsService.save(entity);
+//
+//                String downloadDir = mailFileProperties.getPath().getPath()+File.separator+smtpPop.getEmailAddress()+File.separator;
+//                downloadAttachmentFromMessage(message,downloadDir,entity.getId());
+//            }
+//            inbox.close(false);
+//            mailConnection.close();
+//        }catch (Exception e) {
+//            log.error("receiveEmails - error =",e);
+//            mailConnection.close();
+//        }
+//
+//    }
+//
+//    private Session getSendEmailsSession(SmtpPopSettingsEntity smtpPop) {
+//
+//        Properties properties = new Properties();
+//        properties.put("mail.smtp.host", smtpPop.getSmtpServer());
+//        properties.put("mail.smtp.port", smtpPop.getSmtpPort());
+//        properties.put("mail.smtp.auth", "true");
+//        properties.put("mail.user", smtpPop.getEmailAddress());
+//        properties.put("mail.smtp.starttls.enable",smtpPop.getUseTls());
+//        properties.put("mail.smtp.ssl.enable", smtpPop.getUseSsl());
+//
+//        Session session = Session.getInstance(properties, new Authenticator() {
+//            protected PasswordAuthentication getPasswordAuthentication() {
+//                return new PasswordAuthentication(smtpPop.getEmailAddress(), smtpPop.getEmailPassword());
+//            }
+//        });
+//        return session;
+//    }
+//
+//        private static Long getMessageId(Message message, Folder folder) throws MessagingException {
+//        if (folder instanceof IMAPFolder) {
+//            IMAPFolder imapFolder = (IMAPFolder) folder;
+//            return  imapFolder.getUID(message);
+//        } else {
+//            return null;
+//        }
+//    }
+//
+//
+//    private EmailsEntity convertMessageToEmailVo(Message message,SmtpPopSettingsEntity smtpPop) throws MessagingException, IOException {
+//
+//        EmailsEntity entity = new EmailsEntity();
+//        String subject =  MimeUtility.decodeText(message.getSubject());
+//        entity.setSubject(subject);
+//
+//        Map<String,String>  fromMap = decodeAndPrintAddresses(message.getFrom());
+//        entity.setFrom(mapKeyToString(fromMap));
+//        entity.setFromName(mapValueToString(fromMap));
+//
+//        Map<String,String>  toMap = decodeAndPrintAddresses(message.getRecipients(Message.RecipientType.TO));
+//        entity.setRecipient(mapKeyToString(toMap));
+//        entity.setRecipientName(mapValueToString(toMap));
+//
+//        if (Objects.nonNull(message.getSentDate())) {
+//            entity.setSentDate(message.getSentDate());
+//        }
+//
+//        if (Objects.nonNull(message.getReceivedDate())) {
+//            entity.setRecipientDate(message.getReceivedDate());
+//        }
+//        boolean isSeen = message.isSet(Flags.Flag.SEEN);
+//        entity.setIsRead(isSeen);
+//
+////      Map<String,String>  ccMap = decodeAndPrintAddresses(message.getRecipients(Message.RecipientType.CC));
+////      Map<String,String>  bccMap = decodeAndPrintAddresses(message.getRecipients(Message.RecipientType.BCC));
+//        Object content = message.getContent();
+//        if (content instanceof String) {
+//            entity.setContent(message.getContent().toString());
+//        } else if (content instanceof Multipart) {
+//            Multipart multipart = (Multipart) content;
+//            String str = parseMultipart(multipart);
+//            entity.setContent(str);
+//        }
+//        return entity;
+//    }
+//
+//    private String parseMultipart(Multipart multipart) {
+//        try {
+//            StringBuilder stringBuilder = new StringBuilder();
+//            for (int i = 0; i < multipart.getCount(); i++) {
+//                BodyPart bodyPart = multipart.getBodyPart(i);
+//                if (bodyPart.isMimeType("text/plain")) {
+//                    stringBuilder.append(bodyPart.getContent());
+//                } else if (bodyPart.isMimeType("text/html")) {
+//                    stringBuilder.append(bodyPart.getContent());
+//                } else if (bodyPart.isMimeType("multipart/alternative")) {
+//                    parseMultipart((Multipart) bodyPart.getContent());
+//                } else if (bodyPart.isMimeType("multipart/*")) {
+//                    parseMultipart((Multipart) bodyPart.getContent());
+//                }
+//            }
+//            return stringBuilder.toString();
+//        }catch (Exception e) {
+//            return "";
+//        }
+//    }
+//
+//    private void downloadAttachmentFromMessage(Message message, String downloadDir, long emailId) {
+//        try {
+//            Object content = message.getContent();
+//            if (content instanceof Multipart) {
+//                Multipart multipart = (Multipart) content;
+//                for (int i = 0; i < multipart.getCount(); i++) {
+//                    BodyPart bodyPart = multipart.getBodyPart(i);
+//                    if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) {
+//                        saveAttachment(bodyPart, downloadDir, emailId);
+//                    }
+//                }
+//            }
+//        }catch (Exception e) {
+//            log.error("downloadAttachmentFromMessage -- error = ",e);
+//        }
+//    }
+//
+//    private void saveAttachment(BodyPart bodyPart,  String downloadDir, long emailId) throws MessagingException, IOException {
+//        String fileName = bodyPart.getFileName();
+//        fileName = MimeUtility.decodeText(fileName);
+//        String path = DateUtils.date2Str(new Date(), DateUtils.date_yyyy_mm);
+//        // 如果不存在这创建路径
+//        downloadDir = downloadDir + File.separator + path;
+//        if (!new File(downloadDir).exists()) {
+//            new File(downloadDir).mkdirs();
+//        }
+//        File file = new File(downloadDir +  File.separator +fileName);
+//        try (FileOutputStream output = new FileOutputStream(file)) {
+//            bodyPart.getInputStream().transferTo(output);
+//        }
+//        System.out.println("Saved attachment: " + file.getAbsolutePath());
+//        saveAttachmentToDatabase(file, emailId);
+//    }
+//
+//    private void saveAttachmentToDatabase(File file, long emailId) {
+//
+//        String fileName = file.getName();
+//        MailAttachmentEntity attachment = new MailAttachmentEntity();
+//        attachment.setEmailId(emailId);
+//        attachment.setFileName(fileName);
+//        attachment.setFilePath(file.getAbsolutePath());
+//        attachment.setFilePath(file.getAbsolutePath());
+//
+//        String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1);
+//        attachment.setFileExt(fileExtension);
+//        attachment.setFileSize(file.length());
+//        mailAttachmentService.save(attachment);
+//    }
+//
+//    private static String formatDate(Date date) {
+//        if (date == null) return "N/A";
+//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+//        return sdf.format(date);
+//    }
+//
+//    private static String decodeAddresses(Address [] addresses) throws MessagingException {
+//        try {
+//            if (addresses == null) return "[]";
+//            String[] decodedAddresses = new String[addresses.length];
+//            for (int i = 0; i < addresses.length; i++) {
+//                decodedAddresses[i] = MimeUtility.decodeText(addresses[i].toString());
+//            }
+//            return Arrays.toString(decodedAddresses);
+//        }catch (Exception e) {
+//            return "";
+//        }
+//    }
+//
+//    private static Map<String,String> decodeAndPrintAddresses(Address[] addresses) throws MessagingException, IOException {
+//
+//        Map<String,String> map = new HashMap<>();
+//        if (addresses == null) return new HashMap<>();
+//        StringBuilder decodedAddresses = new StringBuilder();
+//        for (Address address : addresses) {
+//            InternetAddress internetAddress = (InternetAddress) address;
+//            String personal = internetAddress.getPersonal();
+//            String email = internetAddress.getAddress();
+//            if (personal != null) {
+//                personal = MimeUtility.decodeText(personal);
+//            }
+//            map.put(email,(personal != null ? personal : "N/A"));
+////            decodedAddresses.append("[Name: ").append(personal != null ? personal : "N/A").append(", Email: ").append(email).append("] ");
+//        }
+//        return map;
+//    }
+//
+//    private static String mapKeyToString(Map<String,String> map) {
+//        if (map == null) return "";
+//        return map.entrySet().stream()
+//                .map(entry -> entry.getKey())
+//                .collect(Collectors.joining(","));
+//    }
+//
+//    private static String mapValueToString(Map<String,String> map) {
+//        if (map == null) return "";
+//        return map.entrySet().stream()
+//                .map(entry -> entry.getValue())
+//                .collect(Collectors.joining(","));
+//    }
+//}

+ 422 - 0
storlead-api/src/main/java/com/storlead/mail/SmtpPopSettingsApiController.java

@@ -0,0 +1,422 @@
+package com.storlead.mail;
+
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.storlead.framework.common.dto.page.PageDTO;
+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 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.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.mail.Authenticator;
+import javax.mail.PasswordAuthentication;
+import javax.mail.Session;
+import javax.mail.Transport;
+import java.util.*;
+
+/**
+ * <p>
+ * 邮箱smtp_setting 前端控制器
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-05-28
+ */
+@Log4j2
+@RestController
+@RequestMapping("/smtp/pop/setting")
+@Api(tags = "020.邮件管理相关接口")
+public class SmtpPopSettingsApiController {
+
+    @Resource
+    private SmtpPopSettingsService smtpPopSettingsService;
+
+    @Resource
+    private EmailsService emailsService;
+
+
+    @PostMapping(value = "/pageList")
+    @ApiOperation(value = "获取我的邮箱配置信息" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> pageList(PageDTO dto) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (Objects.isNull(currentUserId)) {
+            return Result.result(null);
+        }
+        AccessKeyEncryptor encryptor = AccessKeyEncryptor.getAccessKeyEncryptor("");
+        Page<SmtpPopSettingsEntity> page = new Page<>(dto.getPageIndex(),dto.getPageSize());
+        LambdaQueryWrapper<SmtpPopSettingsEntity> queryWrapper = new LambdaQueryWrapper();
+        queryWrapper.eq(SmtpPopSettingsEntity::getIsDelete,Integer.valueOf(0));
+        queryWrapper.eq(SmtpPopSettingsEntity::getOwnerBy,currentUserId);
+        IPage<SmtpPopSettingsEntity> pageList =  smtpPopSettingsService.page(page,queryWrapper);
+        if (!CollectionUtils.isEmpty(pageList.getRecords())) {
+            pageList.getRecords().forEach(e -> {
+                e.setEmailPassword(encryptor.decrypt(e.getEmailPassword()));
+            });
+        }
+        return Result.result(pageList);
+    }
+
+    @PostMapping(value = "/setReplyContent")
+    @ApiOperation(value = "设置自动回复内容,并且开始" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = MailboxAutoReplySetEntity.class)
+    })
+    public Result<?> setReplyContent(Long id,String replyContent,String replyTitle,Integer autoReplyStatus) {
+        if (Objects.isNull(id) || Objects.isNull(autoReplyStatus)) {
+            return Result.error("参数错误");
+        }
+        if (Integer.valueOf(1).equals(autoReplyStatus)) {
+            if(StrUtil.isBlank(replyContent) || StrUtil.isBlank(replyTitle)) {
+                return Result.error("参数错误");
+            }
+        }
+        LambdaUpdateWrapper<SmtpPopSettingsEntity> updateWrapper = new LambdaUpdateWrapper();
+        updateWrapper.set(SmtpPopSettingsEntity::getReplyContent,replyContent);
+        updateWrapper.set(SmtpPopSettingsEntity::getReplyTitle,replyTitle);
+        updateWrapper.set(SmtpPopSettingsEntity::getReplyOnTime,new Date());
+        updateWrapper.set(SmtpPopSettingsEntity::getIsAutoReply,autoReplyStatus);
+        updateWrapper.eq(SmtpPopSettingsEntity::getId,id);
+        smtpPopSettingsService.update(updateWrapper);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/setAutoReplyStatus")
+    @ApiOperation(value = "设置自动回复是否开启:1:开启,0:关闭" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = MailboxAutoReplySetEntity.class)
+    })
+    public Result<?> setAutoReplyStatus(Long id,Integer autoReplyStatus) {
+        if (Objects.isNull(id) || Objects.isNull(autoReplyStatus)) {
+            return Result.error("参数错误");
+        }
+        LambdaUpdateWrapper<SmtpPopSettingsEntity> updateWrapper = new LambdaUpdateWrapper();
+        updateWrapper.set(SmtpPopSettingsEntity::getIsAutoReply,autoReplyStatus);
+        updateWrapper.set(SmtpPopSettingsEntity::getReplyOnTime,new Date());
+        updateWrapper.eq(SmtpPopSettingsEntity::getId,id);
+        smtpPopSettingsService.update(updateWrapper);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/delete")
+    @ApiOperation(value = "删除" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> delete(Long id) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (Objects.isNull(currentUserId)) {
+            return Result.result(null);
+        }
+        SmtpPopSettingsEntity smtpPop = smtpPopSettingsService.getById(id);
+        if (Objects.isNull(smtpPop)) {
+            return Result.error("参数错误");
+        }
+
+        LambdaUpdateWrapper<SmtpPopSettingsEntity> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.set(SmtpPopSettingsEntity::getIsDelete,Integer.valueOf(1));
+        updateWrapper.eq(SmtpPopSettingsEntity::getId,id);
+        smtpPopSettingsService.update(updateWrapper);
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/save")
+    @ApiOperation(value = "保存或修改" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = Result.class)
+    })
+    public Result<?> save(@RequestBody SmtpPopSettingsEntity entity) {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (Objects.isNull(currentUserId)) {
+            return Result.result(null);
+        }
+        /**
+         * 保存邮箱先校验
+         */
+        if ("POP3".equals(entity.getProtocolType())) {
+            if (!testPop3(entity)) {
+                MailProperties properties = new MailProperties(entity);
+                MailConnection mailConnection = MailConnectionUtil.receiveEmailsConnection(properties);
+                if (Objects.isNull(mailConnection)) {
+                    return Result.error("邮箱校验失败,请输入正确的账号密码");
+                }
+                mailConnection.close();
+            }
+        }else if("IMAP".equals(entity.getProtocolType())) {
+            MailProperties properties = new MailProperties(entity);
+            MailConnection mailConnection = MailConnectionUtil.receiveEmailsConnection(properties);
+            if (!testImap(entity)) {
+                return Result.error("邮箱校验失败,请输入正确的账号密码");
+            }
+            mailConnection.close();
+        } else {
+            return Result.error("邮箱校验失败,请输入正确的账号密码");
+        }
+        if (!testSmtp(entity)) {
+            return Result.error("邮箱校验失败,请输入正确的账号密码");
+        }
+        /**
+         * 修改和增加根据邮箱进行查重
+         */
+        AccessKeyEncryptor encryptor = AccessKeyEncryptor.getAccessKeyEncryptor("");
+        entity.setEmailPassword(encryptor.encrypt(entity.getEmailPassword()));
+        if (!Integer.valueOf(1).equals(entity.getUseDefault())) {
+            LambdaQueryWrapper<SmtpPopSettingsEntity> queryWrapper = new LambdaQueryWrapper();
+            queryWrapper.eq(SmtpPopSettingsEntity::getUseDefault, Integer.valueOf(1));
+            queryWrapper.eq(SmtpPopSettingsEntity::getOwnerBy, currentUserId);
+            queryWrapper.eq(SmtpPopSettingsEntity::getIsDelete, Integer.valueOf(0));
+            queryWrapper.last("limit 1");
+            SmtpPopSettingsEntity c = smtpPopSettingsService.getOne(queryWrapper);
+            if (Objects.isNull(c)) {
+                return Result.error("请设置默认邮箱");
+            }
+            if (Objects.nonNull(c) && c.getId().equals(entity.getId())) {
+                return Result.error("请设置默认邮箱");
+            }
+        }
+
+        if (Objects.nonNull(entity.getId())) {
+            // 修改
+            SmtpPopSettingsEntity old = smtpPopSettingsService.getById(entity.getId());
+            if (Objects.nonNull(old)) {
+                if(!old.getEmailAddress().equals(entity.getEmailAddress())){
+                    return Result.error("已绑定的邮箱无法修改,可新增邮箱配置!");
+                }
+            }
+        }
+        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.ne(SmtpPopSettingsEntity::getId,entity.getId());
+            smtpPopSettingsService.update(updateWrapper);
+        }
+
+        return Result.ok();
+    }
+
+    @PostMapping(value = "/defaultUse")
+    @ApiOperation(value = "设置默认邮箱" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = Result.class)
+    })
+    public Result<?> defaultUse(Long id) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        if (Objects.isNull(currentUserId) || Objects.isNull(id)) {
+            return Result.result(null);
+        }
+
+        LambdaUpdateWrapper<SmtpPopSettingsEntity> updateWrapper = new LambdaUpdateWrapper();
+        updateWrapper.set(SmtpPopSettingsEntity::getUseDefault,Integer.valueOf(0));
+        updateWrapper.eq(SmtpPopSettingsEntity::getOwnerBy,currentUserId);
+        smtpPopSettingsService.update(updateWrapper);
+
+        updateWrapper = new LambdaUpdateWrapper();
+        updateWrapper.eq(SmtpPopSettingsEntity::getId,id);
+        updateWrapper.eq(SmtpPopSettingsEntity::getOwnerBy,currentUserId);
+        updateWrapper.set(SmtpPopSettingsEntity::getUseDefault,Integer.valueOf(1));
+        smtpPopSettingsService.update(updateWrapper);
+        /**
+         * 需要当前默认邮箱的邮件和未读数
+         */
+        return Result.ok();
+    }
+
+
+    @PostMapping(value = "/isEnabledDelete")
+    @ApiOperation(value = "是否开启删除服务器邮件;0 不开启,1:开启" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> setReplyContent(Long id,Integer isEnabled) {
+        if (Objects.isNull(id) || Objects.isNull(isEnabled)) {
+            return Result.error("参数错误");
+        }
+        LambdaUpdateWrapper<SmtpPopSettingsEntity> updateWrapper = new LambdaUpdateWrapper();
+        updateWrapper.set(SmtpPopSettingsEntity::getIsDeleteMail,isEnabled);
+        updateWrapper.eq(SmtpPopSettingsEntity::getId,id);
+        smtpPopSettingsService.update(updateWrapper);
+        return Result.ok();
+    }
+
+
+    @PostMapping(value = "/personal_mail_account")
+    @ApiOperation(value = "获取个人邮箱账户" )
+    public Result personalMailAccount() {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        List<SmtpPopSettingsEntity> emails =  smtpPopSettingsService.getEmailAccount(currentUserId);
+        QueryWrapper<EmailsEntity> queryWrapper = new QueryWrapper<EmailsEntity>();
+        queryWrapper.select("smtp_pop_id", "COUNT(*) AS email_count");
+        queryWrapper.eq("owner_by", currentUserId);
+        queryWrapper.eq("folder", EmailBoxEnum.INBOX.code);
+        queryWrapper.eq("is_trash", Integer.valueOf(0));
+        queryWrapper.eq("is_read", Integer.valueOf(0));
+        queryWrapper.eq("is_delete", Integer.valueOf(0));
+        queryWrapper.isNotNull("smtp_pop_id");
+        queryWrapper.ne("`from`", "system@storlead.com");
+        queryWrapper.groupBy("smtp_pop_id");
+        List<Map<String,Object>> readMapls = emailsService.listMaps(queryWrapper);
+        Map<Long, Integer> readMap = new HashMap<>();
+        if (!CollectionUtils.isEmpty(readMapls)) {
+            for (Map<String, Object> map : readMapls) {
+                Long key = Long.valueOf(map.get("smtp_pop_id").toString());
+                Integer val = Integer.valueOf(map.get("email_count").toString());
+                readMap.put(key, val);
+            }
+        }
+
+        List<MailAcountVO> mails = new ArrayList<>();
+        if (CollectionUtil.isNotEmpty(emails)) {
+            emails.forEach(e -> {
+                MailAcountVO mailvo = new MailAcountVO();
+                mailvo.setMailAccount(e.getEmailAddress());
+                mailvo.setId(e.getId());
+                mailvo.setUseDefault(e.getUseDefault());
+                Integer readNum = readMap.get(e.getId());
+                if (Objects.nonNull(readNum)) {
+                    mailvo.setUnReadCount(readNum);
+                } else {
+                    mailvo.setUnReadCount(0);
+                }
+                mails.add(mailvo);
+            });
+        }
+        return Result.result(mails);
+    }
+
+    @PostMapping(value = "/test_connect")
+    @ApiOperation(value = "测试" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> receiveMail(@RequestBody SmtpPopSettingsEntity mailSet) {
+
+        if (!testSmtp(mailSet)) {
+            return Result.error("邮箱校验失败,请输入正确的账号密码");
+        }
+        if ("POP3".equals(mailSet.getProtocolType())) {
+            if (!testPop3(mailSet)) {
+                return Result.error("邮箱校验失败,请输入正确的账号密码");
+            }
+        }else if("IMAP".equals(mailSet.getProtocolType())) {
+            if (!testImap(mailSet)) {
+                return Result.error("邮箱校验失败,请输入正确的账号密码");
+            }
+        } else {
+            return Result.error("邮箱校验失败,请输入正确的账号密码");
+        }
+        return Result.ok();
+    }
+
+
+
+    public Boolean testImap(SmtpPopSettingsEntity mailSet){
+        try {
+            MailProperties properties = new MailProperties(mailSet);
+            MailConnection mailConnection = MailConnectionUtil.testReceiveEmailsConnection(properties);
+            if (Objects.isNull(mailConnection)) {
+                return false;
+            }
+            log.error("mailConnection -- testImap == "+mailConnection);
+//            String host = mailSet.getReceiveServer();
+//            String port = mailSet.getReceivePort();
+//            String username = mailSet.getEmailAddress();
+//            String password = mailSet.getEmailPassword();;
+//
+//            Properties properties = new Properties();
+//            properties.put("mail.imap.host", host);
+//            properties.put("mail.imap.port", port);
+//            properties.put("mail.imap.ssl.enable",Integer.valueOf(1).equals(mailSet.getReceiveSsl()) ? "true" : "false");
+//            Session session = Session.getDefaultInstance(properties);
+//            Store store = session.getStore("imap");
+//            store.connect(username, password);
+//            store.close();
+//            session = null;
+            mailConnection.close();
+
+            return true;
+        } catch (Exception e) {
+            log.error("testImap - error",e);
+            return false;
+        }
+    }
+
+    public Boolean testPop3(SmtpPopSettingsEntity mailSet){
+        try {
+            MailProperties properties = new MailProperties(mailSet);
+            MailConnection mailConnection = MailConnectionUtil.testReceiveEmailsConnection(properties);
+            if (Objects.isNull(mailConnection)) {
+                return false;
+            }
+            log.error("mailConnection -- testPop3 == "+mailConnection);
+            mailConnection.close();
+
+            return true;
+        } catch (Exception e) {
+            log.error("testPop3 - error",e);
+            return false;
+        }
+    }
+
+    public Boolean testSmtp(SmtpPopSettingsEntity smtpPop){
+        try {
+            Properties properties = new Properties();
+            properties.put("mail.smtp.host", smtpPop.getSmtpServer());
+            properties.put("mail.smtp.port", smtpPop.getSmtpPort());
+            properties.put("mail.smtp.auth", "true");
+            properties.put("mail.user", smtpPop.getEmailAddress());
+            properties.put("mail.smtp.starttls.enable",Integer.valueOf(1).equals(smtpPop.getSmtpTls()) ? "true" : "false");
+            properties.put("mail.smtp.ssl.enable", Integer.valueOf(1).equals(smtpPop.getSmtpSsl()) ? "true" : "false");
+
+            String username = smtpPop.getEmailAddress();
+            String password = smtpPop.getEmailPassword();
+
+            Session session = Session.getInstance(properties, new Authenticator() {
+                protected PasswordAuthentication getPasswordAuthentication() {
+                    return new PasswordAuthentication(username, password);
+                }
+            });
+            Transport transport = session.getTransport("smtp");
+            transport.connect();
+            transport.close();
+            return true;
+        } catch (Exception e) {
+            log.error("testSmtp - error",e);
+            return false;
+        }
+    }
+
+}

+ 119 - 0
storlead-api/src/main/java/com/storlead/mail/ThumbnailPreviewController.java

@@ -0,0 +1,119 @@
+package com.storlead.mail;
+
+import com.storlead.system.properties.FileProperties;
+import io.swagger.annotations.Api;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.imageio.IIOImage;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.stream.ImageOutputStream;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2025-08-11 11:11
+ */
+@RestController
+@RequestMapping("/view")
+@Api(tags = "图片显示")
+@Log4j2
+public class ThumbnailPreviewController {
+
+    @Autowired
+    private FileProperties fileProperties;
+
+    @GetMapping("/thumbnail")
+    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));
+            if (originalImage == null) {
+                return ResponseEntity.notFound().build();
+            }
+            // 3. 压缩图片
+            byte[] compressedImage = compressImage(originalImage, 0.2f);
+            // 5. 返回压缩后的图片流
+            return ResponseEntity.ok()
+                    .contentType(MediaType.IMAGE_JPEG)
+                    .body(compressedImage);
+
+        } catch (Exception e) {
+            log.error("thumbnail error", e);
+            return ResponseEntity.notFound().build();
+        }
+    }
+
+    private byte[] compressImage(BufferedImage image, float quality) throws IOException {
+        ByteArrayOutputStream compressed = new ByteArrayOutputStream();
+
+        // 获取JPEG编码器
+        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
+        if (!writers.hasNext()) {
+            throw new IllegalStateException("不支持JPEG编码");
+        }
+
+        ImageWriter writer = writers.next();
+        try (ImageOutputStream ios = ImageIO.createImageOutputStream(compressed)) {
+            writer.setOutput(ios);
+
+            // 设置压缩参数
+            ImageWriteParam param = writer.getDefaultWriteParam();
+            if (param.canWriteCompressed()) {
+                param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+                param.setCompressionQuality(quality); // 设置压缩质量 (0.0-1.0)
+            }
+
+            // 写入压缩后的图片
+            writer.write(null, new IIOImage(image, null, null), param);
+        } finally {
+            writer.dispose();
+        }
+
+        return compressed.toByteArray();
+    }
+
+    private String getCleanFileName(String path) {
+        int lastSeparator = path.lastIndexOf(File.separatorChar);
+        String fileName = (lastSeparator >= 0) ? path.substring(lastSeparator + 1) : path;
+
+        int lastDot = fileName.lastIndexOf('.');
+        if (lastDot > 0) {
+            int secondLastDot = fileName.lastIndexOf('.', lastDot - 1);
+            if (secondLastDot > 0) {
+                return fileName.substring(0, lastDot);
+            }
+        }
+        return fileName;
+    }
+
+    private MediaType determineContentType(String fileName) {
+        if (fileName.toLowerCase().endsWith(".png")) {
+            return MediaType.IMAGE_PNG;
+        } else if (fileName.toLowerCase().endsWith(".gif")) {
+            return MediaType.IMAGE_GIF;
+        }
+        return MediaType.IMAGE_JPEG;
+    }
+
+}

+ 136 - 0
storlead-api/src/main/java/com/storlead/mail/UserEmailFolderApiController.java

@@ -0,0 +1,136 @@
+package com.storlead.mail;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+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 io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * <p>
+ * 用户文件夹 前端控制器
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-11-12
+ */
+@RestController
+@RequestMapping("/user/email/folder")
+@Api(tags = "邮件:邮件自定义文件夹")
+public class UserEmailFolderApiController {
+    @Resource
+    private UserEmailFolderService emailFolderService;
+
+    @Resource
+    private EmailsService emailsService;
+
+    @PostMapping(value = "/page_list")
+    @ApiOperation(value = "获取用户文件夹(分页)" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> pageList(EmailTemplatesDTO dto) {
+
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        Page<UserEmailFolderEntity> page = new Page<>(dto.getPageIndex(),dto.getPageSize());
+        LambdaQueryWrapper<UserEmailFolderEntity> queryWrapper = new LambdaQueryWrapper();
+        queryWrapper.eq(UserEmailFolderEntity::getOwnerBy,currentUserId);
+        queryWrapper.eq(UserEmailFolderEntity::getIsDelete,Integer.valueOf(0));
+        IPage<UserEmailFolderEntity> pageList = emailFolderService.page(page,queryWrapper);
+        return Result.result(pageList);
+    }
+
+    @PostMapping(value = "/list")
+    @ApiOperation(value = "获取用户文件夹" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> list() {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        LambdaQueryWrapper<UserEmailFolderEntity> queryWrapper = new LambdaQueryWrapper();
+        queryWrapper.eq(UserEmailFolderEntity::getOwnerBy,currentUserId);
+        queryWrapper.eq(UserEmailFolderEntity::getIsDelete,Integer.valueOf(0));
+        queryWrapper.eq(UserEmailFolderEntity::getEnabled,Integer.valueOf(1));
+        List<UserEmailFolderEntity> ls = emailFolderService.list(queryWrapper);
+        return Result.result(ls);
+    }
+
+    @PostMapping(value = "/save")
+    @ApiOperation(value = "绑定文件夹入站规则" )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "", response = SmtpPopSettingsEntity.class)
+    })
+    public Result<?> save(UserEmailFolderEntity entity) {
+        Long currentUserId = LoginUserUtil.getCurrentUserId();
+        LambdaQueryWrapper<UserEmailFolderEntity> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(UserEmailFolderEntity::getFolderName,entity.getFolderName());
+        queryWrapper.eq(UserEmailFolderEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+        queryWrapper.eq(UserEmailFolderEntity::getOwnerBy,currentUserId);
+
+        if (Objects.isNull(entity.getId())) {
+            Integer exit = emailFolderService.count(queryWrapper);
+            if (exit > 0) {
+                return Result.error("文件夹'"+ entity.getFolderName() +"'已存在!");
+            }
+        } else {
+            UserEmailFolderEntity oldFolder = emailFolderService.getOne(queryWrapper);
+            if (Objects.nonNull(oldFolder)) {
+                if (!oldFolder.getId().equals(entity.getId())) {
+                    return Result.error("文件夹'"+ entity.getFolderName() +"'已存在,无法修改!");
+                }
+            }
+        }
+        emailFolderService.saveOrUpdate(entity);
+        return Result.ok();
+    }
+
+    @ApiOperation(value = "删除")
+    @PostMapping("deleteIds")
+    public Result delete(Long [] ids) {
+        if(Objects.isNull(ids)) {
+            return Result.error("参数错误");
+        }
+        /**
+         * 需要修改邮件文件夹标记为''
+         */
+        emailFolderService.lgDelete(Arrays.asList(ids));
+
+        LambdaUpdateWrapper<EmailsEntity> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.in(EmailsEntity::getCustomFolderId,Arrays.asList(ids));
+        updateWrapper.set(EmailsEntity::getCustomFolderId,null);
+        emailsService.update(updateWrapper);
+        return Result.ok();
+    }
+
+
+    @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);
+        return Result.ok();
+    }
+}

+ 3 - 7
storlead-api/src/main/resources/application-dev.yml

@@ -1,5 +1,5 @@
 server:
-  port: 10010
+  port: 10020
   tomcat:
     max-swallow-size: -1
     basedir: /app/temp
@@ -91,15 +91,11 @@ spring:
         connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
       datasource:
         master:
-          url: jdbc:mysql://mysql.test.storlead.com:39091/sp_saas_platform_test?useSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
+          url: jdbc:mysql://mysql.test.storlead.com:39091/sp_email_platform_test?useSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
           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
+
 #mybatis plus 设置
 mybatis-plus:
   mapper-locations: classpath*:/mapper/*Mapper.xml,classpath*:/mapper/*/*Mapper.xml

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

@@ -90,7 +90,7 @@ spring:
         connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
       datasource:
         master:
-          url: jdbc:mysql://mysql.test.storlead.com:39091/sp_smart_trade_test?useSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
+          url: jdbc:mysql://mysql.test.storlead.com:39091/sp_email_platform_test?useSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
           username: root
           password: rCgRgLjH99Xvg5BN
           driver-class-name: com.mysql.jdbc.Driver

+ 3 - 21
storlead-dependencies/pom.xml

@@ -60,36 +60,31 @@
 
     <dependencyManagement>
         <dependencies>
+
             <dependency>
                 <groupId>org.springframework</groupId>
                 <artifactId>spring-web</artifactId>
                 <version>${spring-web.version}</version>
             </dependency>
 
-
-
-
             <dependency>
                 <groupId>io.springfox</groupId>
                 <artifactId>springfox-swagger2</artifactId>
                 <version>${swagger.version}</version>
             </dependency>
+
             <dependency>
                 <groupId>io.springfox</groupId>
                 <artifactId>springfox-swagger-ui</artifactId>
                 <version>${swagger.ui.version}</version>
             </dependency>
+
             <dependency>
                 <groupId>io.swagger</groupId>
                 <artifactId>swagger-annotations</artifactId>
                 <version>${swagger.annotations.version}</version>
             </dependency>
 
-<!--            <dependency>-->
-<!--                <groupId>com.google.code.gson</groupId>-->
-<!--                <artifactId>gson</artifactId>-->
-<!--            </dependency>-->
-
             <dependency>
                 <groupId>com.alibaba</groupId>
                 <artifactId>fastjson</artifactId>
@@ -102,18 +97,6 @@
                 <version>4.5.3</version>
             </dependency>
 
-<!--            <dependency>-->
-<!--                <groupId>org.apache.httpcomponents.client5</groupId>-->
-<!--                <artifactId>httpclient5</artifactId>-->
-<!--                <version>${apache.httpcore5.client5.version}</version>-->
-<!--            </dependency>-->
-
-<!--            <dependency>-->
-<!--                <groupId>org.apache.httpcomponents.core5</groupId>-->
-<!--                <artifactId>httpcore5</artifactId>-->
-<!--                <version>${apache.httpcore5.version}</version>-->
-<!--            </dependency>-->
-
             <!--JWT-->
             <dependency>
                 <groupId>com.auth0</groupId>
@@ -144,7 +127,6 @@
 <!--                <version>1.8.7</version>-->
 <!--            </dependency>-->
 
-
 <!--            <dependency>-->
 <!--                <groupId>com.squareup.okhttp3</groupId>-->
 <!--                <artifactId>okhttp</artifactId>-->

+ 1 - 0
storlead-framework/storlead-core/pom.xml

@@ -6,6 +6,7 @@
         <groupId>com.storlead.boot</groupId>
         <artifactId>storlead-framework</artifactId>
         <version>1.0</version>
+        <relativePath>../pom.xml</relativePath>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 0
storlead-framework/storlead-web/pom.xml

@@ -6,6 +6,7 @@
         <groupId>com.storlead.boot</groupId>
         <artifactId>storlead-framework</artifactId>
         <version>1.0</version>
+        <relativePath>../pom.xml</relativePath>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>