java 通过 microsoft graph 调用outlook(三)
这次会添加一个Reply接口,
并且使用6.10.0版本
直接上代码
一, POM
<!-- office 365 --><dependency><groupId>com.microsoft.graph</groupId><artifactId>microsoft-graph</artifactId><version>6.10.0</version><!--x-release-please-end--></dependency><dependency><groupId>com.azure</groupId><artifactId>azure-identity</artifactId><version>1.11.0</version></dependency><!-- office 365 -->
二,Service / impl
主要讲一下Reply方法,Reply本质是添加评论,我们所有回复邮件,可以看到上下文时,实际都是添加了评论而已。(对比了outlook是一样的)
而Reply添加的附件,只有最后一份才会显示附件。
其他的附件,都只能在各自发送的邮件中找到,而Reply的连续回复中,只会有最后的附件。
package com.xxx.mail.service.impl;import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.xxx.mail.service.IMailOffice365Service;
import com.microsoft.graph.models.*;
import com.microsoft.graph.serviceclient.GraphServiceClient;
import com.microsoft.graph.users.item.messages.item.reply.ReplyPostRequestBody;
import com.microsoft.graph.users.item.sendmail.SendMailPostRequestBody;
import okhttp3.Request;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;import javax.annotation.PostConstruct;
import java.util.*;
import java.util.List;@Service("mailOffice365Util")
public class MailOffice365Impl implements IMailOffice365Service {@Value("${mailOffice365.clientId}")private String clientId;@Value("${mailOffice365.tenantId}")private String tenantId;@Value("${mailOffice365.clientSecret}")private String clientSecret;//scopes = "https://graph.microsoft.com/.default"@Value("${mailOffice365.scopes}")private String scopes;GraphServiceClient graphClient;/*** auth 授权*/@PostConstructpublic void auth() {ClientSecretCredential credential = new ClientSecretCredentialBuilder().clientId(clientId).tenantId(tenantId).clientSecret(clientSecret).build();graphClient = new GraphServiceClient(credential, scopes);}/*** 获取用户信息** @param email 邮箱* @return*/public User getUser(String email) {User user = graphClient.users().byUserId(email).get(requestConfiguration -> {requestConfiguration.queryParameters.select = new String[]{"displayName", "mail", "userPrincipalName"};});return user;}/*** 邮件文件夹** @param email 邮箱* @return*/@Overridepublic MailFolderCollectionResponse getMailFolders(String email) {MailFolderCollectionResponse result = graphClient.users().byUserId(email).mailFolders().get();return result;}/*** 获取文件夹邮件** @param email 邮箱* @return*/public MessageCollectionResponse getFolderMails(String email, String folderId, int page, int size) {MessageCollectionResponse message = graphClient.users().byUserId(email).mailFolders().byMailFolderId(folderId).messages().get(requestConfiguration -> {requestConfiguration.queryParameters.select = new String[]{"id", "from", "isRead", "receivedDateTime", "subject"};requestConfiguration.queryParameters.skip = page * size;requestConfiguration.queryParameters.top = size;requestConfiguration.queryParameters.orderby = new String[]{"receivedDateTime DESC"};});return message;}/*** 获取邮件** @param email 邮箱* @return*/public MessageCollectionResponse getMails(String email, int page, int size) {MessageCollectionResponse message = graphClient.users().byUserId(email).messages().get(requestConfiguration -> {requestConfiguration.queryParameters.select = new String[]{"id", "from", "isRead", "receivedDateTime", "subject"};requestConfiguration.queryParameters.skip = page * size;requestConfiguration.queryParameters.top = size;requestConfiguration.queryParameters.orderby = new String[]{"receivedDateTime DESC"};});return message;}/*** 邮件详情** @param email 邮箱* @param messageId 邮件id* @return*/@Overridepublic Message getMailById(String email, String messageId) {Message message = graphClient.users().byUserId(email).messages().byMessageId(messageId).get(requestConfiguration -> {requestConfiguration.queryParameters.select = new String[]{"id", "from", "isRead", "receivedDateTime", "subject","body","hasAttachments"};requestConfiguration.queryParameters.expand = new String []{"attachments"};});//转换邮件中的图片message = getMailByIdWithAttachment(message);return message;}@Overridepublic List<Message> getMailByIds(String email, List<String> messageIds) {List<Message> messages = new ArrayList<>();if (!CollectionUtils.isEmpty(messageIds)) {for (String messageId : messageIds) {Message message = getMailById(email, messageId);messages.add(message);}}return messages;}/*** 获取带有图片的邮件** @param message 邮件* @return*/@Overridepublic Message getMailByIdWithAttachment(Message message) {//邮件内图片展示String emailBody = message.getBody().getContent();if(!CollectionUtils.isEmpty(message.getAttachments())) {for (Attachment attachment : message.getAttachments()) {if (attachment.getIsInline().booleanValue()) {if ((attachment instanceof FileAttachment) && (attachment.getContentType().contains("image"))) {FileAttachment fileAttachment = (FileAttachment) attachment;byte[] contentBytes = fileAttachment.getContentBytes();String imageContentIDToReplace = "cid:" + fileAttachment.getContentId();emailBody = emailBody.replace(imageContentIDToReplace,String.format("data:image;base64,%s", Base64.getEncoder().encodeToString(contentBytes)));}}}}message.getBody().setContent(emailBody);return message;}/*** 发送邮件** @param sender 发件人* @param recipient 收件人* @param subject 主题* @param body 内容* @throws Exception*/public Message sendMail(String sender, String recipient, String subject, String body) throws Exception {List<String> recipients = List.of(recipient);return sendMail(sender, recipients, subject, body, null);}/*** 发送邮件(多个收件人)** @param sender 发件人* @param recipients 多收件人* @param subject 主题* @param body 内容* @throws Exception*/public Message sendMail(String sender, List<String> recipients, String subject, String body) throws Exception {return sendMail(sender, recipients, subject, body, null);}@Overridepublic Message sendMail(String sender, List<String> recipients, String subject, String body, List<FileAttachment> files) throws Exception {// Ensure client isn't nullif (graphClient == null) {throw new Exception("Graph has not been initialized for user auth");}// Create a new messageSendMailPostRequestBody sendMailPostRequestBody = new SendMailPostRequestBody();Message message = new Message();message.setSubject(subject);ItemBody itemBody=new ItemBody();itemBody.setContent(body);itemBody.setContentType(BodyType.Html);message.setBody(itemBody);//收件人if (!CollectionUtils.isEmpty(recipients)) {List<Recipient> toRecipients=new ArrayList<>();for (String item : recipients) {Recipient recipient = new Recipient();EmailAddress emailAddress = new EmailAddress();emailAddress.setAddress(item);recipient.setEmailAddress(emailAddress);toRecipients.add(recipient);}message.setToRecipients(toRecipients);}//附件message = addAttarchment(message, files);// Send the messagesendMailPostRequestBody.setMessage(message);graphClient.users().byUserId(sender).sendMail().post(sendMailPostRequestBody);return message;}public Message replyMail(String messageId, String sender, String recipient, String body) throws Exception {List<String> recipients = List.of(recipient);return replyMail(messageId, sender, recipients, body, null);}public Message replyMail(String messageId, String sender, List<String> recipients, String body) throws Exception {return replyMail(messageId, sender, recipients, body, null);}@Overridepublic Message replyMail(String messageId, String sender, List<String> recipients, String body, List<FileAttachment> files) throws Exception {ReplyPostRequestBody replyPostRequestBody=new ReplyPostRequestBody();Message message = new Message();//附件message = addAttarchment(message, files);//收件人if (!CollectionUtils.isEmpty(recipients)) {List<Recipient> toRecipients=new ArrayList<>();for (String item : recipients) {Recipient recipient = new Recipient();EmailAddress emailAddress = new EmailAddress();emailAddress.setAddress(item);recipient.setEmailAddress(emailAddress);toRecipients.add(recipient);}message.setToRecipients(toRecipients);}replyPostRequestBody.setMessage(message);replyPostRequestBody.setComment(body);graphClient.users().byUserId(sender).messages().byMessageId(messageId).reply().post(replyPostRequestBody);return message;}@Overridepublic Message addAttarchment(Message message, List<FileAttachment> files) {if (files != null && files.size() > 0) {List<Attachment> attachmentList = new ArrayList<>();for (FileAttachment file : files) {FileAttachment attachment = new FileAttachment();attachment.setName(file.getName());attachment.setOdataType("#microsoft.graph.fileAttachment");attachment.setContentType(file.getContentType());attachment.setContentBytes(file.getContentBytes());attachment.setIsInline(file.getIsInline());attachment.setContentId(file.getContentId());attachmentList.add(attachment);}message.setAttachments(attachmentList);}return message;}@Overridepublic Message setRead(String sender, Message message) {if (!message.getIsRead()) {Message newMessage = new Message();newMessage.setIsRead(true);graphClient.users().byUserId(sender).messages().byMessageId(message.getId()).patch(newMessage);}return message;}}
三, Controller
package com.xxx.mail.controller;import com.xxx.common.core.domain.R;
import com.xxx.common.satoken.utils.LoginHelper;
import com.xxx.common.web.core.BaseController;
import com.xxx.mail.domain.MessageVo;
import com.xxx.mail.service.IMailOffice365Service;
import com.microsoft.graph.models.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.List;@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/mail365")
public class MailController extends BaseController {@AutowiredIMailOffice365Service mailOffice365Service;@GetMapping("/getUser")public R<User> getUser() {String account = LoginHelper.getLoginUser().getEmail();User user = mailOffice365Service.getUser(account);return R.ok(user);}@GetMapping("/getMailFolders")public R<List<MailFolder>> getMailFolders() {String account = LoginHelper.getLoginUser().getEmail();MailFolderCollectionResponse folder = mailOffice365Service.getMailFolders(account);return R.ok(folder.getValue());}@GetMapping("/getFolderMails")public R<List<Message>> getFolderMails(String folderId, int pageIndex) {String account = LoginHelper.getLoginUser().getEmail();MessageCollectionResponse mails = mailOffice365Service.getFolderMails(account, folderId, pageIndex, 10);return R.ok(mails.getValue());}@GetMapping("/getMails")public R<List<Message>> getMails(int pageIndex) {String account = LoginHelper.getLoginUser().getEmail();MessageCollectionResponse mails = mailOffice365Service.getMails(account, pageIndex, 10);return R.ok(mails.getValue());}@GetMapping("/getMailById")public R<Message> getMailById(String messageId) {String account = LoginHelper.getLoginUser().getEmail();Message mail = mailOffice365Service.getMailById(account, messageId);//设置已读mailOffice365Service.setRead(account,mail);return R.ok(mail);}@GetMapping("/getMailByIds")public R<List<Message>> getMailByIds(List<String> messageIds){String account = LoginHelper.getLoginUser().getEmail();List<Message> mails = mailOffice365Service.getMailByIds(account, messageIds);for(Message mail : mails){//设置已读mailOffice365Service.setRead(account,mail);}return R.ok(mails);}@PostMapping("/sendMail")public R<Message> sendMail(@RequestBody MessageVo req) throws Exception {String account = LoginHelper.getLoginUser().getEmail();mailOffice365Service.sendMail(account,req.getRecipients(),req.getSubject(),req.getBody(),req.getAttachments());return R.ok();}@PostMapping("/replyMail")public R<Message> replyMail(@RequestBody MessageVo req) throws Exception {String account = LoginHelper.getLoginUser().getEmail();Message message = mailOffice365Service.replyMail(req.getMessageId(), account, req.getRecipients(), req.getBody(), req.getAttachments());return R.ok(message);}}
MessageVo
这个类,纯粹是为了发送邮件时,带上附件一起调用接口。
package com.xxx.mail.domain;import com.microsoft.graph.models.Attachment;
import com.microsoft.graph.models.FileAttachment;
import lombok.Data;import java.util.ArrayList;
import java.util.List;@Data
public class MessageVo {private String messageId;private List<String> recipients;private String subject;private String body;private List<FileAttachment> attachments=new ArrayList<>();
}
相关文章:
java 通过 microsoft graph 调用outlook(三)
这次会添加一个Reply接口, 并且使用6.10.0版本 直接上代码 一, POM <!-- office 365 --><dependency><groupId>com.microsoft.graph</groupId><artifactId>microsoft-graph</artifactId><version>6.1…...
QT--TCP网络通讯工具编写记录
QT–TCP网络通讯工具编写记录 文章目录 QT--TCP网络通讯工具编写记录前言演示如下:一、服务端项目文件:【1.1】server_tcp.h 服务端声明文件【1.2】thread_1.h 线程处理声明文件【1.3】main.cpp 执行源文件【1.4】server_tcp.cpp 服务端逻辑实现源文件【…...
如何解决爬虫的IP地址受限问题?
使用代理IP池、采用动态IP更换策略、设置合理的爬取时间间隔和模拟正常用户行为,是解决爬虫IP地址受限问题的主要策略。代理IP池是通过集合多个代理IP来分配爬虫任务,从而避免相同的IP地址对目标网站进行高频次访问,减少被目标网站封禁的风险…...
harmony 文件上传
图片上传 1, 获取文件,这里指的是图片 在鸿蒙内部有一个API pick选择器,实现文件保存和文件选择的功能, 使用pick对象创建PhotoViewPicker实例 传入必要的参数,如选择图片的数量,和弹出窗口的位置…...
什么是安全左移如何实现安全左移
文章目录 一、传统软件开发面临的安全挑战二、什么是安全左移四、安全左移与安全开发生命周期(SDL)三、安全左移对开发的挑战五、从DevOps到DevSecOps六、SDL与DevSecOps 一、传统软件开发面临的安全挑战 传统软件开发面临的安全挑战主要包括以下几个方…...
将PCD点云投影到BEV平面得到图片
前言 点云数据作为一种丰富的三维空间信息表达方式,通常用于自动驾驶、机器人导航和三维建模等领域。然而,点云数据的直观性不如二维图像,这限制了它在一些需要快速视觉反馈的应用场景中的使用。本文将探讨如何将点云数据转换为二维图像&…...
计算机笔记14(续20个)
230.色彩的种类就是色相 饱和度就是彩度除以明度 231.RISC是精简指令集,CISC是复杂指令集 232.世界上第一台数字计算机,奠定了至今仍在使用计算机体系结构 233.数据传输中,电路交换的传输延迟最小 234.定点整数的小数点约定在最低…...
docker 使用桥接网
在Docker中使用桥接网络,你可以创建一个新的桥接网络或者使用默认的桥接网络(如果已经存在的话)。以下是创建新桥接网络和连接容器到这个网络的示例命令: 1.创建一个新的桥接网络(如果你想创建一个新的)&a…...
1金融风控相关业务介绍
金融风控相关业务介绍 学习目标 知道常见信贷风险知道机器学习风控模型的优势知道信贷领域常用术语含义1 信贷&风控介绍 信贷业务,就是贷款业务,是商业银行和互联网金融公司最重要的资产业务和主要赢利手段 通过放款收回本金和利息,扣除成本后获得利润。贷款平台预测有…...
521源码-免费教程-经常用到的Vue.js的Vue@Cli入门指导
更多网站源码学习教程,请点击👉-521源码-👈获取最新资源:521源码-网站源码-资源素材-免费下载 Vue.js是一款流行的JavaScript框架,它使得构建交互式的Web界面变得简单和快捷。VueCli是Vue.js官方提供的脚手架工具&…...
大数据技术原理(二):搭建hadoop伪分布式集群这一篇就够了
(实验一 搭建hadoop伪分布式) -------------------------------------------------------------------------------------------------------------------------------- 一、实验目的 1.理解Hadoop伪分布式的安装过程 实验内容涉及Hadoop平台的搭建和…...
中间件是什么?信创中间件有哪些牌子?哪家好用?
当今社会,中间件的重要性日益凸显,尤其是在信创背景下,选择适合的中间件产品对于推动企业数字化转型和升级具有重要意义。今天我们就来聊聊中间件是什么?信创中间件有哪些牌子?哪家好用?仅供参考哈…...
python实现520表白图案
今天是520哦,作为程序员有必要通过自己的专业知识来向你的爱人表达下你的爱意。那么python中怎么实现绘制520表白图案呢?这里给出方法: 1、使用图形库(如turtle) 使用turtle模块,你可以绘制各种形状和图案…...
【Linux】-Flink分布式内存计算集群部署[21]
注意: 本节的操作,需要前置准备好Hadoop生态集群,请先部署好Hadoop环境 简介 Flink同spark一样,是一款分布式内存计算引擎,可以支撑海量数据的分布式计算 Flink在大数据体系同样是明星产品,作为新一代的…...
《python程序语言设计》2018版第5章第44题利用python循环进行十进制变十六进制,依然是44题的旧问题。倒着打出来的16进制
它似乎也有上一道题同样道问题。就是结果可能是倒着的。我还不能用超纲的办法。似乎上一个问题的难点又传到了下面 note: 我建立了一个method_a的变量干脆把整数除16的第一次放到循环外。 这样是不是可以解决呢? 我感觉还是在整除和除于的概念中,没有解脱…...
【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(九)
课程地址: 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程,一套精通鸿蒙应用开发 (本篇笔记对应课程第 16 节) P16《15.ArkUI-状态管理-任务统计案例》 1、实现任务进度卡片 怎么让进度条和进度展示文本堆叠展示࿱…...
海山数据库(He3DB)数据仓库发展历史与架构演进:(一)传统数仓
从1990年代Bill Inmon提出数据仓库概念后经过四十多的发展,经历了早期的PC时代、互联网时代、移动互联网时代再到当前的云计算时代,但是数据仓库的构建目标基本没有变化,都是为了支持企业或者用户的决策分析,包括运营报表、企业营…...
简单快捷的图片格式转换工具:认识webp2jpg-online
经常写博客或记笔记的朋友们可能会碰到图床不支持的图片格式或图片太大需要压缩的情况。通常,我们会在浏览器中搜索在线图片格式转换器,但这些转换器往往伴有烦人的广告或要求登录,并且支持的转换格式有限。最近,我在浏览 GitHub …...
iptablese防火墙【SNAT和DNAT】
目录 1.SNAT策略及应用 1.1SNAT原理与应用 1.2 SNAT策略的工作原理 1.3 实验操练 2.DNAT策略 2.1 DNAT策略的概述 2.2 DNAT原理与应用 2.3 实验操练 1.SNAT策略及应用 1.1SNAT原理与应用 SNAT 应用环境:局域网主机共享单个公网IP地址接入Internet…...
IT行业现状与未来趋势
随着技术的不断进步,IT行业已成为推动全球经济和社会发展的关键力量。从云计算、大数据、人工智能到物联网、5G通信和区块链,这些技术正在重塑我们的生活和工作方式。你眼中IT行业的现状及未来发展趋势是怎么样的?无论您是行业领袖、技术专家…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
