Outlook不支持账号密码改OAuth2.0认证方式获取outlook邮箱收件箱以及附件(python)

发布时间:2026/10/23 10:50:27

Outlook不支持账号密码改OAuth2.0认证方式获取outlook邮箱收件箱以及附件(python) 1.在Azure 门户注册应用程序微软文档地址重定向的地址配置(微软地址) https://login.microsoftonline.com/common/oauth2/nativeclient注册应用地址2.程序代码#安装包以及需要的驱动 pip3 install playwright playwright installget_token1() 》 grant_type: client_credentials最简单 ,不需要模拟登录去获取code,只需要把获取邮箱地址 /me/部分换成/users/xxxddd.com(公司对应邮箱)即可import base64 import json import logging from io import BytesIO from playwright.sync_api import sync_playwright import time import urllib.parse import requests from pia.utils.cache import get_redis_value, set_redis_expire from pia.utils.constants import OUTLOOK_CLIENT_ID, OUTLOOK_TENANT_ID, OUTLOOK_CLIENT_SECRET, OUTLOOK_REDIRECT_URI, \ COS_OUTLOOK_DIR, OUTLOOK_TOP from pia.utils.cos_upload import upload_stream_to_cos, check_exists from pia.utils.reids_key import OUTLOOK_TOKEN log logging.getLogger(__name__) #这一步很重要是给用户读取收件箱的权限赋予给你注册的应用这样才能基于应用去读取邮箱这里需要账号和密码 #账号登录 官方文档 https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow def get_authorization_code(_user_name, _pass_word): with sync_playwright() as play_wright: browser play_wright.chromium.launch(headlessTrue) context browser.new_context(localezh-CN, accept_downloadsTrue) try: # Open new page page context.new_page() url fhttps://login.microsoftonline.com/{OUTLOOK_TENANT_ID}/oauth2/v2.0/authorize?client_id{OUTLOOK_CLIENT_ID}response_typecoderedirect_uri{OUTLOOK_REDIRECT_URI}response_modequeryscopehttps%3A%2F%2Fgraph.microsoft.com%2Fmail.readstate12345 page.goto(url) page.click([placeholder\电子邮件、电话或\\ Skype\]) page.fill([placeholder\电子邮件、电话或\\ Skype\], _user_name) with page.expect_navigation(): page.click(text下一步) page.click([placeholder\密码\]) page.fill([placeholder\密码\], _pass_word) # 点击登录并等待导航 with page.expect_navigation(timeout6000): page.click(text登录, timeout2000) # 如果有确认信息点击是 try: page.click(text是, timeout2000) except: pass # 上一步没生效在执行一次 try: page.click(text是, timeout2000) except: pass # 如果有确认信息点击是 try: # 点击接受按钮 page.click(input[typesubmit][nameidSIButton9][value接受], timeout2000) except: pass time.sleep(3) # 解析 URL 获取授权码 query dict(urllib.parse.parse_qsl(urllib.parse.urlsplit(page.url).query)) authorization_code query.get(code) if not authorization_code: # todo 待开发 print(f*****************{_user_name}: 密码错误\n\n) return return authorization_code except Exception as e: print(foutlook获取code失败:::{traceback.format_exc()}) # 输出异常信息 # 记录错误继续执行后续操作 return finally: context.close() browser.close() def get_token(authorization_code): param {client_id: OUTLOOK_CLIENT_ID, code: authorization_code, redirect_uri: OUTLOOK_REDIRECT_URI, grant_type: authorization_code, client_secret: OUTLOOK_CLIENT_SECRET } token_headers {Content-Type: application/x-www-form-urlencoded} token_url fhttps://login.microsoftonline.com/{OUTLOOK_TENANT_ID}/oauth2/v2.0/token res requests.post(urltoken_url, headerstoken_headers, dataparam) access_token json.loads(res.text).get(access_token) return fBearer {access_token} # api官方文档 https://learn.microsoft.com/en-us/graph/api/mailfolder-list-messages?viewgraph-rest-1.0 def get_inbox(authorization, str_start, str_end): condition ?$filter if str_start: condition fReceivedDateTime ge {str_start} and condition freceivedDateTime lt {str_end} # 获取收件箱里面的 邮件 endpoint fhttps://graph.microsoft.com/v1.0/me/mailFolders/inbox/messages{condition}$top{OUTLOOK_TOP} http_headers {Authorization: authorization, Accept: application/json, Content-Type: application/json} data requests.get(endpoint, headershttp_headers, streamFalse).json() return data def get_email_attachments(authorization, email_id): # 获取收件箱里面的邮件附件 endpoint fhttps://graph.microsoft.com/v1.0/me/messages/{email_id}/attachments http_headers {Authorization: authorization, Accept: application/json, Content-Type: application/json} data requests.get(endpoint, headershttp_headers, streamFalse).json() return data #程序入口 def deal_user_email(_user_name, _pass_word, str_start, str_end) - list: result [] redis_key f{OUTLOOK_TOKEN}:{_user_name} # 缓存 authorization get_redis_value(redis_key) if authorization: pass else: authorization_code get_authorization_code(_user_name, _pass_word) authorization get_token(authorization_code) if authorization: set_redis_expire(redis_key, authorization, 60 * 60) if authorization: email get_inbox(authorization, str_start, str_end) if email: email_values email.get(value) if email_values: for value in email_values: # 邮件 id email_id value.get(id) # 是否存在附件 True/False has_attachments value.get(hasAttachments) value.update({attachments: {}}) if has_attachments and email_id: attachment_dict upload_attachment_to_cos(authorization, email_id, _user_name) value.update({attachments: attachment_dict}) result.append(value) else: log.error(foutlook user_name: {_user_name} Authorization Failed) return result 附件上传到cos def upload_attachment_to_cos(authorization, email_id, _user_name): attachment_dict {} attachments get_email_attachments(authorization, email_id) if attachments: attachment_values attachments.get(value) if attachment_values: for _value in attachment_values: # 附件 name attachment_name _value.get(name) # 附件 内容 attachment_content _value.get(contentBytes) # Step 1: 解码 Base64 字符串 decoded_data base64.b64decode(attachment_content) # Step 2: 创建一个 BytesIO 对象作为文件流 file_stream BytesIO(decoded_data) object_name f{COS_OUTLOOK_DIR}/{_user_name}/{email_id}/{attachment_name} is_exists, url check_exists(object_name) if not is_exists: url upload_stream_to_cos(file_stream, object_name) attachment_dict.update({attachment_name: url}) return attachment_dict #client_credentials 该方式最简单,拿到token后 只要是该应用下的 邮箱 xxxddd.com 都能直接获取 def get_token1(): # 替换为您的应用信息 client_id tenant_id client_secret # 请求访问令牌 token_url fhttps://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token data { grant_type: client_credentials, client_id: client_id, client_secret: client_secret, scope: https://graph.microsoft.com/.default } response requests.post(token_url, datadata) if response.status_code 200: access_token response.json().get(access_token) # 获取收件箱里面的 邮件 endpoint fhttps://graph.microsoft.com/v1.0/users/xxxddd.com/mailFolders/inbox/messages http_headers {Authorization: access_token, Accept: application/json, Content-Type: application/json} data requests.get(endpoint, headershttp_headers, streamFalse).json() print(fAccess Token: {access_token}) else: print(fError: {response.status_code}, {response.text})import traceback from datetime import datetime, timedelta from django.core.management import BaseCommand import logging import uuid from django.db import transaction from pia.models import PiaOutLookTask, PiaOutLookData from pia.utils.aes import decrypted from pia.utils.outlook import deal_user_email logging logging.getLogger(task) #任务的方式拉取 class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument(trace_id, typestr) def handle(self, *args, **options): trace_id options[trace_id] if not trace_id: trace_id str(uuid.uuid4()) self.trace_id trace_id self.writeLog(outlook email start) outlook_task PiaOutLookTask.objects.values(id, user_name, pwd, execution_time) for x in outlook_task: _id x.get(id) user_name x.get(user_name) self.writeLog(f############## outlook email user_name:{user_name} start ##############) pwd x.get(pwd) execution_time x.get(execution_time) # 获取当前时间 current_time datetime.now() # 格式化为 YYYY-MM-DD end_time current_time.strftime(%Y-%m-%dT%H:%M:%S) try: if user_name and pwd: _pwd decrypted(pwd) result deal_user_email(user_name, _pwd, f{execution_time}Z, F{end_time}Z) with transaction.atomic(): PiaOutLookTask.objects.filter(id_id).update(status0, execution_timeend_time) outlook_data PiaOutLookData.objects.filter(outlook_task_id_id, start_timeexecution_time, end_timeend_time) if outlook_data: outlook_data.update(contentresult) else: PiaOutLookData.objects.create(outlook_task_id_id, start_timeexecution_time, end_timeend_time, contentresult) self.writeLog(f############## outlook email user_name:{user_name} end ##############) except Exception: PiaOutLookTask.objects.filter(id_id).update(status1, execution_timeend_time) self.writeLog( f############## outlook email user_name:{user_name} execution failed::::{traceback.format_exc()}) self.writeLog(outlook email end) def writeLog(self, msg: str): logging.info(f[{self.trace_id}] {msg})
延伸阅读

更多相关文章

2026/10/22 22:45:52

Mac挖矿病毒排查与清理实战:从异常发热到彻底清除

1. 项目概述:当Mac风扇狂转,我意识到事情不简单那天下午,我正在用MacBook Pro处理一份文档,风扇突然开始发出持续的、不寻常的啸叫声,机身C面靠近Touch Bar的位置烫得可以煎鸡蛋。我下意识地看了一眼活动监视器&#x…

2026/10/21 11:43:56

Calibre电子书格式转换实用工具

Calibre电子书格式转换实用工具 【免费下载链接】calibre The official source code repository for the calibre ebook manager 项目地址: https://gitcode.com/GitHub_Trending/ca/calibre 想让一本EPUB格式的书在只支持MOBI的阅读器上打开,格式转换是绕不…

2026/10/23 10:50:13

YOLOv5工业视觉实战:钢轨缺陷检测系统代码全解析

我们做工业视觉的人,其实天天都在和"脏、乱、差"的数据打交道。钢轨表面缺陷检测就是其中特别典型的一个场景——目标小、形态杂、环境光干扰大、误报代价又高。这几年深度学习方案逐步落地,YOLOv5因为工程生态成熟、部署链路短,成…

2026/10/23 10:50:13

本地部署LaMa模型:三分钟搭建AI图像修复橡皮擦工具

前两天翻相册的时候我特别烦——好好一张照片,垃圾桶、路人、电线杆全在里面,想发朋友圈都得先修半天。以前我得打开修图软件,用内容识别填充一点一点蹭;现在不一样了,我把照片拖进自己搭的小工具里,用鼠标…

2026/10/23 10:50:13

自动排课系统:基于约束满足(CSP)的工程化落地实践

简介:这是一套面向高校教务系统开发者与计算机专业学生的自动排课系统实现源码,聚焦教育信息化场景中课程表智能生成这一核心痛点,解决人工排课易冲突、效率低、难兼顾主副科与时段分布等现实问题。资源包共334个文件,含52个Java源…

2026/10/23 10:50:13

Dynamic IR Drop分析:为何必须用VCD波形替代vectorless

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/23 10:45:12

credui.dll丢失怎么修复?系统文件恢复与DLL报错排查全攻略

今天在帮朋友处理一台电脑时,又看到那个熟悉的弹窗:打开某个软件,屏幕中间窜出一句“无法启动此程序,因为计算机中丢失credui.dll”,点“确定”之后,软件要么直接没反应,要么勉强能进但功能残缺…

2026/10/22 11:29:28

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/23 0:02:26

Verilog实现FPGA密码锁:矩阵键盘与状态机设计实战

说实话,这几年接触了不少想入门FPGA的朋友,如果你问哪个项目能一口气把Verilog的核心基本功串起来,我通常会推荐电子密码锁。这个项目看着不起眼,却把矩阵键盘扫描、按键消抖、状态机设计、动态显示刷新、外设控制这些数字逻辑里的…

2026/10/23 0:02:26

数据服务监控运维实战:从指标体系到告警治理与故障排查

周末凌晨两点,手机震了。第一反应是“数据服务挂了”。打开电脑看了下,果然,某张核心报表的数据产出时间已经超过SLA两小时,下游三个业务方连着发来问询。这种场景,做过大数据运维的人都不会陌生。数据服务的监控与运维…

2026/10/23 0:02:26

FreeRTOS任务通知实战详解:内核原理、API与避坑指南

裸机编程切到RTOS之后,任务之间的通信和同步永远是躲不开的坎。前面聊过队列、信号量、互斥锁、事件组,这次把FreeRTOS任务通知(Task Notification)单独拎出来讲透。原因很简单:任务通知是FreeRTOS里最容易用错、也最容…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑