简体   繁体   English

认证 Azure Email Python 中使用服务主体的通信服务

[英]Authenticate Azure Email Communication Services using Service Principals in Python

I am attempting to create an API in my Azure Static Web App which sends an email when a form submission occurs in my app.我正在尝试在我的 Azure Static Web 应用程序中创建一个 API,当我的应用程序中发生表单提交时,它会发送一个 email。

I was able to get this working by passing a connection string to the EmailClient, but I would prefer to authenticate my EmailClient using Azure's Service Principals as recommended in the email quickstart and briefly explained in the SMS quickstart .我能够通过将连接字符串传递给 EmailClient 来实现此功能,但我更愿意按照 email 快速入门中的建议并在SMS 快速入门中简要说明,使用 Azure 的服务主体对我的EmailClient进行身份验证。

I have tried passing an DefaultAzureCredential() as in the SMS quickstart我试过像 SMS 快速入门中那样传递 DefaultAzureCredential()

email_client = EmailClient(endpoint=endpoint, credential=DefaultAzureCredential())

But I get an error saying expected bytes or ASCII in the credential parameter.但是我收到一条错误消息,指出凭证参数中的expected bytes or ASCII

I then attempted to generate a token from the credential using the Client ID of the Email Communication Services object, so I could pass this as the credential per the identity docs , but I get an error saying that the scope has not been provided:然后,我尝试使用 Email 通信服务 object 的客户端 ID 从凭据生成令牌,因此我可以根据身份文档将其作为凭据传递,但我收到一条错误消息,指出尚未提供 scope:

credential=DefaultAzureCredential()
token=credential.get_token(scopes="bbjkl-xyz-abc/.default").token
email_client = EmailClient(endpoint=endpoint, credential=token)

DefaultAzureCredential failed to retrieve a token from the included credentials. 
Attempted credentials:
    EnvironmentCredential: "get_token" requires at least one scope

How do I authenticate the EmailClient using service principals?如何使用服务主体对 EmailClient 进行身份验证? Or is this - as I suspect - a bug?或者这是 - 正如我怀疑的那样 - 一个错误?

I tried in my environment and got below results:我在我的环境中尝试并得到以下结果:

Initially, I tried the EmailClient with Defaultcredentials and got same error:最初,我尝试使用 Defaultcredentials 的 EmailClient 并得到同样的错误:

在此处输入图像描述

TypeError: argument should be a bytes-like object or ASCII string, not 'DefaultAzureCredential' TypeError:参数应该是类似字节的 object 或 ASCII 字符串,而不是“DefaultAzureCredential”

As a workaround for authentication to send an email using EmailClient I tried to use Azurekeycredential method to send an email to the recipient.作为使用EmailClient发送 email 的身份验证解决方法,我尝试使用Azurekeycredential方法向收件人发送 email。

Code:代码:

from azure.communication.email import EmailClient,EmailAddress,EmailContent,EmailRecipients,EmailMessage
from azure.core.credentials import AzureKeyCredential

end="< your communication endpoint >"
cred=AzureKeyCredential(key="< key of azure communication service >")
email=EmailClient(endpoint=end,credential=cred)
content = EmailContent(
    subject="Welcome to Azure Communication Services Email",
    plain_text="This email message is sent from Azure Communication Services Email using the Python SDK.",
)

address = EmailAddress(email="demomail.com")
recipient = EmailRecipients(to=[address])

message = EmailMessage(
            sender="DoNotReply@xxxxxxxxxx.azurecomm.net",
            content=content,
            recipients=recipient
        )

response = email.send(message)

Console:安慰:

在此处输入图像描述

Mail: The above code executed successfully by send mail to recipient with Azurekeycredential method.邮件:上面的代码通过使用Azurekeycredential方法向收件人发送邮件成功执行。

在此处输入图像描述

Reference:参考:

Azure.communication.email.EmailClient class | Azure.communication.email.EmailClient class | Microsoft Learn 微软学习

This is still in preview, so it's not well documented.这仍处于预览阶段,因此没有很好的记录。 I can't answer how to use the provided library, but here's an example using the REST API with service principal authentication.我无法回答如何使用提供的库,但这里有一个使用 REST API 和服务主体身份验证的示例。

Note your principal needs the Contributor role on the Azure Communication Service as well请注意,您的委托人还需要Azure 通信服务贡献者角色

import msal
import requests
import uuid
from wsgiref.handlers import format_date_time
from datetime import datetime
from time import mktime

def get_token_with_client_secret(client_id, client_secret, tenant_id):
    app = msal.ConfidentialClientApplication(
        client_id         = client_id,
        client_credential = client_secret,
        authority         = f"https://login.microsoftonline.com/{tenant_id}")

    scopes = ["https://communication.azure.com/.default"]

    token = app.acquire_token_for_client(scopes = scopes)

    return(token)

def main():
    tenant_id = ""
    client_id = ""
    client_secret = ""
    endpoint = "https://endpoint.communication.azure.com/"
    sender = "DoNotReply@guid.azurecomm.net"
    
    # Obtain a token using the application credentials
    cred = get_token_with_client_secret(client_id, client_secret, tenant_id)
    
    # Generate timestamp to use in the repeatability-first-sent header    
    now = datetime.now()
    stamp = mktime(now.timetuple())
    time = format_date_time(stamp)

    request_url = f"{endpoint}emails:send?api-version=2021-10-01-preview"

    request_headers = {
        "Authorization": "Bearer " + cred["access_token"],
        "Content-Type": "application/json",
        "repeatability-request-id": str(uuid.uuid4()),
        "repeatability-first-sent": time
    }

    request_body = {
        "Sender": sender,
        "Content": {
            "Subject": "Email Subject",
            "PlainText": "This is the email body"
        },
        "Importance": "Normal",
        "Recipients": {
            "To": [
                {
                    "Email": "user@company.com",
                    "DisplayName": "User"
                }
            ]
        }
    }

    response = requests.post(url = request_url, headers = request_headers, json = request_body)

main()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM