如何用Python创建Outlook邮件跟踪服务(含Microsoft Graph与本地服务)
解决方案:两类Python邮件跟踪服务实现
咱先搞定第一个基于Microsoft Graph的邮件跟踪服务,这个方案跨平台友好,不需要依赖本地Outlook客户端,只要能访问Graph API就能运行。
方案1:基于Microsoft Graph的邮件跟踪服务
前期准备
- 去Azure Active Directory注册一个应用,拿到三个核心参数:
CLIENT_ID、CLIENT_SECRET、TENANT_ID - 给应用添加权限:如果是用户级使用,加Delegated权限
Mail.Read和Mail.Send;如果是服务级无人值守场景,加Application权限,记得让管理员授予权限同意 - 安装依赖包:
pip install msgraph-core python-dotenv requests
完整代码实现
先创建.env文件存配置信息(避免硬编码敏感数据):
CLIENT_ID=你的客户端ID CLIENT_SECRET=你的客户端密钥 TENANT_ID=你的租户ID TARGET_SUBJECT=目标邮件主题 FORWARD_TO=要转发的收件人邮箱
然后是Python核心代码:
import os import time from dotenv import load_dotenv from msgraph.core import GraphClient from azure.identity import ClientSecretCredential # 加载环境变量 load_dotenv() # 初始化Graph客户端 credential = ClientSecretCredential( tenant_id=os.getenv("TENANT_ID"), client_id=os.getenv("CLIENT_ID"), client_secret=os.getenv("CLIENT_SECRET") ) client = GraphClient(credential=credential) TARGET_SUBJECT = os.getenv("TARGET_SUBJECT") FORWARD_TO = os.getenv("FORWARD_TO") def track_and_forward_emails(): """轮询收件箱,匹配主题后自动转发""" # 过滤条件:匹配目标主题+未读邮件,可根据需求调整 query = f"$filter=subject eq '{TARGET_SUBJECT}' and isRead eq false" while True: try: # 获取符合条件的邮件列表 response = client.get(f"/me/messages?{query}") response.raise_for_status() emails = response.json().get("value", []) for email in emails: email_id = email["id"] print(f"找到匹配主题的邮件,ID: {email_id}") # 拉取邮件完整详情(正文、附件等) email_details = client.get(f"/me/messages/{email_id}?$select=subject,body,attachments") email_details.raise_for_status() email_data = email_details.json() # 构造转发请求 forward_payload = { "comment": "自动转发:匹配目标主题的邮件", "toRecipients": [{"emailAddress": {"address": FORWARD_TO}}] } client.post(f"/me/messages/{email_id}/forward", json=forward_payload) # 标记为已读,避免重复处理 client.patch(f"/me/messages/{email_id}", json={"isRead": True}) print(f"邮件已转发给 {FORWARD_TO}") except Exception as e: print(f"处理邮件时出错: {str(e)}") # 每隔30秒轮询一次,可根据需求调整间隔 time.sleep(30) if __name__ == "__main__": print("启动Microsoft Graph邮件跟踪服务...") track_and_forward_emails()
注意事项
- 如果是服务级应用(不需要用户登录),要把
/me换成/users/{目标用户ID},确保权限配置正确 - 追求实时性的话,可以用Graph API的订阅功能替代轮询,实现新邮件实时通知,但配置复杂度会高一些
方案2:本地Outlook邮件跟踪服务(Windows专属)
这个方案依赖Windows本地安装的Outlook客户端,适合不需要联网访问Graph API的场景,直接通过COM接口操作本地Outlook。
前期准备
- 确保Windows上已安装Outlook,并且登录了目标邮箱账号
- 安装依赖包:
pip install pywin32
完整代码实现
import win32com.client import pythoncom import time # 自定义配置参数 TARGET_SUBJECT = "你的目标邮件主题" FORWARD_TO = "要转发的收件人邮箱" class OutlookMailTracker: def __init__(self): self.outlook = win32com.client.Dispatch("Outlook.Application") self.namespace = self.outlook.GetNamespace("MAPI") self.inbox = self.namespace.GetDefaultFolder(6) # 6代表Outlook收件箱 self.processed_ids = set() # 记录已处理邮件ID,避免重复转发 def track_new_emails(self): """监听新邮件事件,实时处理匹配的邮件""" # 注册NewMailEx事件,有新邮件时触发回调 self.outlook.NewMailEx += self.on_new_mail print("启动本地Outlook邮件跟踪服务...") print("等待新邮件(按Ctrl+C停止服务)") # 保持程序运行,处理Windows消息循环 while True: pythoncom.PumpWaitingMessages() time.sleep(1) def on_new_mail(self, entry_id_collection): """新邮件触发的回调函数""" # entry_id_collection可能包含多个邮件ID,用逗号分隔 for entry_id in entry_id_collection.split(","): if entry_id in self.processed_ids: continue try: mail = self.namespace.GetItemFromID(entry_id) # 模糊匹配主题(忽略大小写),可改成精确匹配 if TARGET_SUBJECT.lower() in mail.Subject.lower(): print(f"找到匹配主题的邮件:{mail.Subject}") # 读取邮件内容 plain_body = mail.Body # 纯文本正文,要HTML内容用mail.HTMLBody attachments = [att.FileName for att in mail.Attachments] if mail.Attachments.Count > 0 else [] print(f"邮件正文预览:{plain_body[:200]}...") if attachments: print(f"附件列表:{', '.join(attachments)}") # 转发邮件(自动携带原附件) forward_mail = mail.Forward() forward_mail.To = FORWARD_TO forward_mail.Subject = f"自动转发:{mail.Subject}" forward_mail.Body = f"以下是匹配主题的自动转发邮件\n\n原邮件内容:\n{plain_body}" forward_mail.Send() print(f"邮件已转发给 {FORWARD_TO}") self.processed_ids.add(entry_id) except Exception as e: print(f"处理邮件时出错: {str(e)}") if __name__ == "__main__": try: tracker = OutlookMailTracker() tracker.track_new_emails() except KeyboardInterrupt: print("\n服务已停止")
注意事项
- 第一次运行时,Outlook会弹出权限提示,需要点击“允许”程序访问邮件
- 如果需要处理历史邮件(不是新收到的),可以遍历
self.inbox.Items,循环检查每封邮件的主题 - 其他文件夹的ID可以参考Outlook COM文档,比如已发送邮件是
5,草稿箱是3
内容的提问来源于stack exchange,提问作者Ben Kennadi
相关产品推荐
相关产品推荐

