How to create a promotional campaign with RCS and SendGrid in C#

March 31, 2026
Written by
Reviewed by

How to create a promotional campaign with RCS and SendGrid in C#

In 2026, it's harder than ever to capture and hold the attention of your customers. A promotional campaign isn't just one text or one email. It’s a coordinated dance between different channels. SMS is one approach to send out marketing pushes, and email is another. To make a bigger impact, you can combine email templates and RCS resources for a more unified look and feel to your marketing.

In this short tutorial, you will learn how to use Twilio Sendgrid and RCS together with .NET 10 to create a cohesive marketing campaign. You'll learn how to contact your customers with email reach-outs that match your RCS reachouts with the same style of template. Let's get started.

What is RCS?

RCS cards are interactive, rich media messages. RCS enhances traditional SMS by supporting features like branded and verified sender IDs, titles, images, and interactive content, providing a more engaging and interactive messaging experience for consumers.

If you've never used RCS, check out our RCS vs SMS article to understand the differences between these messaging channels.

RCS messaging is only available on supported devices and carriers. If your recipient doesn't have RCS support, Twilio will automatically send the fallback text message defined in your template's twilio/text section.

What is SendGrid?

SendGrid is Twilio's email sending platform. SendGrid allows you to easily design, automate, and deliver impactful email marketing campaigns. You can use SendGrid to automate your campaigns with simple triggers, and set up drag and drop templates to make marketing email creation easy.

These two services can work together well for your cross-channel marketing campaigns:

  • RCS (Rich Communication Services): It’s SMS, but more. RCS allows for high-res carousels, "Suggested Reply" buttons, and verified sender branding. It's great for instant impulse clicks.
  • SendGrid: Email is better for long-form storytelling. If your customers liked the RCS photo, the email gives them the full catalog and the "About Our Brand" story.

Creating Our RCS/SendGrid Campaign

To get started, you will need the following:

  • A Twilio account (sign up here).
  • A SendGrid account (you can use the same Twilio account)
  • A Twilio phone number for sending SMS, as a fallback to your RCS service.
  • A device capable of receiving RCS messages.
  • The .NET framework installed on your development machine.

Setting up your RCS Sender

This tutorial builds off of the tutorial How to Send an RCS Message with C# .NET and Twilio. That tutorial walks through a detailed demonstration of how to set up an RCS sender with screenshots. To begin with this tutorial, set up your RCS Sender in the Twilio RCS Dashboard as shown. You will need a graphical logo for your RCS sender, as well as a device for testing. Set your device up as an RCS Tester so you can continue to test the rest of the tutorial.

Setting up a SendGrid Dynamic Template

You will need to create a dynamic template in SendGrid to match your RCS. Log into the SendGrid dashboard, and go to Email API > Dynamic Templates. Enter a human readable name for your template and click Create. You are going to create a Dynamic Template, so that you can programmatically utilize the same template structure for both your RCS message and your matching SendGrid email. Click on the button that says Create a Dynamic Template. Choose a memorable name for your template, then continue.

Now that the template has been created, click the arrow next to your new template name to open up the editing panel. You will see a Template ID here. Save that ID number for later as you will need this for your email sending application.

Now, to construct the rest of your template, select Add Version. Then select Blank Template. This gives you the option to create your template with code or with drag-and-drop. For this tutorial, you can use drag-and-drop, along with handlebar templating to create a truly dynamic template.

Choose Design and SendGrid will open up an email template. For the Subject of your email you type {{subject}} to replace the placeholder with the dynamic value you will create programmatically. Likewise, for the Preheader, choose {{preheader}}.

Build out your template using placeholders and any custom text you wish to add. To add an image, use the Image module, and choose to edit the HTML of that image. Replace the image URL with the variable {{image_url}} as shown here.

example code for the image replacement
example code for the image replacement

This tutorial also has an option for a button that you can add. Drag the Button element onto your email template, and enter {{button_text}} for the Button Text, and {{button_url}} for the Button URL.

When you are done, your SendGrid template will look like this:

the sendgrid template with all placeholders
the sendgrid template with all placeholders

Save your Template.

It's possible to save multiple versions of a Dynamic Template with the same ID. For your code solution to work, make sure the Code template you just created is the one that is set to Active.

Your .NET Application for RCS and SendGrid

Your .NET application will tie both of these pieces together, sending an email and RCS at once.

Open your IDE and begin by creating a new .NET WebAPI application.

mkdir RcsEmailSender
cd RcsEmailSender
dotnet new console
dotnet new sln
dotnet sln add RcsEmailSender.csproj

Your project will require the following nuget packages:

dotnet add package SendGrid
dotnet add package Twilio
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Json
dotnet add package Microsoft.Extensions.Configuration.EnvironmentVariables

For this project you will use several environment variables. In this tutorial those variables will be added to the file appsettings.json. Create this file in your project folder. Add the following lines, replacing the placeholders with the necessary values for your application.

{
 "MessageServices": {
   "Twilio": {
     "AccountSid": "YOUR_TWILIO_ACCOUNT_SID",
     "AuthToken": "YOUR_TWILIO_AUTH_TOKEN",
     "FromNumber": "+15551234567"
   },
   "SendGrid": {
     "ApiKey": "YOUR_SENDGRID_API_KEY",
     "FromEmail": "no-reply@example.com",
     "FromName": "Example Sender",
     "TemplateId": "d-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
   },
   "Recipients": {
     "PhoneNumber": "+15557654321",
     "Email": "recipient@example.com"
   }
 }
}

Twilio Account SID and Authentication Token are found in your Twilio dashboard. Your From number is your sending number for RCS. For SendGrid, you will need to create a SendGrid API Key that allows you to send mail. If you are creating a custom key, be sure it has Mail Send permissions. To get your Dynamic Template ID, go to the SendGrid dashboard and get the ID from the template that you created. The FromEmail will be your verified sender email, and the FromName can be any human readable value. For the Recipients, add the phone number and email address that you are going to use for testing.

There are multiple ways to secure environment variables in a .NET project. This demo is using a simplified approach. Be sure not to check any code into Github or any other source control containing your environment variables. See this explainer for how to set environment variables to get more information about best practices to store environment variables securely.

Now you are ready to add code to your project.

The first step is creating models that the RCS and email will use.

In a fully structured application, this would be included in a folder. For this demo, however, you'll just make a quick models file to store the models you need.

Create a file, Models.cs, and add this code:

using System;
namespace RcsEmailSender
{
   // Configuration class for storing API keys and credentials
   public class MessageServiceConfig
   {
       public string TwilioAccountSid { get; set; } = string.Empty;
       public string TwilioAuthToken { get; set; } = string.Empty;
       public string TwilioFromNumber { get; set; } = string.Empty;
       public string SendGridApiKey { get; set; } = string.Empty;
       public string SendGridFromEmail { get; set; } = string.Empty;
       public string SendGridFromName { get; set; } = string.Empty;
       public string SendGridTemplateId { get; set; } = string.Empty;
       public string RecipientPhoneNumber { get; set; } = string.Empty;
       public string RecipientEmail { get; set; } = string.Empty;
   }
   // Consolidated message model for both RCS and Email
   public class MessageContent
   {
       public string Title { get; set; } = string.Empty;
       public string Body { get; set; } = string.Empty;
       public string ImageUrl { get; set; } = string.Empty;
       public string ButtonText { get; set; } = string.Empty;
       public string ButtonUrl { get; set; } = string.Empty;
   }
}

Save the models file.

Now you will turn your attention to the program logic of the project. In your Program.cs file, replace the existing code with the following:

using Microsoft.Extensions.Configuration;
using SendGrid;
using SendGrid.Helpers.Mail;
using Twilio;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
namespace RcsEmailSender
{
   class Program
   {
       static async Task Main(string[] args)
       {
           // Set up configuration system
                var configuration = new ConfigurationBuilder()
               .SetBasePath(Directory.GetCurrentDirectory())
               .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
               //.AddEnvironmentVariables("RCS_EMAIL_") // Allows overriding with environment variables prefixed with RCS_EMAIL_
               .Build();
           // Load config from configuration
           var config = new MessageServiceConfig
           {
               TwilioAccountSid = configuration["MessageServices:Twilio:AccountSid"] ?? string.Empty,
               TwilioAuthToken = configuration["MessageServices:Twilio:AuthToken"] ?? string.Empty,
               TwilioFromNumber = configuration["MessageServices:Twilio:FromNumber"] ?? string.Empty,
               SendGridApiKey = configuration["MessageServices:SendGrid:ApiKey"] ?? string.Empty,
               SendGridFromEmail = configuration["MessageServices:SendGrid:FromEmail"] ?? string.Empty,
               SendGridFromName = configuration["MessageServices:SendGrid:FromName"] ?? string.Empty,
               SendGridTemplateId = configuration["MessageServices:SendGrid:TemplateId"] ?? string.Empty,
               RecipientPhoneNumber = configuration["MessageServices:Recipients:PhoneNumber"] ?? string.Empty,
               RecipientEmail = configuration["MessageServices:Recipients:Email"] ?? string.Empty
           };

This is starting off by getting your API keys and other security information from the appsettings.json file that you built. An optional line of code, commented out, would allow this application to use environment variables instead if that is your preference. Once all these values are collected, the application builds a MessageService based on that model.

Now add the next block of code:

var messageContent = new MessageContent
           {
               Title = "Owl Air Elite Status",
               Body = "Congratulations! You've reached Elite status. Add code ELITE10 for 10% off your next flight. Book at twilio.com or call +15551234567",
               ImageUrl = "https://rcs-4036.twil.io/image.png", // Image URL for testing
               ButtonText = "Book Now",
               ButtonUrl = "https://twilio.com"
           };

This block builds the RCS Message. Replace the test URL with the URL of the image you wish to send, or leave it as it is for now to send a Twilio logo.

Now continue your Program.cs with this block of code:

try
           {
               //Send RCS message
               var rcsResult = await SendRcsMessage(config, messageContent);
               Console.WriteLine($"RCS message sent: {rcsResult}");
               // Send Email
               var emailResult = await SendEmailWithDynamicTemplate(config, messageContent);
               Console.WriteLine($"Email sent: {emailResult}");
           }
           catch (Exception ex)
           {
               Console.WriteLine($"Error sending messages: {ex.Message}");
           }
       }

Here you are actually sending your RCS message and email. This takes the content of both and distributes them to the email dynamic template and to the RCS.

Finish off your Program.cs by adding the following blocks:

static async Task<string> SendRcsMessage(MessageServiceConfig config, MessageContent content)
       {
           TwilioClient.Init(config.TwilioAccountSid, config.TwilioAuthToken);
           var message = await MessageResource.CreateAsync(
               body: $"{content.Title}\n\n{content.Body}\n\nClick here: {content.ButtonUrl}",
               from: new PhoneNumber(config.TwilioFromNumber),
               to: new PhoneNumber(config.RecipientPhoneNumber),
               mediaUrl: new List<Uri> { new Uri(content.ImageUrl) } 
           );
           return message.Sid;
       }
       // Method to send email using SendGrid with dynamic template
       static async Task<bool> SendEmailWithDynamicTemplate(MessageServiceConfig config, MessageContent content)
       {
           // Initialize SendGrid client
           var client = new SendGridClient(config.SendGridApiKey);
           var from = new EmailAddress(config.SendGridFromEmail, config.SendGridFromName);
           var to = new EmailAddress(config.RecipientEmail);
           var msg = new SendGridMessage();
           msg.SetFrom(from);
           msg.AddTo(to);

           msg.SetTemplateId(config.SendGridTemplateId);
           // Define template data with proper naming that matches the SendGrid template
           var templateData = new
           {
               subject = content.Title,
               preheader = "Special offer inside!", // Optional preheader text
               title = content.Title,
               body_text = content.Body,
               image_url = content.ImageUrl,
               button_text = content.ButtonText,
               button_url = content.ButtonUrl,
               sender_name = config.SendGridFromName
           };
           msg.SetTemplateData(templateData);
           // Send the message
           var response = await client.SendEmailAsync(msg);
           return response.IsSuccessStatusCode;
       }
   }
}

This code takes the dynamic template placeholders you set up earlier for RCS and for email, and assigns values to them based on your code. If everything has been set up correctly, you can now run your application.

dotnet run

The application will send both an email and an RCS message. The format of the email will match the dynamic template that you set up earlier, and the RCS message will include the same information and graphic.

example of sent RCS
example of sent RCS

Troubleshooting

If you run into problems with your application there are a few things to consider.

First of all, be sure that your user account permits sending RCS and that your device is capable of receiving RCS. Remember to set your receiving device up as an RCS Tester. Sending RCS in bulk may require additional verification or certification depending on your country.

If your RCS isn't rendering as expected, you may have forgotten to use an image with a public URL. You can also review the TwilioCard Content Template documentation for supported card features.

If SendGrid email isn't sending, check your SendGrid dashboard. You may need to verify your sender or sender DNS. Check Email logs to confirm the status of your sent mail and look for any possible error codes.

If your Email isn't rendering as expected, you may want to make some adjustments on the template itself. Check out some tips for using the Design Editor in SendGrid.

What's Next?

In this tutorial you have learned how to create an RCS message and a SendGrid email that work together as part of a unified campaign. Future upgrades to this application might include additional template images to make the email and RCS look slightly different from one another. Another possible upgrade is to stagger the campaign so instead of sending emails and RCS simultaneously, the email is only sent if the user doesn't engage with the RCS. This way you can avoid sending redundant emails while A/B testing which users respond more to which style of product outreach.

For some more things you can build with RCS, check out some of these other Twilio articles:

We can't wait to see what you will build next!

Amanda Lange is a .NET Engineer of Technical Content. She is here to teach how to create great things using C# and .NET programming. She can be reached at amlange [ at] twilio.com.