Build a Twilio SMS + Microsoft Teams Integration

December 15, 2025
Written by
Reviewed by

Build a Twilio SMS + Microsoft Teams Integration

Integrating Twilio SMS with Microsoft Teams creates a powerful, streamlined communication channel that brings customer, client, or field messages directly into the collaboration platform your teams already use every day. By leveraging Twilio’s reliable global messaging infrastructure and Teams’ familiar interface and collaboration features, you can deliver fast and coordinated support right from your phone.

In this tutorial, you'll learn how to integrate Twilio SMS with Microsoft Teams and .NET 8 or 9, using an Azure bot as the connection source.

Prerequisites

Before you begin, make sure you have the following:

  • A Microsoft Account
  • An Office Account with access to Teams Enterprise Edition. You will need the Enterprise version of Teams to be able to install the bot.
  • A Twilio Account with a phone number with SMS capabilities
  • .NET 8 or 9
  • IDE of choice

High-Level Architecture/What You'll Build

You'll create:

  • A lightweight Azure Bot
  • Twilio posts SMS → your bot endpoint
  • Bot posts messages into Teams channel

Incoming SMS ➜ Your Bot Server ➜ Teams Channel ➜ Agent Replies ➜ Your bot server ➜ Twilio SMS

Tutorial

1. Create the Azure Bot

You only need the “Bot Channels Registration” resource. Set it up with the following steps.

  • Go to Azure Portal → Create a Resource
  • Search: Bot Channels Registration
  • Create an Azure Bot with the following settings:
  • Bot name: teams-sms-bot
  • Type: Single-tenant

You can create a new Resource Group or use an existing one.

  • After deployment:
  • Go to Resource
  • Choose Settings → Channels in the left hand sidebar
  • Add Microsoft Teams channel

You will have to agree to the Terms of Service for a Teams channel, and choose Commercial (most common) or Government channel. It will take a few seconds to create your channel.

  • After deployment, you will need to create a Client Secret to authenticate your Bot with Teams. You will first need to find your Bot's App Registration.
  • Search for "App registrations" in the top search bar.
  • Click App Registrations
  • Click All Applications
  • Click on your Bot
  • In the left side nav, look for Manage → Certificates & secrets
  • Click New Client Secret
  • Create a new client secret with a description like "BotSecret." Save this value for later.

2. Build the Bot Server

Now you will create your bot server in .NET.

First, start by creating a new .NET web application. In the terminal:

dotnet new webapi -n SmsTeamsBot cd SmsTeamsBot

Now add the necessary packages for .NET and Twilio:

dotnet add package Microsoft.Bot.Builder dotnet add package Microsoft.Bot.Builder.Integration.AspNet.Core dotnet add package Twilio

You'll need to create a few files for your bot to operate, and change the code in your program.cs file. Here's the folder structure that you will create:

/SmsTeamsBot

    Program.cs

    AdapterWithErrorHandler.cs

    SmsBot.cs

    Appsettings.json

Populate these files with the following code.

Program.cs

using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Extensions.Logging;
using Twilio.Rest.Api.V2010.Account;
using Twilio;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient();
// Bot Framework adapters
builder.Services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
builder.Services.AddSingleton<IBot, SmsBot>();
builder.Services.AddSingleton<ConversationReferenceStore>();
var config = builder.Configuration;
// Twilio setup
TwilioClient.Init(
   config["Twilio:AccountSid"],
   config["Twilio:AuthToken"]
);
var app = builder.Build();
var botAppId = config["AzureBot:MicrosoftAppID"];
// Endpoint for Teams → Bot
app.MapPost("/api/messages", async (HttpRequest req, HttpResponse res, IBotFrameworkHttpAdapter adapter, IBot bot) =>
{
   await adapter.ProcessAsync(req, res, bot);
});
// Endpoint for Twilio → Bot (incoming SMS)
app.MapPost("/sms", async (HttpContext context, BotFrameworkHttpAdapter adapter, ConversationReferenceStore store) =>
{
   var form = await context.Request.ReadFormAsync();
   var from = form["From"].ToString();
   var body = form["Body"].ToString();
   var reference = store.GetOrCreateReference(from);
   await adapter.ContinueConversationAsync(
       botAppId,
       reference,
       async (turnContext, cancellationToken) =>
       {
           await turnContext.SendActivityAsync("Forwarded message from SMS.", cancellationToken: cancellationToken);
       },
       default
   );
   context.Response.ContentType = "text/xml";
   await context.Response.WriteAsync("<Response></Response>");
});
app.Run();
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Builder;
using Microsoft.Extensions.Logging;
public class AdapterWithErrorHandler : BotFrameworkHttpAdapter
{
    public AdapterWithErrorHandler(IConfiguration configuration, ILogger<BotFrameworkHttpAdapter> logger)
        : base(configuration, logger)
    {
        OnTurnError = async (turnContext, exception) =>
        {
            logger.LogError(exception, "Unhandled bot error");
            await turnContext.SendActivityAsync("Oops! Something went wrong.");
        };
    }
}
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using Twilio.Rest.Api.V2010.Account;
public class SmsBot : ActivityHandler
{
    private readonly IConfiguration _config;
    private readonly ConversationReferenceStore _store;
    public SmsBot(IConfiguration config, ConversationReferenceStore store)
    {
        _config = config;
        _store = store;
    }
    protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> context, CancellationToken cancellationToken)
    {
        var activity = context.Activity;
        // Phone number attached from Twilio handler
        var phone = activity.ChannelData is IDictionary<string, object> data && data.ContainsKey("phone")
            ? data["phone"].ToString()
            : null;
        if (string.IsNullOrEmpty(phone))
        {
            await context.SendActivityAsync("This Teams thread is not linked to an SMS session.");
            return;
        }
        // Send SMS back via Twilio
        await MessageResource.CreateAsync(
            body: activity.Text,
            from: _config["Twilio:FromNumber"],
            to: phone
        );
        await context.SendActivityAsync($"Sent SMS to {phone}");
    }
}

ConversationReferenceStore.cs

Stores (phone → Teams thread) mappings. For production, replace with Redis/DB.

using Microsoft.Bot.Schema;
public class ConversationReferenceStore
{
    private readonly Dictionary<string, ConversationReference> _store = new();
    private readonly IConfiguration _config;
    public ConversationReferenceStore(IConfiguration config)
    {
        _config = config;
    }
    public ConversationReference GetOrCreateReference(string phone)
    {
        if (_store.ContainsKey(phone))
            return _store[phone];
        var reference = new ConversationReference
        {
            Bot = new ChannelAccount { Id = _config["AzureBot:MicrosoftAppId"] },
            ChannelId = "msteams",
            ServiceUrl = _config["Teams:ServiceUrl"],
            Conversation = new ConversationAccount
            {
                Id = _config["Teams:ChannelId"]
            }
        };
        _store[phone] = reference;
        return reference;
    }
}

appsettings.json

For appsettings.json, you will need to replace the placeholder values shown here with real values from your configuration. Twilio values are all found on the Twilio Account Dashboard. The Azure Bot requires the Microsoft App ID, called Application (client) ID, and the Secret key created earlier.

Note that app settings should never be shared, so do not check this file with its real values into source control like GitHub.

{
  "AzureBot": {
    "MicrosoftAppId": "YOUR_BOT_APP_ID",
    "MicrosoftAppPassword": "YOUR_BOT_SECRET"
  },
  "Twilio": {
    "AccountSid": "ACxxxx",
    "AuthToken": "xxxx",
    "FromNumber": "+15551234567"
  },
  "Teams": {
    "ServiceUrl": "https://smba.trafficmanager.net/amer/",
    "ChannelId": "19:yourchannel@thread.tacv2"
  }
}

3. Deploy Your Application

Your application can be deployed anywhere, including on Azure, your own server, or AWS.

For demo purposes, you can deploy the application locally and use ngrok to create a port that is accessible by Twilio.

Type the following into your terminal

dotnet build
dotnet run

Note the port where your application is running. Use ngrok to open a connection:

ngrok http 5000

Use the forwarding URL created by ngrok in the next step.

4. Wire Twilio → .NET webhook

Navigate to the Twilio Console.

Select your phone number, and look for the settings for SMS under Messaging Configuration.

Add the following settings

  • A Message Comes In: Webhook
  • URL: https://yourngrokurl.ngrok.app/sms
  • HTTP: HTTP POST

5. Test your Bot in Teams

For the final step you will have to install your Bot in Teams. This requires the Enterprise edition of Teams to install the bot.

First, package your Bot for Teams. This will require a small amount of files in a .zip.

This includes:

  • manifest.json
  • color.png
  • outline.png

The color and outline pngs are just small png files that show an icon for your bot. Color.png is at the dimensions of 192x192 and outline.png is at the dimensions of 32x32. These icons don't have to be complex for testing, and can be a solid color. Check the requirements in the documentation for best practices about app icon creation.

This code snippet shows an example format for the manifest.json file that you will need.

{
  "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.11/MicrosoftTeams.schema.json",
  "manifestVersion": "1.11",
  "version": "1.0.0",
  "id": "YOUR-BOT-APP-ID",
  "packageName": "com.yourcompany.bot",
  "name": {
    "short": "My Bot",
    "full": "My Teams Bot"
  },
  "description": {
    "short": "My bot",
    "full": "My bot that connects to Twilio"
  },
  "developer": {
    "name": "Your Company",
    "websiteUrl": "https://yourdomain.com",
    "privacyUrl": "https://yourdomain.com/privacy",
    "termsOfUseUrl": "https://yourdomain.com/terms"
  },
  "bots": [
    {
      "botId": "YOUR-BOT-APP-ID",
      "scopes": ["personal", "team", "groupchat"]
    }
  ]
}

In the manifest, the botId is your Microsoft App ID. Now install your bot to Teams.

  • Open Microsoft Teams
  • Look at the left sidebar → Apps
  • Click Upload a custom app
  • Choose Upload for [Your Team Name]
  • Select TestBot.zip

Your bot is now linked into Microsoft Teams. Test the integration by sending an SMS message to your registered Twilio number and get the bot posting to your Teams channel.

What's Next?

With a developer tenant in place and your bot installed in Teams, you now have a complete, end-to-end setup where Twilio SMS and Microsoft Teams work together—making it easy to test, iterate, and confidently move from a proof of concept to a production-ready integration. This is just the beginning of what you can do with integrations and administration in Microsoft Teams. For more information, check out the Microsoft Teams documentation.

If you want to explore low-code integrations between Teams and Twilio, you might find Zapier to be a useful alternative method. This template will allow integration between Voice and Teams, or, try the popular SMS and Teams template.

As you can see, there are multiple different possibilities when creating connections between MS Teams and Twilio's systems. Using Twilio, you can create a variety of smooth integrations for you and your team to stay connected no matter where you are! We can't wait to see what you'll 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.