调用azure的npm实现outlook_api模拟查看邮件、发送邮件(实现web版接受outlook邮件第一步)

news2024/12/24 10:26:28

文章目录

    • ⭐前言
    • ⭐注册azure应用
      • 💖添加权限
    • ⭐调用npm 实现收发邮件
      • 💖安装依赖
      • 💖创建appSettings.js 放置密钥
      • 💖创建graphHelper.js封装功能
      • 💖主文件index.js 对外暴露
      • 💖效果
    • ⭐结束

yma16-logo

⭐前言

大家好,我是yma16,本文分享 调用azure的npm实现outlook_api模拟查看邮件、发送邮件。
背景:

模拟outlook邮件客户端收发邮件

该系列往期文章:
前端笔记_OAuth规则机制下实现个人站点接入qq三方登录
OAuth机制_web站点接入微软azure账号进行三方登录
官网教程:
https://learn.microsoft.com/zh-cn/graph/tutorials/javascript?context=outlook%2Fcontext&tabs=aad

⭐注册azure应用

记住客户端id和租户id,验证使用
在这里插入图片描述

💖添加权限

身份验证打开允许客户端流
在这里插入图片描述
添加email api
在这里插入图片描述

⭐调用npm 实现收发邮件

💖安装依赖

安装官方身份验证库 @azure/identity

npm install @azure/identity @microsoft/microsoft-graph-client isomorphic-fetch readline-sync

💖创建appSettings.js 放置密钥

管理密钥文件appSettings.js

const settings = {
    'clientId': '应用客户端id',
    'tenantId': '应用租户id',
    'graphUserScopes': [
        'user.read',
        'mail.read',
        'mail.send'
    ]
};

module.exports = settings;

💖创建graphHelper.js封装功能

graphHelper.js放置功能

require('isomorphic-fetch');
const azure = require('@azure/identity');
const graph = require('@microsoft/microsoft-graph-client');
const authProviders =
    require('@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials');

let _settings = undefined;
let _deviceCodeCredential = undefined;
let _userClient = undefined;

function initializeGraphForUserAuth(settings, deviceCodePrompt) {
    // Ensure settings isn't null
    if (!settings) {
        throw new Error('Settings cannot be undefined');
    }

    _settings = settings;

    _deviceCodeCredential = new azure.DeviceCodeCredential({
        clientId: settings.clientId,
        tenantId: settings.tenantId,
        userPromptCallback: deviceCodePrompt
    });

    const authProvider = new authProviders.TokenCredentialAuthenticationProvider(
        _deviceCodeCredential, {
            scopes: settings.graphUserScopes
        });

    _userClient = graph.Client.initWithMiddleware({
        authProvider: authProvider
    });
}
async function getUserTokenAsync() {
    // Ensure credential isn't undefined
    if (!_deviceCodeCredential) {
        throw new Error('Graph has not been initialized for user auth');
    }

    // Ensure scopes isn't undefined
    if (!_settings?.graphUserScopes) {
        throw new Error('Setting "scopes" cannot be undefined');
    }

    // Request token with given scopes
    const response = await _deviceCodeCredential.getToken(_settings?.graphUserScopes);
    return response.token;
}
async function getUserAsync() {
    // Ensure client isn't undefined
    if (!_userClient) {
        throw new Error('Graph has not been initialized for user auth');
    }

    return _userClient.api('/me')
    // Only request specific properties
        .select(['displayName', 'mail', 'userPrincipalName'])
        .get();
}
async function getInboxAsync() {
    // Ensure client isn't undefined
    if (!_userClient) {
        throw new Error('Graph has not been initialized for user auth');
    }

    return _userClient.api('/me/mailFolders/inbox/messages')
        .select(['from', 'isRead', 'receivedDateTime', 'subject'])
        .top(25)
        .orderby('receivedDateTime DESC')
        .get();
}
async function sendMailAsync(subject, body, recipient) {
    // Ensure client isn't undefined
    if (!_userClient) {
        throw new Error('Graph has not been initialized for user auth');
    }

    // Create a new message
    const message = {
        subject: subject,
        body: {
            content: body,
            contentType: 'text'
        },
        toRecipients: [
            {
                emailAddress: {
                    address: recipient
                }
            }
        ]
    };

    // Send the message
    return _userClient.api('me/sendMail')
        .post({
            message: message
        });
}
// This function serves as a playground for testing Graph snippets
// or other code
async function makeGraphCallAsync() {
    // INSERT YOUR CODE HERE
}
module.exports.makeGraphCallAsync = makeGraphCallAsync;
module.exports.sendMailAsync = sendMailAsync;
module.exports.getInboxAsync = getInboxAsync;
module.exports.getUserAsync = getUserAsync;
module.exports.getUserTokenAsync = getUserTokenAsync;
module.exports.initializeGraphForUserAuth = initializeGraphForUserAuth;

💖主文件index.js 对外暴露

index.js 功能

const readline = require('readline-sync');

const settings = require('./appSettings');
const graphHelper = require('./graphHelper');

async function main() {
    console.log('JavaScript Graph Tutorial');

    let choice = 0;

    // Initialize Graph
    initializeGraph(settings);

    // Greet the user by name
    await greetUserAsync();

    const choices = [
        'Display access token',
        'List my inbox',
        'Send mail',
        'Make a Graph call'
    ];

    while (choice != -1) {
        choice = readline.keyInSelect(choices, 'Select an option', { cancel: 'Exit' });

        switch (choice) {
            case -1:
                // Exit
                console.log('Goodbye...');
                break;
            case 0:
                // Display access token
                await displayAccessTokenAsync();
                break;
            case 1:
                // List emails from user's inbox
                await listInboxAsync();
                break;
            case 2:
                // Send an email message
                await sendMailAsync();
                break;
            case 3:
                // Run any Graph code
                await makeGraphCallAsync();
                break;
            default:
                console.log('Invalid choice! Please try again.');
        }
    }
}
function initializeGraph(settings) {
    // TODO
    graphHelper.initializeGraphForUserAuth(settings, (info) => {
        // Display the device code message to
        // the user. This tells them
        // where to go to sign in and provides the
        // code to use.
        console.log(info.message);
    });
}

async function greetUserAsync() {
    // TODO

    try {
        const user = await graphHelper.getUserAsync();
        console.log(`Hello, ${user?.displayName}!`);
        // For Work/school accounts, email is in mail property
        // Personal accounts, email is in userPrincipalName
        console.log(`Email: ${user?.mail ?? user?.userPrincipalName ?? ''}`);
    } catch (err) {
        console.log(`Error getting user: ${err}`);
    }
}



async function displayAccessTokenAsync() {
    // TODO
    try {
        const userToken = await graphHelper.getUserTokenAsync();
        console.log(`User token: ${userToken}`);
    } catch (err) {
        console.log(`Error getting user access token: ${err}`);
    }

}

async function listInboxAsync() {
    // TODO
    try {
        const messagePage = await graphHelper.getInboxAsync();
        const messages = messagePage.value;

        // Output each message's details
        for (const message of messages) {
            console.log(`Message: ${message.subject ?? 'NO SUBJECT'}`);
            console.log(`  From: ${message.from?.emailAddress?.name ?? 'UNKNOWN'}`);
            console.log(`  Status: ${message.isRead ? 'Read' : 'Unread'}`);
            console.log(`  Received: ${message.receivedDateTime}`);
        }

        // If @odata.nextLink is not undefined, there are more messages
        // available on the server
        const moreAvailable = messagePage['@odata.nextLink'] != undefined;
        console.log(`\nMore messages available? ${moreAvailable}`);
    } catch (err) {
        console.log(`Error getting user's inbox: ${err}`);
    }
}

async function sendMailAsync() {
    // TODO
    try {
        // Send mail to the signed-in user
        // Get the user for their email address
        const user = await graphHelper.getUserAsync();
        const userEmail = user?.mail ?? user?.userPrincipalName;

        if (!userEmail) {
            console.log('Couldn\'t get your email address, canceling...');
            return;
        }

        await graphHelper.sendMailAsync('Testing Microsoft Graph',
            'Hello world!', userEmail);
        console.log('Mail sent.');
    } catch (err) {
        console.log(`Error sending mail: ${err}`);
    }
}

async function makeGraphCallAsync() {
    // TODO
    try {
        await graphHelper.makeGraphCallAsync();
    } catch (err) {
        console.log(`Error making Graph call: ${err}`);
    }
}

main();

💖效果

运行首先需要授权
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code S6HDWLLQ3 to authenticate.

在这里插入图片描述

手动授权输入返回的验证码
在这里插入图片描述
登录outlook
在这里插入图片描述
登录成功
在这里插入图片描述
可以打印token
在这里插入图片描述
后续把这个放在koa暴露接口可以实现web简陋版的邮箱登录

⭐结束

本文分享到这结束,如有错误或者不足之处欢迎指出!
blue-sky-boy

👍 点赞,是我创作的动力!
⭐️ 收藏,是我努力的方向!
✏️ 评论,是我进步的财富!
💖 感谢你的阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1987237.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我的cesium for UE踩坑之旅(蓝图、UI创建)

我的小小历程 过程创建对应目录,并将要用到的图片、资源放入对应目录下内容浏览器 窗口中右键,创建一个控件蓝图,用来编辑界面UI绘制画布面板(canvas)调整整体布局加入对应的控件将UI加入到关卡中 备注搜索不到 Add To…

【原创】简易学生成绩查询系统Excel版

简易学生成绩查询系统通常是为了方便学校、教师和学生能够快速查询和管理成绩而设计的一种工具。从之前提供的信息来看,我们可以总结出简易学生成绩查询系统的一些常见功能: ### 易查分成绩查询系统功能特点: - **成绩导入与管理**&#xff…

Spark_获取id对应日期的所在月份的天数完整指南

开发背景 前段时间有一个开发需求的一小块用到了这,是一个利用率的计算。规则是某id下的近半年的值的小时利用率。 计算规则是某值除以近半年 天数以及24h,但是月份里面数据有空值,所以要计算一下id对应的月份的天数,并且过滤掉数据有空值的天…

Azure openai connection with javascript

题意:使用JavaScript与Azure OpenAI进行连接 问题背景: I have created my chatbot with javascript and used open ai. I need to change it to azure open ai but can not find the connection details for javascript. This is how i connect with p…

十九、虚拟机VMware Workstation(CentOSDebian)的安装

目录 🌻🌻 一、安装 VMware Workstation1.1 安装 VMware Workstation1.2 虚拟机上安装 CentOS1.3 虚拟机安装 Debian 二、配置Debian方便第三方工具远程连接2.1 配置debian2.2 安装远程SSH工具并连接 一、安装 VMware Workstation 官网下载 本地资源库…

端到端自动驾驶:终局还是误区?

近年来,端到端自动驾驶技术成为了汽车行业的热议话题。尤其是在2024年,各家新兴车企纷纷打出端到端的旗号,似乎谁没有搞端到端,就会被市场淘汰。然而,端到端自动驾驶真的是自动驾驶技术的终局吗?本文将深入…

使用QML的ListView自制树形结构图TreeView

背景 感觉QML自带的TreeView不是很好用,用在文件路径树形结构比较多,但是想用在自己数据里,就不太方便了,所以自己做一个。 用‘ListView里迭代ListView’的方法,制作树形结构,成果图: 代码…

尚硅谷谷粒商城项目笔记——四、使用docker安装redis【电脑CPU:AMD】

四、使用docker安装redis 注意: 因为电脑是AMD芯片,自己知识储备不够,无法保证和课程中用到的环境一样,所以环境都是自己根据适应硬件软件环境重新配置的,这里的虚拟机使用的是VMware。 在解决了 Docker 安装的问题之…

app逆向抓包技巧:SSL Pinning检测绕过

本篇博客旨在记录学习过程,不可用于商用等其它途径 场景 在charles抓包下,某斑马app在注册时发现点击登录毫无反应,看抓包结果提示SSL handshake with client failed,确定是触发了SSL/TLS Pinning(证书锁定&#xff…

Flutter 正在迁移到 Swift Package Manager ,未来会弃用 CocoaPods 吗?

什么是 Swift Package Manager ?其实 Swift Package Manager (SwiftPM) 出现已经挺长一段时间了,我记得第一次听说 SwiftPM 的时候,应该还是在 2016 年,那时候 Swift 3 刚发布,不过正式出场应该还是在 2018 年的 Apple…

【研发日记】嵌入式处理器技能解锁(二)——TI C2000 DSP的SCI(串口)通信

文章目录 前言 背景介绍 SCI通信 Transmitter Receiver SCI中断 分析和应用 总结 参考资料 前言 见《【研发日记】嵌入式处理器技能解锁(一)——多任务异步执行调度的三种方法》 背景介绍 近期使用TI C2000 DSP做的一个嵌入式系统开发项目中,在使用它的SCI&…

缓存异常:缓存雪崩、击穿、穿透

缓存异常:缓存雪崩、击穿、穿透 缓存雪崩 定义 大量的应用请求无法在 Redis 缓存中进行处理,会将这些请求发送到数据库,导致数据库的压力激增,是发生在大量数据同时失效的场景下 原因 1. 缓存中有大量数据同时过期&#xff0…

常见中间件漏洞复现之【Apache】!

CVE-2021-41773 Apache HTTP Server 路径穿越漏洞 漏洞简介 该漏洞是由于Apache HTTP Server 2.4.49版本存在⽬录穿越漏洞,在路径穿越⽬录 <Directory/>Require all granted</Directory>允许被访问的的情况下&#xff08;默认开启&#xff09;&#xff0c;攻击者…

【机器人学】6-4.六自由度机器人运动学参数辨识-机器人精度验证【附MATLAB代码】

前言 前两个章节以及完成了机器人参数辨识。 【机器人学】6-1.六自由度机器人运动学参数辨识-辨识数学模型的建立 【机器人学】6-2.六自由度机器人运动学参数辨识-优化方法求解辨识参数 标定了工具端、基座以及机器人本身的DH参数。那么我们的机器人精度如何呢&#xff1f;机…

实操: 如何在AirBox上跑Stable Diffusion 3

以下文章来源于Radxa &#xff0c;作者瑞莎 Stable Diffusion 3 Medium 是一种多模态扩散变换器 (MMDiT) 文本到图像模型&#xff0c;在图像质量、排版、复杂提示理解和资源效率方面具有显著提升的性能。 目前瑞莎团队使用 Stable Diffusion 3 Medium 开源模型&#xff0c;通过…

领域驱动设计实战:使用Wow框架重构银行转账系统

银行账户转账案例是一个经典的领域驱动设计&#xff08;DDD&#xff09;应用场景。 接下来我们通过一个简单的银行账户转账案例&#xff0c;来了解如何使用 Wow 进行领域驱动设计以及服务开发。 银行转账流程 准备转账&#xff08;Prepare&#xff09;&#xff1a; 用户发起…

24/8/6算法笔记 不同核函数

import numpy as np from sklearn import datasets from sklearn.svm import SVC from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score import matplotlib.pyplot as plt 加载数据 X,ydatasets.load_wine(return_X_y True) d…

python中的turtle库(适用于计算机二级)

窗体函数 turtle.setup(width,height,startx,starty) width:窗口宽度 height:窗口高度 startx&#xff1a;窗口与屏幕左侧的距离 starty&#xff1a;窗口与屏幕顶部的距离 常用的引进turtle方法 # 引入turtle import turtle# 引入turtle库中的所有函数 from turtle import *# …

如何使用AI提问提示词(Prompt):让你的提问回答更有效

现在AI模型在日常工作和生活中的应用越来越广泛&#xff0c;无论是生成文本、回答问题&#xff0c;还是进行对话互动&#xff0c;提示词&#xff08;Prompt&#xff09;在与AI交互时起着至关重要的作用&#xff0c;一个好的提示词可以引导AI生成更加准确、有价值的内容。 那么…

【简历】宜春某二本学院:Java简历指导,秋招简历通过率低

简历说明 这是一个25届的二本宜春某学院的这个Java简历&#xff0c;今天看了两个简历&#xff0c;包括前面个985的&#xff0c;也是12306&#xff0c;这个12306已经烂大街&#xff0c;是个人都知道这个项目了&#xff0c;所以不要放在简历上&#xff0c;你不管大厂中厂还是小公…