提交 ee9a4269 作者: duanxincheng

GraphApi接入推送邮件

父级 1a40d520
......@@ -73,9 +73,6 @@
<version>3.1</version>
</dependency>
<dependency>
<groupId>com.microsoft.graph</groupId>
<artifactId>microsoft-graph-auth</artifactId>
<version>0.3.0</version>
......
package com.cmeeting.email;
import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenRequestContext;
import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.cmeeting.log.service.ProcessLogService;
import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
import com.microsoft.graph.models.*;
import com.microsoft.graph.models.Message;
import com.microsoft.graph.requests.AttachmentCollectionPage;
import com.microsoft.graph.requests.AttachmentCollectionResponse;
import com.microsoft.graph.requests.GraphServiceClient;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Request;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
......@@ -15,6 +26,11 @@ import javax.mail.internet.*;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Base64;
import java.util.LinkedList;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
......@@ -25,8 +41,10 @@ public class EmailSender {
private String SENDER;
@Value("${email.sender-pwd}")
private String EMAIL_PWD;
@Value("${email.smtp-host}")
private String SMTP_HOST;
private String CLIENT_ID = "c06fe7cf-2a89-4099-9805-ce03031938f8";
private String CLIENT_SECRET = "wsu8Q~GxYxPLf2akioQZDRG8NR1EzCAHIAQRVc6u";
private String TENANT_ID = "18653b3e-03c7-499e-8baf-42ef06a814ef";
@Resource
private ProcessLogService processLogService;
......@@ -39,33 +57,121 @@ public class EmailSender {
* @param meetingId 会议id
* @return
*/
public boolean sendEmailWithAttachment(String toEmail, String subject, String attachmentPath, String meetingId) {
// 邮件服务器配置
Properties props = new Properties();
props.put("mail.smtp.host", SMTP_HOST);
props.put("mail.smtp.auth", "true");
// public boolean sendEmailWithAttachment(String toEmail, String subject, String attachmentPath, String meetingId) {
// log.info("sendEmailWithAttachment start...");
// // 邮件服务器配置
// Properties props = new Properties();
// props.put("mail.smtp.host", SMTP_HOST);
// props.put("mail.smtp.auth", "true");
//
// props.put("mail.smtp.port", "587");
// props.put("mail.smtp.starttls.enable", "true"); // 使用TLS
// props.put("mail.smtp.starttls.required", "true");
// props.put("mail.debug", "true");
// props.put("mail.smtp.connectiontimeout", "5000"); // 连接超时时间(毫秒)
// props.put("mail.smtp.timeout", "5000"); // 读取超时时间(毫秒)
// props.remove("mail.smtp.user");
// props.remove("mail.user");
// props.remove("mail.smtp.ssl.enable");
//
// // 创建会话
// log.info("sender->{},email_pwd->{}",SENDER, EMAIL_PWD);
//
// System.getProperties().stringPropertyNames().stream()
// .filter(name -> name.startsWith("mail."))
// .forEach(name -> log.info(name + " = " + System.getProperty(name)));
//
// Session session = Session.getInstance(props); // 不传递 Authenticator
// String body = "您好:\n" +
// "\n" +
// " 附件为您本次会议的会议纪要,烦请下载查看";
//
// AtomicInteger retryCount = new AtomicInteger(0);
// boolean isSent = false;
// if(StringUtils.isEmpty(toEmail)){
// log.error("收件邮箱为空,推送失败");
// processLogService.log(meetingId,null,"收件邮箱为空,推送失败");
// return false;
// }
// log.info("准备开始邮件推送...");
// while (retryCount.intValue() < MAX_RETRY && !isSent){
// try {
// Transport transport = session.getTransport("smtp");
// // 创建邮件消息
// Message message = new MimeMessage(session);
// message.setFrom(new InternetAddress("cmeeting_assistant@cimc.com"));
// message.setRecipients(Message.RecipientType.TO,
// InternetAddress.parse(toEmail));
// message.setSubject(subject);
//
// // 创建消息体部分(正文)
// MimeBodyPart messageBodyPart = new MimeBodyPart();
// messageBodyPart.setText(body);
//
// // 创建多部分消息
// Multipart multipart = new MimeMultipart();
//
// // 添加文本部分
// multipart.addBodyPart(messageBodyPart);
//
// // 添加附件部分
// if (attachmentPath != null && !attachmentPath.isEmpty()) {
// MimeBodyPart attachmentPart = new MimeBodyPart();
// DataSource source = new FileDataSource(attachmentPath);
// attachmentPart.setDataHandler(new DataHandler(source));
// attachmentPart.setFileName(new File(attachmentPath).getName());
// multipart.addBodyPart(attachmentPart);
// }
//
// // 设置完整消息内容
// message.setContent(multipart);
//
// // 发送邮件
// log.info("Transport.send...");
//// Transport.send(message);
// transport.connect("smtp.office365.com", 587, "cmeeting_assistant@cimc.com", "scyou@xih45g6@xih4");
// transport.sendMessage(message, message.getAllRecipients());
// transport.close();
// log.error("邮件已成功发送: meetingId->{}", meetingId);
// isSent = true;
// }catch (Exception e) {
// retryCount.getAndIncrement();
// // 异常处理
// StringWriter sw = new StringWriter();
// PrintWriter pw = new PrintWriter(sw);
// e.printStackTrace(pw);
// processLogService.log(meetingId,null,"【邮件推送异常】:"+sw.toString());
// if (retryCount.intValue() > MAX_RETRY) {
// log.error("邮件发送达到最大重试次数: meetingId->{}", meetingId);
// throw new RuntimeException(e);
// }
// // 指数退避
// try {
// Thread.sleep((long) Math.pow(2, retryCount.intValue()) * 1000);
// } catch (InterruptedException ie) {
// Thread.currentThread().interrupt();
// throw new RuntimeException("邮件发送重试失败", ie);
// }
// }
// }
// return isSent;
// }
// props.put("mail.smtp.port", "465");
// props.put("mail.smtp.ssl.enable", "true"); // 使用SSL
/**
* 发送邮件,带附件
* @param toEmail
* @param subject
* @param attachmentPath
* @param meetingId
* @return
*/
public boolean sendEmailWithAttachment(String toEmail, String subject, String attachmentPath, String meetingId) {
log.info("sendEmailWithAttachment start...");
props.put("mail.smtp.port", "587");
props.put("mail.smtp.starttls.enable", "true"); // 使用TLS
// 创建会话
log.info("sender->{},email_pwd->{}",SENDER, EMAIL_PWD);
// 或者使用SSL
// props.put("mail.smtp.port", "465");
// props.put("mail.smtp.ssl.enable", "true");
// 创建会话
Session session = Session.getInstance(props,
new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
// return new PasswordAuthentication("cmeeting_assistant@cimc.com", "scyou@xih45g6@xih4");
return new PasswordAuthentication(SENDER, EMAIL_PWD);
}
});
String body = "您好:\n" +
"\n" +
" 附件为您本次会议的会议纪要,烦请下载查看";
AtomicInteger retryCount = new AtomicInteger(0);
boolean isSent = false;
......@@ -74,42 +180,67 @@ public class EmailSender {
processLogService.log(meetingId,null,"收件邮箱为空,推送失败");
return false;
}
log.info("准备开始邮件推送...");
while (retryCount.intValue() < MAX_RETRY && !isSent){
try {
// 创建邮件消息
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(SENDER));
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(toEmail));
message.setSubject(subject);
// 创建消息体部分(正文)
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(body);
// 创建多部分消息
Multipart multipart = new MimeMultipart();
// 添加文本部分
multipart.addBodyPart(messageBodyPart);
// 添加附件部分
if (attachmentPath != null && !attachmentPath.isEmpty()) {
MimeBodyPart attachmentPart = new MimeBodyPart();
DataSource source = new FileDataSource(attachmentPath);
attachmentPart.setDataHandler(new DataHandler(source));
attachmentPart.setFileName(new File(attachmentPath).getName());
multipart.addBodyPart(attachmentPart);
ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
.tenantId(TENANT_ID)
.build();
try {
TokenRequestContext context = new TokenRequestContext()
.addScopes("https://graph.microsoft.com/.default");
AccessToken token = clientSecretCredential.getToken(context).block();
System.out.println(token != null ? token.getToken() : null);
} catch (Exception e) {
log.error("获取访问令牌失败: {}", e.getMessage());
}
// 设置完整消息内容
message.setContent(multipart);
final TokenCredentialAuthProvider tokenCredAuthProvider = new TokenCredentialAuthProvider(Arrays.asList("https://graph.microsoft.com/.default"), clientSecretCredential);
System.out.println("First Step Reached. ");
GraphServiceClient<Request> graphClient = GraphServiceClient.builder().authenticationProvider(tokenCredAuthProvider).buildClient();
com.microsoft.graph.models.Message message = new Message();
message.subject = subject;
ItemBody body = new ItemBody();
body.contentType = BodyType.TEXT;
body.content = "您好:\n\n 附件为您本次会议的会议纪要,烦请下载查看";
message.body = body;
LinkedList<Recipient> toRecipientsList = new LinkedList<>();
Recipient toRecipients = new Recipient();
EmailAddress emailAddress = new EmailAddress();
emailAddress.address = toEmail;
toRecipients.emailAddress = emailAddress;
toRecipientsList.add(toRecipients);
message.toRecipients = toRecipientsList;
//构建附件
LinkedList<Attachment> attachmentsList = new LinkedList<>();
byte[] recordXmlData = Files.readAllBytes(Paths.get(attachmentPath));
FileAttachment attachments = new FileAttachment();
attachments.name = attachmentPath.substring(attachmentPath.lastIndexOf("/") + 1);
attachments.oDataType = "#microsoft.graph.fileAttachment";
attachments.contentType="application/msword";
attachments.contentBytes = recordXmlData;
attachmentsList.add(attachments);
AttachmentCollectionResponse attachmentCollectionResponse = new AttachmentCollectionResponse();
attachmentCollectionResponse.value = attachmentsList;
AttachmentCollectionPage attachmentCollectionPage = new AttachmentCollectionPage(attachmentCollectionResponse, null);
message.attachments = attachmentCollectionPage;
//以指定用户邮箱发送邮件
graphClient.users(SENDER)
.sendMail(UserSendMailParameterSet.newBuilder().
withMessage(message).
withSaveToSentItems(true).build())
.buildRequest()
.post();
// 发送邮件
Transport.send(message);
log.error("邮件已成功发送: meetingId->{}", meetingId);
isSent = true;
} catch (MessagingException e) {
}catch (Exception e) {
retryCount.getAndIncrement();
// 异常处理
StringWriter sw = new StringWriter();
......@@ -131,4 +262,5 @@ public class EmailSender {
}
return isSent;
}
}
\ No newline at end of file
......@@ -38,15 +38,15 @@ public class CmeetingJob {
@Autowired
private FileProcessProducer producer;
// @PostConstruct
// public void weComUserInit(){
// weComUserSync();
// }
//
// @PostConstruct
// public void tencentUserInit(){
// TencentUserSync();
// }
@PostConstruct
public void weComUserInit(){
weComUserSync();
}
@PostConstruct
public void tencentUserInit(){
TencentUserSync();
}
/**
* 企微人员定时同步
......
......@@ -267,9 +267,9 @@ public class FileProcessTask {
// 将xml格式的内容转换为特殊json
String json = convertXmlToJSON(xml);
String recordContentPath = meetingId + "-recordContent-" + IdUtil.fastSimpleUUID() + "txt";
minioUtils.upload(recordContentPath,recordData);
String recordXmlPath = meetingId + "-recordXmlPath-" + IdUtil.fastSimpleUUID() + "xml";
try {
minioUtils.upload(recordContentPath,recordData);
//写入json文件,这里的json文件用于用户可编辑
Files.write(Paths.get(targetPath), json.getBytes());
log.info("json文件已保存到: {}", targetPath);
......@@ -312,8 +312,17 @@ public class FileProcessTask {
if(meetingInfo.getEmailPushAccess()){
log.info("用户允许邮件推送,准备推送邮件至{}------",meetingInfo.getEmail());
//邮件推送
// isPushed = emailSender.sendEmailWithAttachment("duanxincheng@chatbot.cn",meetingName,path + targetFileName + ".docx",meetingId);
isPushed = emailSender.sendEmailWithAttachment(meetingInfo.getEmail(),meetingName,path + targetFileName + ".docx",meetingId);
isPushed = emailSender.sendEmailWithAttachment("duanxincheng@chatbot.cn",meetingName,path + targetFileName + ".docx",meetingId);
try {
// isPushed = emailSender.sendEmailWithAttachment(meetingInfo.getEmail(),meetingName,path + targetFileName + ".docx",meetingId);
} catch (Exception e) {
log.error("邮件推送失败: {}", e.getMessage(), e);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
processLogService.log(meetingId,subMeetingId,"【邮件推送】:"+sw.toString());
throw new RuntimeException(e);
}
if(isPushed)
processLogService.log(meetingId,subMeetingId,"用户允许邮件推送,推送邮件至"+meetingInfo.getEmail());
// emailSender.sendEmailWithAttachment("xuwentao@chatbot.cn",meetingName,path + targetFileName + ".docx",meetingId);
......
......@@ -103,7 +103,7 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te
// 检查重名并设置标志
markDuplicateNamesTecent(users);
// 批量插入数据库(分批次)
int batchSize = 10;
int batchSize = 1000;
for (int i = 0; i < users.size(); i += batchSize) {
List<TencentMeetingUser> batch = users.subList(i, Math.min(i + batchSize, users.size()));
batchInsert(batch);
......@@ -123,7 +123,7 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te
// 查询近两天的会议录制列表
try {
ZonedDateTime now = ZonedDateTime.now();
String startTime = String.valueOf(now.minusDays(5).toEpochSecond());
String startTime = String.valueOf(now.minusDays(2).toEpochSecond());
String endTime = String.valueOf(now.toEpochSecond());
AtomicInteger currentPage = new AtomicInteger(1);
Long totalPage = 1L;
......
......@@ -22,6 +22,6 @@
SELECT * FROM user_tencentmeeting
</select>
<select id="getUsernameByUserId" resultType="java.lang.String">
SELECT user_name FROM user_tencentmeeting where user_id = #{userId}
SELECT user_name FROM user_tencentmeeting where user_id = #{userId} limit 1
</select>
</mapper>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论