Java以Graph方式发送Outlook、Exchange邮件(2022新版)——修订版,可运行

目录

问题提出

问解决题

快速解决方式

生产解决方式

注意

1、注册应用程序

2、引入需要依赖jar包——重点

3、微软管理员授予应用合适权限

4、配置maven仓库 

参考链接


问题提出

在2022年10月份,微软公司出于安全考虑,陆续取消了Exchange邮件发送的Basic认证。通俗来说就是不能再用用户名密码来直接进行认证了,但是系列的邮件服务不能停,所以需要切换Exchange邮件的认证和发送方式,所以首先放弃掉以前的ews-java-api相关的所有jar包,重新开始。

微软官方目前推荐以Graph的方式来发送Outlook系列邮件。

问解决题

话不多说,直接贴代码,替换必要参数后,可以直接运行:

快速解决方式

public static void main(String[] args) throws IOException {

        ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
                .clientId("clientId")
                .clientSecret("clientSecret")
                .tenantId("tenantId")
                .build();
        final TokenCredentialAuthProvider tokenCredAuthProvider = new TokenCredentialAuthProvider(Arrays.asList("https://graph.microsoft.com/.default"), clientSecretCredential);
        System.out.println("First Step Reached. ");

        test(tokenCredAuthProvider);
    }

    public static void test(IAuthenticationProvider authProvider) throws IOException {
        GraphServiceClient<Request> graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();

        Message message = new Message();
        message.subject = "Meet for lunch?";
        ItemBody body = new ItemBody();
        body.contentType = BodyType.TEXT;
        body.content = "The new cafeteria is open.";
        message.body = body;
        LinkedList<Recipient> toRecipientsList = new LinkedList<Recipient>();
        Recipient toRecipients = new Recipient();
        EmailAddress emailAddress = new EmailAddress();
        emailAddress.address = "bigbearxyz@outlook.com";
        toRecipients.emailAddress = emailAddress;
        toRecipientsList.add(toRecipients);
        message.toRecipients = toRecipientsList;
        //构建附件
        LinkedList<Attachment> attachmentsList = new LinkedList<Attachment>();
        FileAttachment attachments = new FileAttachment();
        attachments.name = "1111.txt";
        attachments.oDataType = "#microsoft.graph.fileAttachment";
        attachments.contentType="text/plain";
        attachments.contentBytes = Base64.getDecoder().decode("SGVsbG8gV29ybGQh");
        attachmentsList.add(attachments);
        AttachmentCollectionResponse attachmentCollectionResponse = new AttachmentCollectionResponse();
        attachmentCollectionResponse.value = attachmentsList;

        AttachmentCollectionPage attachmentCollectionPage = new AttachmentCollectionPage(attachmentCollectionResponse, null);
        message.attachments = attachmentCollectionPage;
        //以指定用户邮箱发送邮件
        graphClient.users("sender@outlook.com")
                .sendMail(UserSendMailParameterSet.newBuilder().
                        withMessage(message).
                        withSaveToSentItems(null).build())
                .buildRequest()
                .post();

    }

生产解决方式

这里的生产解决方式是对快速解决方式的补充,快速解决方式在实际的生产中使用会存在一些问题,主要是和附件相关。

首先是前面解决方式中是把所有的附件放入一个对象,而graph发送邮件附件是有大小限制的,当超过3M以后,需要用超大邮件专用的发送方式,否则会报错。

而上一个解决方法里面,是可以添加多份附件,但是只要附件的大小总和大于3M,这个邮件就无法发送,所以有了下面的面向生产的解决方案。

生产的解决方案是,把附件逐个上传,这样每个附件的大小就可以限制在3M,这种应该可以满足绝大多数的附件发送情况。

在发送的过程中,如果有大于3M的邮件,那么使用超大附件传输的方法,发送超大邮件,代码经过实际测试,可以直接使用。


    public static void main(String[] args) throws IOException {

        ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
                .clientId("clientId")
                .clientSecret("clientSecret")
                .tenantId("tenantId")
                .build();
        final TokenCredentialAuthProvider tokenCredAuthProvider = new TokenCredentialAuthProvider(Arrays.asList("https://graph.microsoft.com/.default"), clientSecretCredential);
        System.out.println("First Step Reached. ");
        buildDraftMessage(tokenCredAuthProvider);
    }


    private static final long MB = 1024 * 1024;
    private static final String  SENDER_MAIL = "sender@outlook.com";
    private static final String  RECIPIENT_MAIL = "accept@outlook.com";


    public static void buildDraftMessage(IAuthenticationProvider authProvider) throws IOException {
        GraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();
        Message message = new Message();
        message.subject = "Did you see last night's game?";
        ItemBody body = new ItemBody();
        body.contentType = BodyType.HTML;
        body.content = "They were <b>awesome</b>!";
        message.body = body;
        LinkedList<Recipient> toRecipientsList = new LinkedList<Recipient>();
        Recipient toRecipients = new Recipient();
        EmailAddress emailAddress = new EmailAddress();
        emailAddress.address = RECIPIENT_MAIL;
        toRecipients.emailAddress = emailAddress;
        toRecipientsList.add(toRecipients);
        message.toRecipients = toRecipientsList;
        //构建草稿
        Message post = graphClient.users(SENDER_MAIL).messages()
                .buildRequest()
                .post(message);
        //构建附件
        buildAttach(authProvider, post);
        //发送草稿邮件
        graphClient.users(SENDER_MAIL).messages(post.id)
                .send()
                .buildRequest()
                .post();
    }

    private static void buildAttach(IAuthenticationProvider authProvider, Message message) throws IOException {
        File file = new File("path");
        FileInputStream fileInputStream = new FileInputStream(file);
        int available = fileInputStream.available();
        if (available >= 3 * MB) {
            //附件大于3M,使用大附件专用发送方法
            bigAttach(authProvider, message, file);
        } else {
            //附件小于3M,使用普通发送方法
            commonAttach(authProvider, message, fileInputStream);
        }
    }

    public static byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024 * 4];
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        return output.toByteArray();
    }


    private static void commonAttach(IAuthenticationProvider authProvider, Message message, FileInputStream fileInputStream) throws IOException {
        GraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();
        FileAttachment attachment = new FileAttachment();
        attachment.oDataType = "#microsoft.graph.fileAttachment";
        attachment.name = "smile.pdf";
        attachment.contentBytes = toByteArray(fileInputStream);

        graphClient.users(SENDER_MAIL).messages(message.id).attachments()
                .buildRequest()
                .post(attachment);
    }

    public static void bigAttach(IAuthenticationProvider authProvider, Message message, File file) throws IOException {
        GraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();

        FileInputStream fileInputStream = new FileInputStream(file);
        int available = fileInputStream.available();
        AttachmentItem attachmentItem = new AttachmentItem();
        attachmentItem.attachmentType = AttachmentType.FILE;
        attachmentItem.name = "flower.pdf";
        attachmentItem.size = (long) available;
        UploadSession uploadSession = graphClient.users(SENDER_MAIL).messages(message.id).attachments()
                .createUploadSession(AttachmentCreateUploadSessionParameterSet
                        .newBuilder()
                        .withAttachmentItem(attachmentItem)
                        .build())
                .buildRequest()
                .post();
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        MediaType mediaType = MediaType.parse("application/octet-stream");
        RequestBody body = RequestBody.create(mediaType, file);
        Request request = new Request.Builder()
                .url(uploadSession.uploadUrl)
                .method("PUT", body)
                .addHeader("Content-Length", String.valueOf(attachmentItem.size))
                .addHeader("Content-Range", "bytes 0-" + (attachmentItem.size - 1) + "/" + attachmentItem.size)
                .addHeader("Content-Type", "application/octet-stream")
                .build();
        Response response = client.newCall(request).execute();
        System.out.println(response.body().string());

    }

 

注意

使用如上代码有几点需要注意:

1、注册应用程序

首先你需要登录微软云平台,搜索Azure Active Directory配置一个应用。

具体步骤如下:

 放下文档链接:配置应用程序文档

按照笔者的经验,学会注册就可以了,不要完全按文档来,对于Java代码级发送邮件基本没帮助。

这样就可以获取到上面的一系列参数了。

2、引入需要依赖jar包——重点

<dependency>
            <groupId>com.microsoft.graph</groupId>
            <artifactId>microsoft-graph-auth</artifactId>
            <version>0.3.0</version>
        </dependency>
        <dependency>
            <!-- Include the sdk as a dependency -->
            <groupId>com.microsoft.graph</groupId>
            <artifactId>microsoft-graph-core</artifactId>
            <version>2.0.14</version>
        </dependency>

        <dependency>
            <!-- Include the sdk as a dependency -->
            <groupId>com.microsoft.graph</groupId>
            <artifactId>microsoft-graph</artifactId>
            <version>5.42.0</version>
        </dependency>
        <dependency>
            <groupId>com.azure</groupId>
            <artifactId>azure-identity</artifactId>
            <version>1.3.3</version>
        </dependency>

这个版本配置,是笔者的心血之作,调试了好久才最终成型,这里要好好吐槽一下微软官方文档,他们依赖配置的错误百出,按照文档完全运行不了。

3、微软管理员授予应用合适权限

需要在AD应用的API权限菜单配置合适的Graph权限,最要紧的是要管理员授予权限,之后就可以正常访问了。

4、配置maven仓库 

微软没有开放公网仓库,所以需要引入指定的maven仓库,github链接

<profiles>
  <profile>
     <id>allow-snapshots</id>
        <activation><activeByDefault>true</activeByDefault></activation>
     <repositories>
       <repository>
         <id>snapshots-repo</id>
         <url>https://oss.sonatype.org/content/repositories/snapshots</url>
         <releases><enabled>false</enabled></releases>
         <snapshots><enabled>true</enabled></snapshots>
       </repository>
     </repositories>
   </profile>
</profiles>

实际项目引入模式为:

参考链接

最后,再给大家提供几个微软获取token的参考文档:

微软身份平台和 OAuth 2.0 授权代码流

Graph使用参考,支持各种语言

最后说一句,直接用我的代码及pom即可。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值