From 3c9c240397490edc80c2277ae802cc4fd4fd3de0 Mon Sep 17 00:00:00 2001 From: bynt Date: Mon, 29 May 2023 13:24:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=82=AE=E4=BB=B6=E5=8F=91?= =?UTF-8?q?=E9=80=81=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../me/zhengjie/utils/EncryptUtilsTest.java | 2 + .../service/mapstruct/LogErrorMapperImpl.java | 2 +- .../service/mapstruct/LogSmallMapperImpl.java | 2 +- .../impl/StatisticsDmpServiceImpl.java | 4 +- .../me/zhengjie/SpringApplicationTest.java | 20 ++ .../java/me/zhengjie/TestEncryptInter.java | 2 +- .../java/me/zhengjie/domain/EmailConfig.java | 2 +- .../me/zhengjie/service/EmailService.java | 13 + .../service/impl/EmailServiceImpl.java | 57 +++- .../main/java/me/zhengjie/utils/MailUtil.java | 246 ++++++++++++++++++ 10 files changed, 331 insertions(+), 19 deletions(-) create mode 100644 eladmin-tools/src/main/java/me/zhengjie/utils/MailUtil.java diff --git a/eladmin-common/src/test/java/me/zhengjie/utils/EncryptUtilsTest.java b/eladmin-common/src/test/java/me/zhengjie/utils/EncryptUtilsTest.java index f909d9d..7b8158b 100644 --- a/eladmin-common/src/test/java/me/zhengjie/utils/EncryptUtilsTest.java +++ b/eladmin-common/src/test/java/me/zhengjie/utils/EncryptUtilsTest.java @@ -11,7 +11,9 @@ public class EncryptUtilsTest { */ @Test public void testDesEncrypt() { + try { + desEncrypt("baiye2022"); assertEquals("7772841DC6099402", desEncrypt("123456")); } catch (Exception e) { e.printStackTrace(); diff --git a/eladmin-logging/target/generated-sources/annotations/me/zhengjie/service/mapstruct/LogErrorMapperImpl.java b/eladmin-logging/target/generated-sources/annotations/me/zhengjie/service/mapstruct/LogErrorMapperImpl.java index d956ba7..c58560a 100644 --- a/eladmin-logging/target/generated-sources/annotations/me/zhengjie/service/mapstruct/LogErrorMapperImpl.java +++ b/eladmin-logging/target/generated-sources/annotations/me/zhengjie/service/mapstruct/LogErrorMapperImpl.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component; @Generated( value = "org.mapstruct.ap.MappingProcessor", - date = "2023-03-21T16:41:41+0800", + date = "2023-05-29T13:21:00+0800", comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_251 (Oracle Corporation)" ) @Component diff --git a/eladmin-logging/target/generated-sources/annotations/me/zhengjie/service/mapstruct/LogSmallMapperImpl.java b/eladmin-logging/target/generated-sources/annotations/me/zhengjie/service/mapstruct/LogSmallMapperImpl.java index d555fe7..d0c7655 100644 --- a/eladmin-logging/target/generated-sources/annotations/me/zhengjie/service/mapstruct/LogSmallMapperImpl.java +++ b/eladmin-logging/target/generated-sources/annotations/me/zhengjie/service/mapstruct/LogSmallMapperImpl.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component; @Generated( value = "org.mapstruct.ap.MappingProcessor", - date = "2023-03-21T16:41:41+0800", + date = "2023-05-29T13:21:01+0800", comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_251 (Oracle Corporation)" ) @Component diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/dmpMonitor/service/impl/StatisticsDmpServiceImpl.java b/eladmin-system/src/main/java/me/zhengjie/modules/dmpMonitor/service/impl/StatisticsDmpServiceImpl.java index 504d49a..eca09f7 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/dmpMonitor/service/impl/StatisticsDmpServiceImpl.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/dmpMonitor/service/impl/StatisticsDmpServiceImpl.java @@ -13,6 +13,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import me.zhengjie.common.json.ApiDataResponse; import me.zhengjie.constant.SystemConstant; +import me.zhengjie.domain.EmailConfig; import me.zhengjie.domain.vo.EmailVo; import me.zhengjie.exception.BadRequestException; import me.zhengjie.modules.dmpMonitor.domian.DmpMonitorNumDto; @@ -23,6 +24,7 @@ import me.zhengjie.modules.dmpMonitor.dto.DataAnalysisRequestDTO; import me.zhengjie.modules.uploadnew.service.impl.BuildPathUtils; import me.zhengjie.service.EmailService; import me.zhengjie.utils.FileUtil; +import me.zhengjie.utils.MailUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -81,7 +83,7 @@ public class StatisticsDmpServiceImpl implements StatisticsDmpService { emailVo.setTos(list); emailVo.setSubject("一次性短链"); emailVo.setContent(link); - emailService.send(emailVo, emailService.find()); + emailService.outlookMail(emailVo, emailService.find()); } private List> getData(Map map) { diff --git a/eladmin-system/src/test/java/me/zhengjie/SpringApplicationTest.java b/eladmin-system/src/test/java/me/zhengjie/SpringApplicationTest.java index 9b31b2c..32d7d6c 100644 --- a/eladmin-system/src/test/java/me/zhengjie/SpringApplicationTest.java +++ b/eladmin-system/src/test/java/me/zhengjie/SpringApplicationTest.java @@ -1,6 +1,7 @@ package me.zhengjie; import com.alibaba.fastjson.JSON; +import me.zhengjie.domain.vo.EmailVo; import me.zhengjie.modules.upload.domain.UploadFile; import me.zhengjie.modules.upload.repository.UploadFileRepository; import me.zhengjie.modules.upload.service.UploadFileService; @@ -8,6 +9,7 @@ import me.zhengjie.modules.upload.service.dto.UploadFileDto; import me.zhengjie.modules.upload.service.dto.UploadFileQueryCriteria; import me.zhengjie.modules.upload.service.mapstruct.UploadFileMapper; import me.zhengjie.modules.upload.task.SaveToFileTask; +import me.zhengjie.service.EmailService; import me.zhengjie.utils.PageUtil; import me.zhengjie.utils.QueryHelp; import me.zhengjie.utils.SecurityUtils; @@ -21,6 +23,8 @@ import org.springframework.data.domain.Pageable; import org.springframework.test.context.junit4.SpringRunner; import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @@ -37,6 +41,22 @@ public class SpringApplicationTest { @Autowired private UploadFileService uploadFileService; + @Autowired + private EmailService emailService; + + @Test + public void send(){ + //发送邮件 + EmailVo emailVo = new EmailVo(); + List list = new ArrayList<>(); + list.add("lambda0821@outlook.com"); + emailVo.setTos(list); + emailVo.setSubject("一次性短链"); + emailVo.setContent("xxxx"); + emailService.send(emailVo, emailService.find(2L)); + } + + /** * 获取当前的用户信息 */ diff --git a/eladmin-system/src/test/java/me/zhengjie/TestEncryptInter.java b/eladmin-system/src/test/java/me/zhengjie/TestEncryptInter.java index 7fd33b0..6ba3c88 100644 --- a/eladmin-system/src/test/java/me/zhengjie/TestEncryptInter.java +++ b/eladmin-system/src/test/java/me/zhengjie/TestEncryptInter.java @@ -119,7 +119,7 @@ public class TestEncryptInter { @Test public void sendSms() { Map map = new HashMap<>(2); - map.put("baseUrlAddr", "http://zw.juqianfw.com/"); + map.put("baseUrlAddr", "https://cdn2.xjietiao.com/d/external_static/invite.html?mid=M6360640276240805889&eventCode=ACT_RICH_TOGETHER_EVENT"); ShortLinkUrlDto urlDto = JSONUtil.toBean(HttpUtil.post("s.z48.cn/trans", JSON.toJSONString(map)), ShortLinkUrlDto.class); System.out.println(JSON.toJSONString(urlDto)); } diff --git a/eladmin-tools/src/main/java/me/zhengjie/domain/EmailConfig.java b/eladmin-tools/src/main/java/me/zhengjie/domain/EmailConfig.java index b4fc1e6..e48138f 100644 --- a/eladmin-tools/src/main/java/me/zhengjie/domain/EmailConfig.java +++ b/eladmin-tools/src/main/java/me/zhengjie/domain/EmailConfig.java @@ -53,6 +53,6 @@ public class EmailConfig implements Serializable { private String pass; @NotBlank - @ApiModelProperty(value = "收件人") + @ApiModelProperty(value = "发件人地址") private String fromUser; } diff --git a/eladmin-tools/src/main/java/me/zhengjie/service/EmailService.java b/eladmin-tools/src/main/java/me/zhengjie/service/EmailService.java index 2c61a53..31f7d8f 100644 --- a/eladmin-tools/src/main/java/me/zhengjie/service/EmailService.java +++ b/eladmin-tools/src/main/java/me/zhengjie/service/EmailService.java @@ -40,6 +40,12 @@ public interface EmailService { */ EmailConfig find(); + /** + * @param id + * 查询配置 + * @return EmailConfig 邮件配置 + */ + EmailConfig find(Long id); /** * 发送邮件 * @param emailVo 邮件发送的内容 @@ -47,4 +53,11 @@ public interface EmailService { * @throws Exception / */ void send(EmailVo emailVo, EmailConfig emailConfig); + + /** + * 发送outlook + * @param emailVo + * @param emailConfig + */ + void outlookMail(EmailVo emailVo, EmailConfig emailConfig); } diff --git a/eladmin-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java b/eladmin-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java index a71628e..edf74f9 100644 --- a/eladmin-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java +++ b/eladmin-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java @@ -15,26 +15,31 @@ */ package me.zhengjie.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.extra.mail.Mail; import cn.hutool.extra.mail.MailAccount; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import me.zhengjie.domain.EmailConfig; import me.zhengjie.domain.vo.EmailVo; import me.zhengjie.exception.BadRequestException; import me.zhengjie.repository.EmailRepository; import me.zhengjie.service.EmailService; import me.zhengjie.utils.EncryptUtils; +import me.zhengjie.utils.MailUtil; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; + import java.util.Optional; /** * @author Zheng Jie * @date 2018-12-26 */ +@Slf4j @Service @RequiredArgsConstructor @CacheConfig(cacheNames = "email") @@ -47,7 +52,7 @@ public class EmailServiceImpl implements EmailService { @Transactional(rollbackFor = Exception.class) public EmailConfig config(EmailConfig emailConfig, EmailConfig old) throws Exception { emailConfig.setId(1L); - if(!emailConfig.getPass().equals(old.getPass())){ + if (!emailConfig.getPass().equals(old.getPass())) { // 对称加密 emailConfig.setPass(EncryptUtils.desEncrypt(emailConfig.getPass())); } @@ -61,15 +66,21 @@ public class EmailServiceImpl implements EmailService { return emailConfig.orElseGet(EmailConfig::new); } + @Override + public EmailConfig find(Long id) { + Optional emailConfig = emailRepository.findById(id); + return emailConfig.orElseGet(EmailConfig::new); + } + @Override @Transactional(rollbackFor = Exception.class) - public void send(EmailVo emailVo, EmailConfig emailConfig){ - if(emailConfig.getId() == null){ + public void send(EmailVo emailVo, EmailConfig emailConfig) { + if (emailConfig.getId() == null) { throw new BadRequestException("请先配置,再操作"); } // 封装 MailAccount account = new MailAccount(); - account.setUser(emailConfig.getUser()); + account.setDebug(true); account.setHost(emailConfig.getHost()); account.setPort(Integer.parseInt(emailConfig.getPort())); account.setAuth(true); @@ -79,25 +90,43 @@ public class EmailServiceImpl implements EmailService { } catch (Exception e) { throw new BadRequestException(e.getMessage()); } - account.setFrom(emailConfig.getUser()+"<"+emailConfig.getFromUser()+">"); + account.setFrom(emailConfig.getUser() + "<" + emailConfig.getFromUser() + ">"); // ssl方式发送 - account.setSslEnable(true); + account.setSslEnable(false); // 使用STARTTLS安全连接 account.setStarttlsEnable(true); String content = emailVo.getContent(); // 发送 try { int size = emailVo.getTos().size(); - Mail.create(account) - .setTos(emailVo.getTos().toArray(new String[size])) - .setTitle(emailVo.getSubject()) - .setContent(content) - .setHtml(true) + Mail.create(account).setTos(emailVo.getTos().toArray(new String[size])).setTitle(emailVo.getSubject()).setContent(content).setHtml(true) //关闭session - .setUseGlobalSession(false) - .send(); - }catch (Exception e){ + .setUseGlobalSession(false).send(); + } catch (Exception e) { throw new BadRequestException(e.getMessage()); } } + + @Override + public void outlookMail(EmailVo emailVo, EmailConfig emailConfig) { + if (CollUtil.isNotEmpty(emailVo.getTos())) { + try { + for (String toAddress : emailVo.getTos()) { + int count = 0; + while (count < 3) { + boolean result = MailUtil.sendEmail(emailConfig.getFromUser(), + EncryptUtils.desDecrypt(emailConfig.getPass()), + emailConfig.getHost(), emailConfig.getPort(), toAddress, "一次性短链", emailVo.getContent()); + log.info("===================== send mail result as {} =====================", result); + if (result) { + break; + } + count++; + } + } + } catch (Exception e) { + throw new BadRequestException(e.getMessage()); + } + } + } } diff --git a/eladmin-tools/src/main/java/me/zhengjie/utils/MailUtil.java b/eladmin-tools/src/main/java/me/zhengjie/utils/MailUtil.java new file mode 100644 index 0000000..975b121 --- /dev/null +++ b/eladmin-tools/src/main/java/me/zhengjie/utils/MailUtil.java @@ -0,0 +1,246 @@ +package me.zhengjie.utils; + + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.exception.BadRequestException; + +import javax.activation.DataHandler; +import javax.activation.FileDataSource; +import javax.mail.*; +import javax.mail.internet.*; +import java.io.*; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Properties; + +/** + * @author Enzo + * @date 2022-10-22 13:49:33 + */ +@Slf4j +public class MailUtil { + + private MailUtil() { + } + + /** + * 结合邮件返回 + * + * @param username + * @param password + * @return + */ + public static List readMailByIMAP(String username, String password) { + List list = Lists.newArrayList(); + Properties props = System.getProperties(); + //设置电子邮件协议 + props.setProperty("mail.store.protocol", "imaps"); + try { + Session session = Session.getDefaultInstance(props, null); + Store store = session.getStore("imaps"); + store.connect("outlook.office365.com", username, password); + Folder inbox = store.getFolder("Inbox"); + inbox.open(Folder.READ_WRITE); + Message[] messages = inbox.getMessages(); + list.addAll(Arrays.asList(messages)); + } catch (NoSuchProviderException e) { + log.error("======================= open mail error time {} message as {} ==================", DateUtil.date(), e.getMessage()); + throw new BadRequestException("没有找到该服务"); + } catch (MessagingException e) { + log.error("======================= open mail error time {} message as {} ==================", DateUtil.date(), e.getMessage()); + throw new BadRequestException("发送邮件失败"); + } + return list; + } + + /** + * 创建一封复杂邮件(文本+图片+附件) + */ + public static MimeMessage createMimeMessage(Session session, String sendMail, String receiveMail, String filename, String taskName) throws Exception { + // 1. 创建邮件对象 + MimeMessage message = new MimeMessage(session); + + // 2. From: 发件人 + message.setFrom(new InternetAddress(sendMail, sendMail, CharsetUtil.UTF_8)); + + // 3. To: 收件人(可以增加多个收件人、抄送、密送) + message.addRecipient(Message.RecipientType.TO, new InternetAddress(receiveMail, receiveMail, CharsetUtil.UTF_8)); + + // 4. Subject: 邮件主题 + message.setSubject(taskName, CharsetUtil.UTF_8); + + /* + * 下面是邮件内容的创建: + */ + + // 6. 创建文本“节点” + /*MimeBodyPart text = new MimeBodyPart(); + // 这里添加图片的方式是将整个图片包含到邮件内容中, 实际上也可以以 http 链接的形式添加网络图片 + text.setContent(taskName, "text/html;charset=UTF-8"); + + // 7. (文本+图片)设置 文本 和 图片 “节点”的关系(将 文本 和 图片 “节点”合成一个混合“节点”) + MimeMultipart mmTextImage = new MimeMultipart(); + mmTextImage.addBodyPart(text); + // 关联关系 + mmTextImage.setSubType("related"); + + // 8. 将 文本+图片 的混合“节点”封装成一个普通“节点” + // 最终添加到邮件的 Content 是由多个 BodyPart 组成的 Multipart, 所以我们需要的是 BodyPart, + // 上面的 mm_text_image 并非 BodyPart, 所有要把 mm_text_image 封装成一个 BodyPart + MimeBodyPart textImage = new MimeBodyPart(); + textImage.setContent(mmTextImage);*/ + + // 9. 创建附件“节点” + MimeBodyPart attachment = new MimeBodyPart(); + // 读取本地文件 + DataHandler dh2 = new DataHandler(new FileDataSource(filename)); + // 将附件数据添加到“节点” + attachment.setDataHandler(dh2); + // 设置附件的文件名(需要编码) + attachment.setFileName(MimeUtility.encodeText(dh2.getName())); + + // 10. 设置(文本+图片)和 附件 的关系(合成一个大的混合“节点” / Multipart ) + MimeMultipart mm = new MimeMultipart(); + // mm.addBodyPart(textImage); + // 如果有多个附件,可以创建多个多次添加 + mm.addBodyPart(attachment); + // 混合关系 + mm.setSubType("mixed"); + + // 11. 设置整个邮件的关系(将最终的混合“节点”作为邮件的内容添加到邮件对象) + message.setContent(mm); + + // 12. 设置发件时间 + message.setSentDate(new Date()); + + // 13. 保存上面的所有设置 + message.saveChanges(); + + return message; + } + + public static Boolean sendMail(String username, String password, String toUsername, String fileName, String taskName) { + + try { + // 1. 创建参数配置, 用于连接邮件服务器的参数配置 + // 参数配置 + Properties props = new Properties(); + + // 端口 + props.put("mail.smtp.port", "587"); + + // 发件人的邮箱的 SMTP 服务器地址 + props.put("mail.smtp.host", "smtp.office365.com"); + + // 当前smtp host设为可信任 否则抛出javax.mail.MessagingException: Could not convert socket to TLS + props.put("mail.smtp.ssl.trust", "smtp.office365.com"); + + // 使用的协议(JavaMail规范要求) + props.put("mail.transport.protocol", "smtp"); + + // 需要请求认证 + props.put("mail.smtp.auth", "true"); + + // 开启STARTTLS + props.put("mail.smtp.starttls.enable", "true"); + + // ssl + props.put("mail.smtp.ssl", "true"); + + // 开启 SSL 连接, 以及更详细的发送步骤请看上一篇: 基于 JavaMail 的 Java 邮件发送:简单邮件发送 + // 2. 根据配置创建会话对象, 用于和邮件服务器交互 + Session session = Session.getInstance(props); + // 设置为debug模式, 可以查看详细的发送 log + session.setDebug(Boolean.FALSE); + + // 3. 创建一封邮件 + MimeMessage message = createMimeMessage(session, username, toUsername, fileName, taskName); + + // 4. 根据 Session 获取邮件传输对象 + Transport transport = session.getTransport(); + + // 5. 使用 邮箱账号 和 密码 连接邮件服务器 + // 这里认证的邮箱必须与 message 中的发件人邮箱一致,否则报错 + transport.connect(username, password); + + // 6. 发送邮件, 发到所有的收件地址, message.getAllRecipients() 获取到的是在创建邮件对象时添加的所有收件人, 抄送人, 密送人 + transport.sendMessage(message, message.getAllRecipients()); + + // 7. 关闭连接 + transport.close(); + return Boolean.TRUE; + } catch (Exception ex) { + log.error("===================== send message error {} ==========================", ex.getMessage()); + return Boolean.FALSE; + } + } + + + public static boolean sendEmail(String sender, String password, String host, String port, String receiver,String subject,String content) { + + try { + + Properties props = new Properties(); + // 开启debug调试 + props.setProperty("mail.debug", "false"); + // 发送服务器需要身份验证 + props.setProperty("mail.smtp.auth", "true"); + // 设置邮件服务器主机名 + props.setProperty("mail.host", host); + // 发送邮件协议名称 这里使用的是smtp协议 + props.setProperty("mail.transport.protocol", "smtp"); + // 服务端口号 + props.setProperty("mail.smtp.port", port); + props.put("mail.smtp.starttls.enable", "true"); + + // 设置环境信息 + Session session = Session.getInstance(props); + + // 创建邮件对象 + MimeMessage msg = new MimeMessage(session); + + // 设置发件人 + msg.setFrom(new InternetAddress(sender)); + + // 设置收件人 + msg.addRecipient(Message.RecipientType.TO, new InternetAddress(receiver)); + + // 设置邮件主题 + msg.setSubject(subject); + + // 设置邮件内容 + Multipart multipart = new MimeMultipart(); + + MimeBodyPart textPart = new MimeBodyPart(); + //发送邮件的文本内容 + textPart.setText(content); + multipart.addBodyPart(textPart); + + + + msg.setContent(multipart); + + Transport transport = session.getTransport(); + // 连接邮件服务器 + transport.connect(sender, password); + // 发送邮件 + transport.sendMessage(msg, new Address[]{new InternetAddress(receiver)}); + // 关闭连接 + transport.close(); + + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + +}