Microsoft Graph API 使用企业应用程序的访问令牌发送电子邮件

Microsoft Graph API send email using Access Token of Enterprise Application

我正在编写 python 代码以使用 Microsoft Graph API 从 Outlook 发送电子邮件。为此,我在我的 Azure Active Directory 租户中创建了一个企业应用程序。我已就 Mail.Send 权限向租户授予管理员许可。借助此应用程序,我能够获得 Graph API 的访问令牌,但我无法发送邮件。任何人都可以帮助我理解我的代码有什么问题吗?

Python代码:

from requests import post


CLIENT_SECRET_VALUE = 'CLIENT_SECRET_VALUE'
TENANT_ID = 'TENANT_ID'
CLIENT_ID = 'CLIENT_ID'

LOGIN_URI = f'https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token'

headers = {
    'Host': 'login.microsoftonline.com',
    'Content-Type': 'application/x-www-form-urlencoded'
}


body = {
    'client_id': CLIENT_ID,
    'scope': 'https://graph.microsoft.com/.default',
    'client_secret': CLIENT_SECRET_VALUE,
    'grant_type': 'client_credentials',
    'tenant': TENANT_ID
}


response = post(url=LOGIN_URI, headers=headers, data=body)
response.raise_for_status()
response_body = response.json()

authorization_token = f"{response_body['token_type']} {response_body['access_token']}"

print(authorization_token)

email_header = {
    'Authorization': authorization_token,
    'Content-Type': 'application/json'
}

message = {
    'body': {
        'content': 'Outlook Mail Testing Demo',
        'contentType': 'Text'
    },
    'sender': {
        'emailAddress': {
            'address': 'email.address.of.shared.mailbox@active-directory-tenant.tld',
            'name': 'Name of Shared Mailbox'
        }
    },
    'subject': 'Testing email',
    'toRecipients': [
        {
            'emailAddress': {
                'address': 'temprorary.email.address@another-domain.tld',
                'name': 'Name of person to whom email belongs'
            }
        }
    ]
}

email_body = {
    'message': message
}


email_send_response = post(url='https://graph.microsoft.com/v1.0/users/me/sendMail', headers=email_header, data=email_body)
email_send_response.raise_for_status()

[N.B.: CLIENT_SECRET_VALUE 由企业应用程序生成。 TENANT_ID & CLIENT_ID 是分配给应用程序的租户和客户端 ID]

在 运行 代码上,我收到一个错误:

400 Client Error: Bad Request for url: https://graph.microsoft.com/v1.0/users/me/sendMail

您的代码中有两个问题。正如我在评论中指定的第一个问题,URL 应该如下所示,因为您正在使用客户端凭证流。

https://graph.microsoft.com/v1.0/users/{userid/UPN}/sendMail

我在 python 的长期研究后发现的第二个问题是,您使用 API 调用发送的正文不是 json 的格式。所以我使用了 import json 和方法 json.dumps 并进行了测试。然后就成功了。

代码:

from requests import post
import json

CLIENT_SECRET_VALUE = 'aX27Q~insds3EvI4z8otRNGHRcCgdjeFOTSpCLPZ'
TENANT_ID = '363147dc-b3be-41a7-af56-f67894ef5a7'
CLIENT_ID = 'e61195e5-7955-4558-9126-37f6cf372d45'

LOGIN_URI = f'https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token'

headers = {
    'Host': 'login.microsoftonline.com',
    'Content-Type': 'application/x-www-form-urlencoded'
}


body = {
    'client_id': CLIENT_ID,
    'scope': 'https://graph.microsoft.com/.default',
    'client_secret': CLIENT_SECRET_VALUE,
    'grant_type': 'client_credentials',
    'tenant': TENANT_ID
}


response = post(url=LOGIN_URI, headers=headers, data=body)
response.raise_for_status()
response_body = response.json()

authorization_token = f"{response_body['token_type']} {response_body['access_token']}"

print(authorization_token)

email_header = {
    'Authorization': authorization_token,
    'Content-Type': 'application/json'
}

message = {
    'body': {
        'content': 'Outlook Mail Testing Demo',
        'contentType': 'Text'
    },
    'sender': {
        'emailAddress': {
            'address': 'email.address.of.shared.mailbox@active-directory-tenant.tld',
            'name': 'Name of Shared Mailbox'
        }
    },
    'subject': 'Testing email',
    'toRecipients': [
        {
            'emailAddress': {
                'address': 'temprorary.email.address@another-domain.tld',
                'name': 'Name of person to whom email belongs'
            }
        }
    ]
}

email_body = {
    'message': message
}

email_send_response = post(url='https://graph.microsoft.com/v1.0/users/1ab4e76f-5f52-44b8-8a72-7d03c05e6ff4/sendMail', headers=email_header, data=json.dumps(email_body))
print(email_send_response)

输出: