今天我一整天都在用 python 处理 OAuth 和 MSAL 的东西。我有一个简单的应用程序,用户填写我的表单,单击提交,然后我将他们的内容写入数据库。我想向他们发送一封电子邮件,内容是“我已将您的内容写入数据库”,我希望该电子邮件来自我的系统帐户,即 AZAD 帐户。
我觉得我应该能够以某种方式获得一个令牌,仅使用名称、密码即可与图形 API 进行交互,然后发送电子邮件。然而我总是碰壁。
我无法为我的应用程序获取管理员内容,以便以任何用户身份发送电子邮件。我想做的就是从我的系统帐户发送一封电子邮件。我可以在桌面上的 Outlook 应用程序中手动执行此操作,但无法从 python IDE 执行此操作。
如果可能的话,我想使用 HTTP 请求来完成此操作
import requests_oauthlib
from requests_oauthlib import OAuth2Session
from oauthlib.oauth2 import LegacyApplicationClient
tenant_id = tid
client_id = cid
client_secret = cs
uri =f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token"
username=un
password=pw
#DOES NOT WORK says the user account doesn't exist
oauth = OAuth2Session(client=LegacyApplicationClient(client_id=client_id))
token = oauth.fetch_token(
token_url=uri
,client_id=client_id
,client_secret=client_secret
,username=username
,password=password
,scope="Mail.Send"
)
#THIS DOES WORK BUT I CANT GET IT TO EMAIL
client = BackendApplicationClient(client_id=client_id)
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(
token_url=uri
,client_id=client_id
,client_secret=client_secret
,scope=["https://graph.microsoft.com/.default"]
)
recipient='[email protected]'
subject="test_subject"
body="test_body"
request_body = {
'message': {
# recipient list
'toRecipients': [
{
'emailAddress': {
'address': recipient
}
}
],
# email subject
'subject': subject,
"body": {
"contentType": "html",
"content": body
},
'importance': 'normal',
}
}
headers = {
'Authorization': 'Bearer ' + token['access_token']
}
GRAPH_ENDPOINT = 'https://graph.microsoft.com/v1.0'
endpoint = GRAPH_ENDPOINT + '/me/sendMail'
response = requests.post(endpoint, headers=headers, json=request_body)
response.raise_for_status() # Raise an exception if request fails
if response.status_code == 202:
print(f"Email sent to: {recipient}")
else:
print(f"Email not sent to: {recipient}")
或者,您可以利用
msal
库使用用户名和密码生成访问令牌。
最初,我注册了一个应用程序并授予了
Mail.Send
经管理员同意的委派权限,仅允许登录用户发送邮件:
使用用户名密码流程时,请确保启用公共客户端流程选项以避免使用客户端机密:
现在,我运行下面的示例 python 代码来创建带有用户名密码的访问令牌,并得到如下响应:
#pip install msal
import msal
import requests
tenant_id = 'tenantId'
client_id = 'appId'
username = '[email protected]' # System account username (email)
password = 'xxxxxxx'
authority = f"https://login.microsoftonline.com/{tenant_id}"
scope = ["https://graph.microsoft.com/Mail.Send", "https://graph.microsoft.com/User.Read"]
app = msal.PublicClientApplication(client_id, authority=authority)
result = app.acquire_token_by_username_password(
username=username,
password=password,
scopes=scope
)
if "access_token" in result:
access_token = result['access_token']
print("Token acquired successfully")
# Prepare the email
recipient = '[email protected]'
subject = "Acknowledgement"
body = "I wrote your stuff to the database"
request_body = {
'message': {
'toRecipients': [
{'emailAddress': {'address': recipient}}
],
'subject': subject,
"body": {"contentType": "html", "content": body},
'importance': 'normal',
}
}
headers = {
'Authorization': 'Bearer ' + access_token,
'Content-Type': 'application/json'
}
# Send email on behalf of the user (using '/me/sendMail' since this is a delegated flow)
GRAPH_ENDPOINT = 'https://graph.microsoft.com/v1.0'
endpoint = f"{GRAPH_ENDPOINT}/me/sendMail"
# Send the email
response = requests.post(endpoint, headers=headers, json=request_body)
# Check for success
if response.status_code == 202:
print(f"Email sent to: {recipient}")
else:
print(f"Failed to send email: {response.status_code}, {response.text}")
else:
print("Failed to acquire token:", result.get("error"), result.get("error_description"))
回复:
为了确认这一点,我在邮件发送成功的用户的
Sent Items
中检查了相同的内容,如下所示: