Microsoft - SDK

API 地址:

https://docs.microsoft.com/zh-cn/graph/api/user-list?view=graph-rest-1.0&tabs=http

一. 添加Maven依赖

// 注意:SpringBoot版本在2.4.0版本以上的只需要加这一个依赖,本人亲测2.4.1版本
<!--Exchange Online-->
<dependency>
    <groupId>com.microsoft.graph</groupId>
    <artifactId>microsoft-graph</artifactId>
    <version>3.0.0</version>
</dependency>
// 如果SpringBoot版本在2.4.0以下,需要加以下两个依赖,本人亲测2.2.1.RELEASE版本,其他版本并未测试
<dependency>
    <groupId>io.projectreactor.netty</groupId>
    <artifactId>reactor-netty</artifactId>
    <version>1.0.4</version>
</dependency>

<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-core</artifactId>
    <version>3.4.4</version>
</dependency>

二. SDK实现

1. 获取客户端服务

public static GraphServiceClient getClient() {
    /* 1. 构建客户端参数:国内版需要指定 authorityHost 参数 */
    ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
            .clientId(AzureConstant.CLIENT_ID)
            .clientSecret(AzureConstant.CLIENT_SECRET)
            .tenantId(AzureConstant.TENANT_ID)
            .authorityHost(AzureConstant.LOGIN)
            .build();

    /* 2. 构建客户端凭证:国内版需要指定 SCOPE 参数 */
    TokenCredentialAuthProvider tokenCredAuthProvider
                = new TokenCredentialAuthProvider(Collections.singletonList(AzureConstant.SCOPE), clientSecretCredential);

    /* 3. 构建客户端服务 */
    GraphServiceClient graphServiceClient = GraphServiceClient.builder().authenticationProvider(tokenCredAuthProvider).buildClient();
    graphServiceClient.setServiceRoot(AzureConstant.SERVICE_ROOT);
    return graphServiceClient;
}

2. 校验邮箱是否存在

// 异常为自定义异常,实操时按照实际情况编写
// mail:邮箱
public void checkMail(String mail) {
    try {
        getClient().users(mail).buildRequest().get();
    } catch (Exception e) {
        throw new QueryException(CLI_ERR_MAIL_IS_NOT_FOUND,
                String.format(CLI_ERR_MAIL_IS_NOT_FOUND.getChnMsg(), mail),
                CLI_ERR_MAIL_IS_NOT_FOUND.getEngMsg());
    }
}

3. 获取用户列表

public List<User> getUserList() {
    UserCollectionPage users = Objects.requireNonNull(getClient().users().buildRequest()).get();
    assert users != null;
    return users.getCurrentPage();
}

4. 获取用户邮件列表

// mail:邮箱
public List<Message> getUserMailList(String mail) {
    /* 1. 参数非空验证 */
    if (StringUtils.isEmpty(mail)) {
        throw new QueryException(CLI_ERR_VALIDATE_ERROR,
                String.format(CLI_ERR_VALIDATE_ERROR.getChnMsg(), "mail"),
                CLI_ERR_VALIDATE_ERROR.getEngMsg());
    }

    /* 3. 验证用户是否存在 */
    checkMail(mail);

    // 3.1 用户下的邮件集合
    List<Message> currentPage = new ArrayList<>();
    // 3.2 设置默认页码
    int page = 0;

    /* 4. 获取用户全部邮件 */
    boolean nextPage = true;
    while (nextPage) {
        // 4.1 获取用户邮件 .top:每页数据长度 .skip:跳过数据数量(类似于分页)
        MessageCollectionPage messageCollectionPage = Objects.requireNonNull(getClient().users(mail).messages()
                    .buildRequest()).top(AzureConstant.PAGE_SIZE).skip(AzureConstant.PAGE_SIZE * page).get();
        assert messageCollectionPage != null;
        currentPage.addAll(messageCollectionPage.getCurrentPage());
        // 4.2 验证是否存在下一页,如果RequestUrl不存在则为尾页
        try {
                Objects.requireNonNull(messageCollectionPage.getNextPage()).getRequestUrl();
        } catch (Exception e) {
            nextPage = false;
        }
        page++;
    }
    return currentPage;
}

5. 获取邮件

// mail:邮箱,mailId:邮件id
public Message getMail(String mail, String mailId) {
    /* 1. 验证参数 */
    if (StringUtils.isEmpty(mail)) {
        throw new QueryException(CLI_ERR_VALIDATE_ERROR,
                String.format(CLI_ERR_VALIDATE_ERROR.getChnMsg(), "mail"),
                CLI_ERR_VALIDATE_ERROR.getEngMsg());
    }
    if (StringUtils.isEmpty(mailId)) {
        throw new QueryException(CLI_ERR_VALIDATE_ERROR,
                String.format(CLI_ERR_VALIDATE_ERROR.getChnMsg(), "mailId"),
                CLI_ERR_VALIDATE_ERROR.getEngMsg());
    }

    /* 2. 验证邮箱是否存在 */
    checkMail(mail);

    /* 3. 获取邮件 */
    Message message = null;
    try {
        message = getClient().users(mail).messages(mailId).buildRequest().get();
    } catch (Exception e) {
        throw new QueryException(CLI_ERR_QUERY_MAIL,
                String.format(CLI_ERR_QUERY_MAIL.getChnMsg(), "mailId"),
                CLI_ERR_QUERY_MAIL.getEngMsg());
    }
    return message;
}

6. 回复邮件(纯文本,支持模板)

// mail:邮箱,mailId:邮件id,content:回复文本,toRecipientsList 收件人集合
public void replyMail(String mail, String mailId, String content, List<Recipient> toRecipientsList) {
    /* 1. 验证参数 */
    if (StringUtils.isEmpty(mail)) {
        throw new QueryException(CLI_ERR_VALIDATE_ERROR,
                String.format(CLI_ERR_VALIDATE_ERROR.getChnMsg(), "mail"),
                CLI_ERR_VALIDATE_ERROR.getEngMsg());
        }
    if (StringUtils.isEmpty(mailId)) {
        throw new QueryException(CLI_ERR_VALIDATE_ERROR,
                String.format(CLI_ERR_VALIDATE_ERROR.getChnMsg(), "mailId"),
                CLI_ERR_VALIDATE_ERROR.getEngMsg());
    }
    if (StringUtils.isEmpty(content)) {
        throw new QueryException(CLI_ERR_VALIDATE_ERROR,
                String.format(CLI_ERR_VALIDATE_ERROR.getChnMsg(), "content"),
                CLI_ERR_VALIDATE_ERROR.getEngMsg());
    }

    /* 2. 验证邮箱是否存在 */
    checkMail(mail);

    /* 3. 发送邮件 */
    // 3.1 设置收件人
    Message message = new Message();
    message.toRecipients = toRecipientsList;

    try {
        getClient().users(mail).messages(mailId)
                .reply(MessageReplyParameterSet
                        .newBuilder()
                        .withMessage(message)
                        .withComment(content)
                        .build())
                .buildRequest()
                .post();
    } catch (Exception e) {
        throw new QueryException(CLI_ERR_SEND_MAIL,
                String.format(CLI_ERR_SEND_MAIL.getChnMsg(), "mailId"),
                CLI_ERR_SEND_MAIL.getEngMsg());
    }
}

7. 回复邮件(文本 + 附件),该方法中“添加附件”不支持国内版账户,支持国际版账户

7.1 创建草稿
// mail:邮箱,mailId:邮件id,content:回复文本,toRecipientsList 收件人集合
public Message createReply(String mail,String mailId, String content, List<Recipient> toRecipientsList){
    // 1. 设置收件人
    Message message = new Message();
    message.toRecipients = toRecipientsList;
    // 2. 发送请求
    Message post = getClient().users(mail).messages(mailId)
            .createReply(MessageCreateReplyParameterSet
                    .newBuilder()
                    .withMessage(message)
                    .withComment(content)
                    .build())
            .buildRequest()
            .post();
    return post;
}
7.2 编辑草稿文本
// mail:邮箱,mailId:邮件id,body:原邮件body,newContent:最新回复文本,subject主题
public Message patchMail(String mail, String mailId,ItemBody body,String newContent,String subject){
    // 1. 构建消息对象
    Message message = new Message();
    message.subject = subject; // 设置主题
    body.contentType = BodyType.HTML; // 设置body类型
    body.content = newContent+body.content; // 组装body消息体
    message.body = body; // 设置body消息体
    message.inferenceClassification = InferenceClassificationType.OTHER;

    // 发送并返回请求
    return getClient().users(mail).messages(mailId)
            .buildRequest()
            .patch(message);
}
7.3 添加附件
// 邮件仅支持3M以下附件,工具类见“文件格式转换工具类:MultipartFileToFileUtils”
public boolean addFileRest(String mail, String mailId, List<MultipartFile> fileList) {
    /* 1. 构建参数 */
    for (MultipartFile f : fileList) {
        java.io.File file = null;
        byte[] data = null;
        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;
        try {
            file = MultipartFileToFileUtils.multipartFileToFile(f);
            //获取输入流
            fis = new FileInputStream(file);

            //新的 byte 数组输出流,缓冲区容量1024byte
            bos = new ByteArrayOutputStream(1024);
            //缓存
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            //改变为byte[]
            data = bos.toByteArray();
        } catch (Exception e) {
            log.error("追加附件,输入流文件错误!");
        }finally {
            try {
                assert fis != null;
                fis.close();
                assert bos != null;
                bos.close();
            } catch (IOException e) {
                log.error("关闭文件流错误!");
            }
        }

        Base64.Encoder encoder = Base64.getEncoder();
        String contentBytes = encoder.encodeToString(data);

        /* 2. 创建文件类型附件对象 */
        String postUrl = "https://graph.microsoft.com/v1.0/users('" + mail + "')/messages/" + mailId + "/attachments";

        Map<String, Object> map = new HashMap<>();
        map.put("@odata.type", "#microsoft.graph.fileAttachment");
        assert file != null;
        map.put("name", file.getName());
        map.put("contentBytes", contentBytes);
        String s = JSON.toJSONString(map);

        /* 3. 发送请求 */
        RequestEntity<String> requestEntity = RequestEntity.post(URI.create(postUrl))
                .accept(MediaType.APPLICATION_JSON)
                .header("Content-Type", "application/json")
                .header("Authorization", getToken())
                .body(s);
        try {
            restTemplate.exchange(requestEntity, Object.class);
        } catch (Exception e) {
            throw new QueryException(CLI_ERR_MAIL_FILE_SEND);
        }
        MultipartFileToFileUtils.deleteTempFile(file);
    }
    return true;
}
7.4 发送邮件
// mail:邮箱,mailId:邮件id
public void sendMail(String mail, String mailId){
    getClient().users(mail).messages(mailId).send().buildRequest().post();
}

8. 列出邮箱文件夹

// mail 卖家邮箱
public List<MailFolder> getMailFolders(String mail) {
    /* 1. 验证参数 */
    if (StringUtils.isEmpty(mail)) {
        throw new QueryException(CLI_ERR_VALIDATE_ERROR,
            String.format(CLI_ERR_VALIDATE_ERROR.getChnMsg(), "mail"),
            CLI_ERR_VALIDATE_ERROR.getEngMsg());
    }

    /* 2. 验证邮箱是否存在 */
    checkMail(mail);

    /* 3. 发送请求 */
    MailFolderCollectionPage mailFolders = null;
    try {
        mailFolders = getClient().users(mail).mailFolders().buildRequest().get();
    } catch (Exception e) {
        throw new QueryException(CLI_ERR_QUERY_MAIL_FOLDERS);
    }
    return mailFolders.getCurrentPage();
}