主动邮件

重要

本部分中的代码示例基于 Bot Framework SDK 版本 4.6 和更高版本。 如果要查找早期版本的文档,请参阅文档的旧版 SDK 文件夹中的 机器人 - v3 SDK 部分。

主动消息是由机器人发送的、不响应用户请求的任何消息。 此消息可以包含内容,例如:

  • 欢迎消息
  • Notifications
  • 计划的消息

重要

若要向用户、群组聊天或团队发送主动消息,机器人必须具有发送消息所需的访问权限。 对于群聊或团队,必须先将包含机器人的应用安装在该位置。

如有必要,可以使用团队中的 Microsoft Graph 主动安装应用 ,或者使用 自定义应用策略 在团队中为组织用户安装应用。 对于某些方案,你必须使用 Graph 主动安装应用。 若要让用户接收主动消息,请为用户安装应用,或让用户成为安装应用的团队的一员。

发送主动消息与发送常规消息不同。 没有用于回复的活动 turnContext。 在发送消息之前,你必须先创建对话。 例如,新的一对一聊天或频道中的新对话线程。 你不能在具有主动消息传递的团队中创建新的群聊或新频道。

若要发送主动邮件,请按照以下步骤操作:

  1. 如有必要,获取Microsoft Entra用户 ID、用户 ID、团队 ID 或频道 ID
  2. 创建对话(如果必要)。
  3. 获取对话 ID
  4. 发送消息.

示例部分中的代码片段用于创建一对一对话。 有关一对一对话和组或频道消息的示例链接,请参阅 代码示例。 若要有效地使用主动消息,请参阅 主动消息传送的最佳做法

获取Microsoft Entra用户 ID、用户 ID、团队 ID 或频道 ID

可以在频道中与用户或会话线程创建新会话,并且必须具有正确的 ID。 可以使用以下任一方式接收或检索此 ID:

  • 当你的应用安装在特定的上下文中时,你会收到一个 onMembersAdded 活动
  • 将新用户添加到安装应用的上下文时,你会收到一个 onMembersAdded 活动
  • 机器人接收的每个事件都包含所需的信息,可以从机器人上下文 (TurnContext 对象) 获取这些信息。
  • 你可以在已安装应用的团队中检索频道列表
  • 你可以检索已安装应用的团队的成员列表

无论如何获取信息,都存储 tenantId ,然后存储 userIdchannelId 以创建新对话。 你还可以使用 teamId 在团队的常规频道或默认频道中创建新的对话线程。 在向频道发送主动消息之前,请确保在团队中安装了机器人。

  • aadObjectId对于用户是唯一的,可以使用图形 API 检索,以在个人聊天中创建新对话。 在发送主动消息之前,请确保机器人已安装在个人范围内。 如果在使用 aadObjectId发送主动消息时未将机器人安装在个人范围内,机器人将返回错误消息403ForbiddenOperationException

  • userId 对于机器人 ID 和特定用户是唯一的。 你不能在机器人之间重复使用 userId

  • channelId 是全局 ID。

在拥有用户或频道信息后创建对话。

注意

仅在个人范围内支持使用 aadObjectId 发送主动消息。

创建对话

如果会话不存在,或者你不知道,则可以创建该 conversationId会话。 仅创建一次对话并存储 conversationId 值或 conversationReference 对象。

若要 创建对话,需要 或 aadObjectIduserIdtenantIdserviceUrl

对于 serviceUrl,请使用来自触发流或其中一个全局服务 URL 的传入活动的值。 serviceUrl如果从触发主动方案的传入活动中不可用,请使用以下全局 URL 终结点:

  • 公共: https://smba.trafficmanager.net/teams/
  • GCC: https://smba.infra.gcc.teams.microsoft.com/teams
  • GCCH: https://smba.infra.gov.teams.microsoft.us/teams
  • 国防部: https://smba.infra.dod.teams.microsoft.us/teams

有关代码示例,请参阅示例中的调用CreateConversationAsync

首次安装应用时,可以获取对话。 创建对话后, 获取对话 ID。 会话更新事件中提供了 conversationId

会话 ID 对于特定通道中的每个机器人都是唯一的,即使在多租户环境中也是如此。 此 ID 可确保机器人的消息定向到相应的通道,并且不会与相同或不同组织中的其他机器人或通道中断。

如果没有 , conversationId则可以 使用 Graph 主动安装应用 以获取 conversationId

获取对话 ID

使用 conversationReference 对象或 conversationIdtenantId 发送消息。 你可以通过以下方式获取此 ID,即通过从该上下文发送给你的任何活动创建对话或存储对话。 存储此 ID 以供参考。

获取相应的地址信息后,你可以发送消息。

发送邮件

现在,你已拥有正确的地址信息,因此可以发送消息。 如果你使用的是 SDK,则必须使用 continueConversation 方法以及 conversationIdtenantId 进行直接 API 调用。 若要发送消息,请 conversationParameters设置 。 请参阅示例部分,或使用代码示例部分中列出的其中一个示例。

注意

Teams 不支持使用电子邮件或用户主体名称 (UPN) 发送主动消息。

现在,你已发送主动消息,你必须在发送主动消息时遵循这些最佳做法,以便更好地在用户和机器人之间交换信息。

请参阅以下视频,以了解如何从机器人发送主动消息:



了解谁阻止、静音或卸载了机器人

开发人员可以创建一个报表,以了解组织中哪些用户已阻止、静音或卸载机器人。 此信息可帮助组织的管理员广播组织范围的消息或推动应用使用情况。

使用 Teams,可以向机器人发送主动消息,以验证用户是否已阻止或卸载机器人。 如果阻止或卸载机器人,Teams 将返回响应 403 代码和 subCode: MessageWritesBlocked。 此响应指示机器人发送的消息未传递给用户。

响应代码按用户发送,并包含用户的标识。 可以编译每个用户的响应代码及其标识,以创建已阻止机器人的所有用户的报告。

下面是 403 响应代码的示例。


HTTP/1.1 403 Forbidden

Cache-Control: no-store, must-revalidate, no-cache

 Pragma: no-cache

 Content-Length: 196

 Content-Type: application/json; charset=utf-8

 Server: Microsoft-HTTPAPI/2.0

 Strict-Transport-Security: max-age=31536000; includeSubDomains

 MS-CV: NXZpLk030UGsuHjPdwyhLw.5.0

 ContextId: tcid=0,server=msgapi-canary-eus2-0,cv=NXZpLk030UGsuHjPdwyhLw.5.0

 Date: Tue, 29 Mar 2022 17:34:33 GMT

{"errorCode":209,"message":"{\r\n  \"subCode\": \"MessageWritesBlocked\",\r\n  \"details\": \"Thread is blocked from message writes.\",\r\n  \"errorCode\": null,\r\n  \"errorSubCode\": null\r\n}"}

主动消息传递的最佳做法

向用户发送主动消息是一种与用户沟通的有效方式。 但是,从用户的角度来看,该消息似乎是未经提示的。 如果有欢迎消息,则表示他们首次与应用交互。 使用此功能并向用户提供完整信息以了解该消息的用途非常重要。

欢迎消息

使用主动消息传送向用户发送欢迎消息时,用户接收消息的原因没有上下文。 此外,这是用户与应用的第一次交互。 这是创造良好第一印象的好机会。 良好的用户体验可确保更好地采用应用。 糟糕的欢迎消息可能会导致用户阻止你的应用。 编写明确的欢迎消息,并在欢迎消息没有达到预期效果时循环访问该消息。

一条好的欢迎消息可以包括以下内容:

  • 消息的原因 - 用户必须清楚他们接收消息的原因。 如果你的机器人序安装在频道中,并且向所有用户发送了欢迎消息,那么请让他们知道它安装在哪个频道中以及谁安装了它。

  • 你的产品/服务 - 用户必须能够确定他们可以对你的应用执行哪些操作,以及你可以给他们带来什么价值。

  • 后续步骤 - 用户应了解后续步骤。 例如,邀请用户试用命令或与应用交互。

通知消息

若要使用主动消息传递发送通知,请确保用户具有清晰的路径来根据你的通知执行常见操作。 如果在选项卡应用中需要用户操作,请使用活动源通知而不是机器人。 确保用户清楚地了解他们收到通知的原因。 良好的通知消息包括以下项:

  • 发生了什么? 明确指出发生了什么情况才导致发送通知。

  • 结果是什么? 必须明确指出哪些项目更新导致发送通知。

  • 谁或什么触发了它? 谁或什么采取了导致发送通知的操作。

  • 用户可以在响应中执行哪些操作? 让用户能够轻松地根据通知执行操作。

  • 用户如何选择退出? 必须为用户提供一个路径,以便用户选择退出更多通知。

若向大量用户发送消息,例如向你的组织发送消息,请使用 Graph 主动安装你的应用。

若要更新或删除仅通知机器人发送的主动消息,请执行以下操作:

  1. 发送主动消息时,通过存储其消息 ID 或对话引用来跟踪发送的消息。

  2. 使用 UpdateActivityAsyncDeleteActivityAsync 方法更新或删除原始消息。

计划的消息

使用主动消息传递向用户发送计划的消息时,请验证你的时区是否已更新为其所在的时区。 这可确保在相关时间将消息传递给用户。 计划消息包括:

  • 为什么用户接收到了消息? 让用户轻松了解他们收到消息的原因。

  • 用户接下来可以做什么? 用户可以根据消息内容执行所需的操作。

使用 Graph 主动安装应用

主动向以前未安装或未与应用交互的用户发送消息。 例如,你希望使用公司通信器向整个组织发送消息。 在这种情况下,可以使用 Graph API 主动为用户安装应用。 缓存应用在安装时收到的 conversationUpdate 事件中的必要值。

只能安装组织应用目录或Microsoft Teams 应用商店中的应用。

请参阅 Graph 文档中的为用户安装应用以及使用 Graph 在 Teams 中进行主动型机器人安装和消息传递。 此外,GitHub 平台上还提供了 Microsoft .NET Framework 示例

示例

在使用 REST API 创建新会话之前,请确保你进行身份验证并具有 持有者令牌 。 下面是用于在不同上下文中创建会话的 REST API:

  • REST API,用于在一对一聊天中创建对话

  • 用于在频道中创建对话的 REST API

  • 用于更新会话中的消息的 REST API:若要更新会话中的现有活动,请在请求终结点中包含 conversationId 和 activityId。 若要完成此方案,必须缓存原始 post 调用返回的活动 ID。

    PUT {Service URL of your bot}/v3/conversations/{conversationId}/activities/{activityId}
    
    
    {
        "type": "message",
        "text": "This message has been updated"
    }
    

    若要更新对话中的现有活动,请在请求端点中包含 conversationIdactivityId。 若要完成此方案,必须缓存 activity ID 原始 post 调用返回的 。 如果调用成功,API 将返回以下响应对象。

    {
        "id": "{{activityID}}"
    }
    

示例

以下代码显示如何发送主动消息:

[Route("api/notify")]
[ApiController]
public class NotifyController : ControllerBase
{
    private readonly IBotFrameworkHttpAdapter _adapter;
    private readonly string _appId;
    private readonly ConcurrentDictionary<string, ConversationReference> _conversationReferences;

    public NotifyController(IBotFrameworkHttpAdapter adapter, IConfiguration configuration, ConcurrentDictionary<string, ConversationReference> conversationReferences)
    {
        _adapter = adapter;
        _conversationReferences = conversationReferences;
        _appId = configuration["MicrosoftAppId"] ?? string.Empty;
    }

    public async Task<IActionResult> Get()
    {
        foreach (var conversationReference in _conversationReferences.Values)
        {
            var newReference = new ConversationReference()
            {
                Bot = new ChannelAccount()
                {
                    Id = conversationReference.Bot.Id
                },
                Conversation = new ConversationAccount()
                {
                    Id = conversationReference.Conversation.Id
                },
                ServiceUrl = conversationReference.ServiceUrl,
            };

            // Sends a proactive message from the bot to a conversation.
            await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, newReference, BotCallback, default(CancellationToken));
        }
        
        // Let the caller know proactive messages have been sent.
        return new ContentResult()
        {
            Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
            ContentType = "text/html",
            StatusCode = (int)HttpStatusCode.OK,
        };
    }

    private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
    {
        // If you encounter permission-related errors when sending this message, see
        // https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-howto-proactive-message?view=azure-bot-service-4.0&tabs=csharp#avoiding-401-unauthorized-errors
        // Sends an activity to the sender of the incoming activity.
        await turnContext.SendActivityAsync("proactive hello");
    }
}

演示如何创建对话引用的代码片段示例。

 var newReference = new ConversationReference()
        {
            Bot = new ChannelAccount()
            {
                Id = conversationReference.Bot.Id
            },
            Conversation = new ConversationAccount()
            {
                Id = conversationReference.Conversation.Id
            },
            ServiceUrl = conversationReference.ServiceUrl,
        };

代码示例

下表提供了一个用于将基本对话流合并到 Teams 应用程序中的简单代码示例,并介绍了如何在 Teams 的频道中创建新的对话线程:

示例名称 说明 .NET Node.js Python 清单
Teams 对话基础知识 此示例应用演示如何将机器人框架 v4 中提供的不同机器人聊天事件用于个人和团队范围。 View View View View
在频道中启动新线程 此示例演示如何使用 Bot Framework v4 在特定团队通道中启动线程。 View View View View
主动安装应用并发送主动通知 此示例演示如何通过调用 Microsoft Graph API 为用户使用主动安装应用并发送主动通知。 View View 不适用 View
主动消息传送 此示例演示如何保存用户的聊天引用信息,以使用机器人发送主动提醒消息。 View View 不适用

后续步骤

另请参阅