你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

发送 WhatsApp 模板消息

本文档提供使用高级通信消息 SDK 发送 WhatsApp 模板消息的指南。

为什么需要发送模板消息?

在用户向企业发送消息之前,企业只能发送模板消息。

企业或用户可启动对话窗口,但企业只能查看他们可发送的消息类型。 只有在用户向企业发送消息后,企业才能在活动对话期间向用户发送文本或媒体消息。 24 小时对话窗口到期后,必须重新发起对话。 若要了解有关对话的详细信息,请访问 WhatsApp Business 平台查看定义。

有关模板的更多 WhatsApp 要求,请查看 WhatsApp Business Platform API 参考:

选择模板

在嵌入式注册期间通过 Azure 门户创建 WhatsApp Business 帐户时,可能会自动提供一组示例模板供你试用。请访问示例,查看其中一些示例模板的用法。

创建模板

若要创建自己的模板,请使用 Meta WhatsApp 管理器。 请按照 Meta Business 帮助中心“为 WhatsApp Business 帐户创建消息模板”中的说明操作。

模板列表

可以通过转到 Azure 通信服务资源 > 模板来查看 Azure 门户中的模板。

Screenshot that shows an Azure Communication Services resource in the Azure portal, viewing the 'Templates' tab.

通过选择模板,可以查看模板的详细信息。
模板详细信息的 content 字段可以包括参数绑定。 参数绑定可以表示为:

  • 具有诸如 IMAGE 之类的值的“格式”字段。
  • 双括号括起数字,例如 {{1}}。 该数字从 1 开始索引,表示创建消息模板时必须提供绑定值的顺序。

Screenshot that shows template details.

或者,可以在“WhatsApp 管理器>帐户工具>消息模板”中查看和编辑所有 WhatsApp Business 帐户的模板。

若要以编程方式列出模板,可以获取频道 ID 的所有模板:

MessageTemplateClient messageTemplateClient = new MessageTemplateClient(connectionString);
Pageable<MessageTemplateItem> templates = messageTemplateClient.GetTemplates(channelRegistrationId);

快速参考

不带参数的模板

如果模板不带参数,则在创建 MessageTemplate 时无需提供值或绑定。

var messageTemplate = new MessageTemplate(templateName, templateLanguage); 

示例

正文中带有文本参数的模板

使用 MessageTemplateText 定义正文中用双括号括起的数字(例如 {{1}})表示的参数。 该数字从 1 开始索引,表示创建消息模板时必须提供绑定值的顺序。

模板定义正文:

{
  "type": "BODY",
  "text": "Message with two parameters: {{1}} and {{2}}"
},

消息模板程序集:

var param1 = new MessageTemplateText(name: "first", text: "First Parameter");
var param2 = new MessageTemplateText(name: "second", text: "Second Parameter");

WhatsAppMessageTemplateBindings bindings = new();
bindings.Body.Add(new(param1.Name));
bindings.Body.Add(new(param2.Name));

var messageTemplate = new MessageTemplate(templateName, templateLanguage);
messageTemplate.Bindings = bindings;
messageTemplate.Values.Add(param1);
messageTemplate.Values.Add(param2);

示例

标头中包含媒体的模板

使用 MessageTemplateImageMessageTemplateVideoMessageTemplateDocument 在标头中定义媒体参数。

需要图像媒体的模板定义标头:

{
  "type": "HEADER",
  "format": "IMAGE"
},

“format”可能需要不同的媒体类型。 在 .NET SDK 中,每个媒体类型都使用相应的 MessageTemplateValue 类型。

Format MessageTemplateValue 类型 文件类型
IMAGE MessageTemplateImage png、jpg
视频 MessageTemplateVideo mp4
DOCUMENT MessageTemplateDocument pdf

有关支持的媒体类型和大小限制的更多信息,请参阅 WhatsApp 的消息媒体文档

图像媒体消息的模板程序集:

var url = new Uri("< Your media URL >");

var media = new MessageTemplateImage("image", url);
WhatsAppMessageTemplateBindings bindings = new();
bindings.Header.Add(new(media.Name));

var messageTemplate = new MessageTemplate(templateName, templateLanguage);
template.Bindings = bindings;
template.Values.Add(media);

示例

包含快速回复按钮的模板

使用 MessageTemplateQuickAction 为快速答复按钮定义有效负载。

MessageTemplateQuickAction 对象,并且具有以下三个属性。
具体来说,对于快速回复按钮,请按照以下指南创建 MessageTemplateQuickAction 对象。

  • name
    name 用于查找 MessageTemplateWhatsAppBindings 中的值。
  • text
    不使用 text 属性。
  • payload
    如果用户选择按钮,则分配给按钮的 payload 可在消息回复中使用。

模板定义按钮:

{
  "type": "BUTTONS",
  "buttons": [
    {
      "type": "QUICK_REPLY",
      "text": "Yes"
    },
    {
      "type": "QUICK_REPLY",
      "text": "No"
    }
  ]
}

按钮在模板定义中出现的顺序应与使用 MessageTemplateWhatsAppBindings 创建绑定时定义按钮的顺序匹配。

消息模板程序集:

var yes = new MessageTemplateQuickAction(name: "Yes", payload: "User said yes");
var no = new MessageTemplateQuickAction(name: "No", payload: "User said no");

var yesButton = new WhatsAppMessageTemplateBindingsButton(WhatsAppMessageButtonSubType.QuickReply.ToString(), yes.Name);
var noButton = new WhatsAppMessageTemplateBindingsButton(WhatsAppMessageButtonSubType.QuickReply.ToString(), no.Name);

WhatsAppMessageTemplateBindings bindings = new();
bindings.Buttons.Add(yesButton);
bindings.Buttons.Add(noButton);

var messageTemplate = new MessageTemplate(templateName, templateLanguage);
messageTemplate.Bindings = bindings;
template.Values.Add(yes);
template.Values.Add(no);

有关用户快速回复响应中有效负载的详细信息,请参阅关于从快速回复按钮收到的回叫的 WhatsApp 文档。

示例

带有行动号召按钮的模板

使用 MessageTemplateQuickAction 定义行动号召按钮的 URL 后缀。

MessageTemplateQuickAction 对象,并且具有以下三个属性。
具体来说,对于行动号召按钮,请按照以下指南创建 MessageTemplateQuickAction 对象。

  • name
    name 用于查找 MessageTemplateWhatsAppBindings 中的值。
  • text
    text 属性定义追加到 URL 的文本。
  • payload
    不需要 payload 属性。

模板定义按钮:

{
  "type": "BUTTONS",
  "buttons": [
    {
      "type": "URL",
      "text": "Take Survey",
      "url": "https://www.example.com/{{1}}"
    }
  ]
}

按钮在模板定义中出现的顺序应与使用 MessageTemplateWhatsAppBindings 创建绑定时定义按钮的顺序匹配。

消息模板程序集:

var urlSuffix = new MessageTemplateQuickAction(name: "text", text: "url-suffix-text");

var urlButton = new WhatsAppMessageTemplateBindingsButton(WhatsAppMessageButtonSubType.Url.ToString(), urlSuffix.Name);

WhatsAppMessageTemplateBindings bindings = new();
bindings.Buttons.Add(urlButton);

var messageTemplate = new MessageTemplate(templateName, templateLanguage);
messageTemplate.Bindings = bindings;
messageTemplate.Values.Add(urlSuffix);

示例

示例

这些示例利用可用于通过 Azure 门户嵌入式注册创建的 WhatsApp Business 帐户的示例模板。

使用示例模板 sample_template

名为 sample_template 的示例模板不带任何参数。

Screenshot that shows template details for template named sample_template.

通过引用目标模板的名称和语言来组合 MessageTemplate

string templateName = "sample_template"; 
string templateLanguage = "en_us"; 

var sampleTemplate = new MessageTemplate(templateName, templateLanguage); 

使用示例模板 sample_shipping_confirmation

有些模板带有参数。 仅包含模板所需的参数。 包含模板中没有的参数是无效的。

Screenshot that shows template details for template named sample_shipping_confirmation.

在此示例中,模板的正文有一个参数:

{
  "type": "BODY",
  "text": "Your package has been shipped. It will be delivered in {{1}} business days."
},

参数使用 MessageTemplateValue 值和 MessageTemplateWhatsAppBindings 绑定定义。 使用值和绑定来组合 MessageTemplate

string templateName = "sample_shipping_confirmation"; 
string templateLanguage = "en_us"; 

var threeDays = new MessageTemplateText("threeDays", "3");

WhatsAppMessageTemplateBindings bindings = new();
bindings.Body.Add(new(threeDays.Name));

MessageTemplate shippingConfirmationTemplate  = new(templateName, templateLanguage);
shippingConfirmationTemplate.Bindings = bindings;
shippingConfirmationTemplate.Values.Add(threeDays);

使用示例模板 sample_movie_ticket_confirmation

模板可能需要各种类型的参数,例如文本和图像。

Screenshot that shows template details for template named sample_movie_ticket_confirmation.

在此示例中,模板的标头需要一个图像:

{
  "type": "HEADER",
  "format": "IMAGE"
},

模板正文需要四个文本参数:

{
  "type": "BODY",
  "text": "Your ticket for *{{1}}*\n*Time* - {{2}}\n*Venue* - {{3}}\n*Seats* - {{4}}"
},

创建一个 MessageTemplateImage 和四个 MessageTemplateText 变量。 然后,按照参数在模板内容中出现的顺序提供参数,组合 MessageTemplateValueMessageTemplateWhatsAppBindings 的列表。

string templateName = "sample_movie_ticket_confirmation"; 
string templateLanguage = "en_us"; 
var imageUrl = new Uri("https://aka.ms/acsicon1");

var image = new MessageTemplateImage("image", imageUrl);
var title = new MessageTemplateText("title", "Contoso");
var time = new MessageTemplateText("time", "July 1st, 2023 12:30PM");
var venue = new MessageTemplateText("venue", "Southridge Video");
var seats = new MessageTemplateText("seats", "Seat 1A");

WhatsAppMessageTemplateBindings bindings = new();
bindings.Header.Add(new(image.Name));
bindings.Body.Add(new(title.Name));
bindings.Body.Add(new(time.Name));
bindings.Body.Add(new(venue.Name));
bindings.Body.Add(new(seats.Name));

MessageTemplate movieTicketConfirmationTemplate = new(templateName, templateLanguage);
movieTicketConfirmationTemplate.Values.Add(image);
movieTicketConfirmationTemplate.Values.Add(title);
movieTicketConfirmationTemplate.Values.Add(time);
movieTicketConfirmationTemplate.Values.Add(venue);
movieTicketConfirmationTemplate.Values.Add(seats);
movieTicketConfirmationTemplate.Bindings = bindings;

使用示例模板 sample_happy_hour_announcement

此示例模板在标头中使用一个视频,在正文中使用两个文本参数。

Screenshot that shows template details for template named sample_happy_hour_announcement.

在这里,模板的标头需要一个视频:

{
  "type": "HEADER",
  "format": "VIDEO"
},

该视频应该是托管 mp4 视频的 URL。 有关支持的媒体类型和大小限制的更多信息,请参阅 WhatsApp 的消息媒体文档

模板正文需要两个文本参数:

{
  "type": "BODY",
  "text": "Happy hour is here! 🍺😀🍸\nPlease be merry and enjoy the day. 🎉\nVenue: {{1}}\nTime: {{2}}"
},

创建一个 MessageTemplateVideo 和两个 MessageTemplateText 变量。 然后,按照参数在模板内容中出现的顺序提供参数,组合 MessageTemplateValueMessageTemplateWhatsAppBindings 的列表。

string templateName = "sample_happy_hour_announcement";
string templateLanguage = "en_us";
var videoUrl = new Uri("< Your .mp4 Video URL >");

var video = new MessageTemplateVideo("video", videoUrl);
var venue = new MessageTemplateText("venue", "Fourth Coffee");
var time = new MessageTemplateText("time", "Today 2-4PM");
WhatsAppMessageTemplateBindings bindings = new();
bindings.Header.Add(new(video.Name));
bindings.Body.Add(new(venue.Name));
bindings.Body.Add(new(time.Name));

MessageTemplate happyHourAnnouncementTemplate = new(templateName, templateLanguage);
happyHourAnnouncementTemplate.Values.Add(venue);
happyHourAnnouncementTemplate.Values.Add(time);
happyHourAnnouncementTemplate.Values.Add(video);
happyHourAnnouncementTemplate.Bindings = bindings;

使用示例模板 sample_flight_confirmation

此示例模板在标头中使用一个文档,在正文中使用三个文本参数。

Screenshot that shows template details for template named sample_flight_confirmation.

在这里,模板的标头需要一个文档:

{
  "type": "HEADER",
  "format": "DOCUMENT"
},

文档应该是托管 pdf 文档的 URL。 有关支持的媒体类型和大小限制的更多信息,请参阅 WhatsApp 的消息媒体文档

模板正文需要三个文本参数:

{
  "type": "BODY",
  "text": "This is your flight confirmation for {{1}}-{{2}} on {{3}}."
},

创建一个 MessageTemplateDocument 和三个 MessageTemplateText 变量。 然后,按照参数在模板内容中出现的顺序提供参数,组合 MessageTemplateValueMessageTemplateWhatsAppBindings 的列表。

string templateName = "sample_flight_confirmation";
string templateLanguage = "en_us";
var documentUrl = new Uri("< Your .pdf document URL >");

var document = new MessageTemplateDocument("document", documentUrl);
var firstName = new MessageTemplateText("firstName", "Kat");
var lastName = new MessageTemplateText("lastName", "Larssen");
var date = new MessageTemplateText("date", "July 1st, 2023");

WhatsAppMessageTemplateBindings bindings = new();
bindings.Header.Add(new(document.Name));
bindings.Body.Add(new(firstName.Name));
bindings.Body.Add(new(lastName.Name));
bindings.Body.Add(new(date.Name));

MessageTemplate flightConfirmationTemplate = new(templateName, templateLanguage);
flightConfirmationTemplate.Values.Add(document);
flightConfirmationTemplate.Values.Add(firstName);
flightConfirmationTemplate.Values.Add(lastName);
flightConfirmationTemplate.Values.Add(date);
flightConfirmationTemplate.Bindings = bindings;

使用示例模板 sample_issue_resolution

此示例模板向消息添加两个预填充回复按钮。 它还在正文中包含一个文本参数。

Screenshot that shows template details for template named sample_issue_resolution.

在这里,模板正文需要一个文本参数:

{
  "type": "BODY",
  "text": "Hi {{1}}, were we able to solve the issue that you were facing?"
},

模板包含两个预填充的回复按钮,YesNo

{
  "type": "BUTTONS",
  "buttons": [
    {
      "type": "QUICK_REPLY",
      "text": "Yes"
    },
    {
      "type": "QUICK_REPLY",
      "text": "No"
    }
  ]
}

快速回复按钮定义为 MessageTemplateQuickAction 对象,并具有三个属性:

  • name
    name 用于查找 MessageTemplateWhatsAppBindings 中的值。
  • text
    使用快速回复按钮时,不使用 text 属性。
  • payload
    如果用户选择按钮,则分配给按钮的 payload 可在消息回复中使用。

有关按钮的详细信息,请参阅关于按钮参数对象的 WhatsApp 文档。

创建一个 MessageTemplateText 和两个 MessageTemplateQuickAction 变量。 然后,按照参数在模板内容中出现的顺序提供参数,组合 MessageTemplateValueMessageTemplateWhatsAppBindings 的列表。 在定义绑定按钮时,顺序也很重要。

string templateName = "sample_issue_resolution";
string templateLanguage = "en_us";

var name = new MessageTemplateText(name: "name", text: "Kat");
var yes = new MessageTemplateQuickAction(name: "Yes"){ Payload =  "Kat said yes" };
var no = new MessageTemplateQuickAction(name: "No") { Payload = "Kat said no" };

WhatsAppMessageTemplateBindings bindings = new();
bindings.Body.Add(new(name.Name));
bindings.Buttons.Add(new(WhatsAppMessageButtonSubType.QuickReply.ToString(), yes.Name));
bindings.Buttons.Add(new(WhatsAppMessageButtonSubType.QuickReply.ToString(), no.Name));

MessageTemplate issueResolutionTemplate = new(templateName, templateLanguage);
issueResolutionTemplate.Values.Add(name);
issueResolutionTemplate.Values.Add(yes);
issueResolutionTemplate.Values.Add(no);
issueResolutionTemplate.Bindings = bindings;

使用示例模板 sample_purchase_feedback

此示例模板向消息添加一个带有动态 URL 链接的按钮。 它还在标头中使用一个图像,在正文中使用一个文本参数。

如果使用预先创建的示例模板 sample_purchase_feedback,则需要将其按钮的 URL 类型从 Static 修改为 Dynamic
转到 WhatsApp 管理器中的消息模板并编辑 sample_purchase_feedback 的模板。 在 URL 类型下拉列表中,将其从 Static 更改为 Dynamic。 如有必要,请包含示例 URL。

Screenshot that shows editing URL Type in the WhatsApp manager.

现在,如果你在 Azure 门户中查看模板详细信息,则会看到:Screenshot that shows template details for template named sample_purchase_feedback.

在此示例中,模板的标头需要一个图像:

{
  "type": "HEADER",
  "format": "IMAGE"
},

在这里,模板正文需要一个文本参数:

{
  "type": "BODY",
  "text": "Thank you for purchasing {{1}}! We value your feedback and would like to learn more about your experience."
},

该模板包含一个带有一个参数的动态 URL 按钮:

{
  "type": "BUTTONS",
  "buttons": [
    {
      "type": "URL",
      "text": "Take Survey",
      "url": "https://www.example.com/{{1}}"
    }
  ]
}

网站链接的行动号召按钮定义为 MessageTemplateQuickAction 对象,并具有三个属性:

  • name
    name 用于查找 MessageTemplateWhatsAppBindings 中的值。
  • text
    使用网站链接的行动号召按钮,text 属性定义追加到 URL 的文本。
    对于本示例,我们的 text 值为 survey-code。 在用户收到的消息中,会显示一个将其链接到 URL https://www.example.com/survey-code 的按钮。
  • payload
    使用网站链接的行动号召按钮时,不需要 payload 属性。

有关按钮的详细信息,请参阅关于按钮参数对象的 WhatsApp 文档。

创建一个 MessageTemplateImage、一个 MessageTemplateText 和一个 MessageTemplateQuickAction 变量。 然后,按照参数在模板内容中出现的顺序提供参数,组合 MessageTemplateValueMessageTemplateWhatsAppBindings 的列表。 在定义绑定按钮时,顺序也很重要。

string templateName = "sample_purchase_feedback";
string templateLanguage = "en_us";
var imageUrl = new Uri("https://aka.ms/acsicon1");

var image = new MessageTemplateImage(name: "image", uri: imageUrl);
var product = new MessageTemplateText(name: "product", text: "coffee");
var urlSuffix = new MessageTemplateQuickAction(name: "text") { Text = "survey-code" };

WhatsAppMessageTemplateBindings bindings = new();
bindings.Header.Add(new(image.Name));
bindings.Body.Add(new(product.Name));
bindings.Buttons.Add(new(WhatsAppMessageButtonSubType.Url.ToString(), urlSuffix.Name));

MessageTemplate purchaseFeedbackTemplate = new("sample_purchase_feedback", "en_us");
purchaseFeedbackTemplate.Values.Add(image);
purchaseFeedbackTemplate.Values.Add(product);
purchaseFeedbackTemplate.Values.Add(urlSuffix);
purchaseFeedbackTemplate.Bindings = bindings;

完整代码示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Azure;
using Azure.Communication.Messages;
using Azure.Communication.Messages.Models.Channels;

namespace SendTemplateMessages
{
    class Program
    {
        public static async Task Main(string[] args)
        {
            Console.WriteLine("Azure Communication Services - Send WhatsApp Template Messages\n");

            string connectionString = Environment.GetEnvironmentVariable("COMMUNICATION_SERVICES_CONNECTION_STRING");

            NotificationMessagesClient notificationMessagesClient = new NotificationMessagesClient(connectionString);

            var channelRegistrationId = new Guid("<Your Channel ID>");
            var recipientList = new List<string> { "<Recipient's WhatsApp Phone Number>" };

            // List out available templates for a channel ID
            MessageTemplateClient messageTemplateClient = new MessageTemplateClient(connectionString);
            Pageable<MessageTemplateItem> templates = messageTemplateClient.GetTemplates(channelRegistrationId);
            foreach (WhatsAppMessageTemplateItem template in templates)
            {
                Console.WriteLine("Name: {0}\tLanguage: {1}\tStatus: {2}\tContent: {3}\n",
                    template.Name, template.Language, template.Status, template.Content);
            }

            // Send Sample Template sample_template
            MessageTemplate sampleTemplate = AssembleSampleTemplate();
            var sampleTemplateContent = new TemplateNotificationContent(channelRegistrationId, recipientList, sampleTemplate);
            var result = await notificationMessagesClient.SendAsync(sampleTemplateContent);
            PrintResponse(result);
           
            // Send sample template sample_shipping_confirmation
            MessageTemplate shippingConfirmationTemplate = AssembleSampleShippingConfirmation();
            var shippingConfirmationTemplateContent = new TemplateNotificationContent(channelRegistrationId, recipientList, shippingConfirmationTemplate);
            result = await notificationMessagesClient.SendAsync(shippingConfirmationTemplateContent);
            PrintResponse(result);

            // Send sample template sample_movie_ticket_confirmation
            MessageTemplate movieTicketConfirmationTemplate = AssembleSampleMovieTicketConfirmation();
            var movieTicketConfirmationTemplateContent = new TemplateNotificationContent(channelRegistrationId, recipientList, movieTicketConfirmationTemplate);
            result = await notificationMessagesClient.SendAsync(movieTicketConfirmationTemplateContent);
            PrintResponse(result);

            // Send sample template sample_happy_hour_announcement
            MessageTemplate happyHourTemplate = AssembleSampleHappyHourAnnouncement();
            var happyHourTemplateContent = new TemplateNotificationContent(channelRegistrationId, recipientList, happyHourTemplate);
            result = await notificationMessagesClient.SendAsync(happyHourTemplateContent);
            PrintResponse(result);

            // Send sample template sample_flight_confirmation
            MessageTemplate flightConfirmationTemplate = AssembleSampleFlightConfirmation();
            var flightConfirmationTemplateContent = new TemplateNotificationContent(channelRegistrationId, recipientList, flightConfirmationTemplate);
            result = await notificationMessagesClient.SendAsync(flightConfirmationTemplateContent);
            PrintResponse(result);

            // Send sample template sample_issue_resolution
            MessageTemplate issueResolutionTemplate = AssembleSampleIssueResolution();
            var issueResolutionTemplateContent = new TemplateNotificationContent(channelRegistrationId, recipientList, issueResolutionTemplate);
            result = await notificationMessagesClient.SendAsync(issueResolutionTemplateContent);
            PrintResponse(result);

            // Send sample template sample_purchase_feedback
            MessageTemplate purchaseFeedbackTemplate = AssembleSamplePurchaseFeedback();
            var purchaseFeedbackTemplateContent = new TemplateNotificationContent(channelRegistrationId, recipientList, purchaseFeedbackTemplate);
            result = await notificationMessagesClient.SendAsync(purchaseFeedbackTemplateContent);
            PrintResponse(result);

            Console.WriteLine("Press any key to exit.");
            Console.ReadKey(true);
        }

        public static MessageTemplate AssembleSampleTemplate()
        {
            string templateName = "sample_template";
            string templateLanguage = "en_us";

            return new MessageTemplate(templateName, templateLanguage);
        }

        public static MessageTemplate AssembleSampleShippingConfirmation()
        {
            string templateName = "sample_shipping_confirmation";
            string templateLanguage = "en_us";

            var threeDays = new MessageTemplateText("threeDays", "3");

            WhatsAppMessageTemplateBindings bindings = new();
            bindings.Body.Add(new(threeDays.Name));

            MessageTemplate shippingConfirmationTemplate = new(templateName, templateLanguage);
            shippingConfirmationTemplate.Bindings = bindings;
            shippingConfirmationTemplate.Values.Add(threeDays);

            return shippingConfirmationTemplate;
        }

        public static MessageTemplate AssembleSampleMovieTicketConfirmation()
        {
            string templateName = "sample_movie_ticket_confirmation"; 
            string templateLanguage = "en_us"; 
            var imageUrl = new Uri("https://aka.ms/acsicon1");

            var image = new MessageTemplateImage("image", imageUrl);
            var title = new MessageTemplateText("title", "Contoso");
            var time = new MessageTemplateText("time", "July 1st, 2023 12:30PM");
            var venue = new MessageTemplateText("venue", "Southridge Video");
            var seats = new MessageTemplateText("seats", "Seat 1A");

            WhatsAppMessageTemplateBindings bindings = new();
            bindings.Header.Add(new(image.Name));
            bindings.Body.Add(new(title.Name));
            bindings.Body.Add(new(time.Name));
            bindings.Body.Add(new(venue.Name));
            bindings.Body.Add(new(seats.Name));

            MessageTemplate movieTicketConfirmationTemplate = new(templateName, templateLanguage);
            movieTicketConfirmationTemplate.Values.Add(image);
            movieTicketConfirmationTemplate.Values.Add(title);
            movieTicketConfirmationTemplate.Values.Add(time);
            movieTicketConfirmationTemplate.Values.Add(venue);
            movieTicketConfirmationTemplate.Values.Add(seats);
            movieTicketConfirmationTemplate.Bindings = bindings;

            return movieTicketConfirmationTemplate;
        }

        public static MessageTemplate AssembleSampleHappyHourAnnouncement()
        {
            string templateName = "sample_happy_hour_announcement";
            string templateLanguage = "en_us";
            var videoUrl = new Uri("< Your .mp4 Video URL >");

            var video = new MessageTemplateVideo("video", videoUrl);
            var venue = new MessageTemplateText("venue", "Fourth Coffee");
            var time = new MessageTemplateText("time", "Today 2-4PM");
            WhatsAppMessageTemplateBindings bindings = new();
            bindings.Header.Add(new(video.Name));
            bindings.Body.Add(new(venue.Name));
            bindings.Body.Add(new(time.Name));

            MessageTemplate happyHourAnnouncementTemplate = new(templateName, templateLanguage);
            happyHourAnnouncementTemplate.Values.Add(venue);
            happyHourAnnouncementTemplate.Values.Add(time);
            happyHourAnnouncementTemplate.Values.Add(video);
            happyHourAnnouncementTemplate.Bindings = bindings;

            return happyHourAnnouncementTemplate;
        }

        public static MessageTemplate AssembleSampleFlightConfirmation()
        {
            string templateName = "sample_flight_confirmation";
            string templateLanguage = "en_us";
            var documentUrl = new Uri("< Your .pdf document URL >");

            var document = new MessageTemplateDocument("document", documentUrl);
            var firstName = new MessageTemplateText("firstName", "Kat");
            var lastName = new MessageTemplateText("lastName", "Larssen");
            var date = new MessageTemplateText("date", "July 1st, 2023");

            WhatsAppMessageTemplateBindings bindings = new();
            bindings.Header.Add(new(document.Name));
            bindings.Body.Add(new(firstName.Name));
            bindings.Body.Add(new(lastName.Name));
            bindings.Body.Add(new(date.Name));

            MessageTemplate flightConfirmationTemplate = new(templateName, templateLanguage);
            flightConfirmationTemplate.Values.Add(document);
            flightConfirmationTemplate.Values.Add(firstName);
            flightConfirmationTemplate.Values.Add(lastName);
            flightConfirmationTemplate.Values.Add(date);
            flightConfirmationTemplate.Bindings = bindings;

            return flightConfirmationTemplate;
        }

        public static MessageTemplate AssembleSampleIssueResolution()
        {
            string templateName = "sample_issue_resolution";
            string templateLanguage = "en_us";

            var name = new MessageTemplateText(name: "name", text: "Kat");
            var yes = new MessageTemplateQuickAction(name: "Yes"){ Payload =  "Kat said yes" };
            var no = new MessageTemplateQuickAction(name: "No") { Payload = "Kat said no" };

            WhatsAppMessageTemplateBindings bindings = new();
            bindings.Body.Add(new(name.Name));
            bindings.Buttons.Add(new(WhatsAppMessageButtonSubType.QuickReply.ToString(), yes.Name));
            bindings.Buttons.Add(new(WhatsAppMessageButtonSubType.QuickReply.ToString(), no.Name));

            MessageTemplate issueResolutionTemplate = new(templateName, templateLanguage);
            issueResolutionTemplate.Values.Add(name);
            issueResolutionTemplate.Values.Add(yes);
            issueResolutionTemplate.Values.Add(no);
            issueResolutionTemplate.Bindings = bindings;

            return issueResolutionTemplate;
        }

        public static MessageTemplate AssembleSamplePurchaseFeedback()
        {
            
            string templateName = "sample_purchase_feedback";
            string templateLanguage = "en_us";
            var imageUrl = new Uri("https://aka.ms/acsicon1");

            var image = new MessageTemplateImage(name: "image", uri: imageUrl);
            var product = new MessageTemplateText(name: "product", text: "coffee");
            var urlSuffix = new MessageTemplateQuickAction(name: "text") { Text = "survey-code"};
            
            WhatsAppMessageTemplateBindings bindings = new();
            bindings.Header.Add(new(image.Name));
            bindings.Body.Add(new(product.Name));
            bindings.Buttons.Add(new(WhatsAppMessageButtonSubType.Url.ToString(), urlSuffix.Name));

            MessageTemplate purchaseFeedbackTemplate = new(templateName, templateLanguage);
            purchaseFeedbackTemplate.Values.Add(image);
            purchaseFeedbackTemplate.Values.Add(product);
            purchaseFeedbackTemplate.Values.Add(urlSuffix);
            purchaseFeedbackTemplate.Bindings = bindings;

            return purchaseFeedbackTemplate;
        }

        public static void PrintResponse(Response<SendMessageResult> response)
        {
            Console.WriteLine($"Response: {response.GetRawResponse().Status} " +
                $"({response.GetRawResponse().ReasonPhrase})");
            Console.WriteLine($"Date: " +
                $"{response.GetRawResponse().Headers.First(header => header.Name == "Date").Value}");
            Console.WriteLine($"ClientRequestId: {response.GetRawResponse().ClientRequestId}");
            Console.WriteLine($"MS-CV: " +
                $"{response.GetRawResponse().Headers.First(header => header.Name == "MS-CV").Value}");
            foreach (var receipts in response.Value.Receipts)
            {
                Console.WriteLine($"MessageId: {receipts.MessageId}");
            }
            Console.WriteLine($"\n");
        }
    }
}

后续步骤