Receive an SMS and email it using Twilio SendGrid, C# and .NET Core

March 27, 2019
Written by

vqwvGirMVXQf8bGStK4xKGF4vtzssY0VthK_xXQyITCdwJoMGJlN_2BxVqxkzasx2t5Vt9HV2T9WIdEDNZHh0a3EISjvwX5eDCwktAsPSJEPWJkQDmAEKDJ47FInZi_XlcaslMHr

An apt business use for both Twilio SMS and Twilio SendGrid would be for customer enquiries on a website. Using C# and .NET Core 2.2 we will build an app that receives an SMS, takes the from number and the message body and send out an email using Twilio SendGrid.

To get started with this project you will need the following:

If you would like to see a full integration of Twilio APIs in a .NET Core application then checkout this free 5-part video series I created. It's separate from this blog post tutorial but will give you a full run down of many APIs at once.

Creating the project

We are going to use the WebApi template project that comes with the .NET Core SDK, as a starting point.

From the command line, navigate to the location you wish to create the new application. Use the following command to create the solution and its containing folder, which we will call TextToEmail

 

>dotnet new webapi -o TextToEmail

The template comes with a demo controller called ValuesController.

Next, open the application in your preferred IDE.

I, personally, like to change the launchSettings.json file, found in the Properties folder of the solution.  Changing the use of ports 5000 and 5001 and removing the sslPort assignation when running locally, as it seems to limit problems with self-signing certificates and the like.

{
 "$schema": "http://json.schemastore.org/launchsettings.json",
 "iisSettings": {
   "windowsAuthentication": false,
   "anonymousAuthentication": true,
   "iisExpress": {
     "applicationUrl": "http://localhost:3238"
   }
 },
 "profiles": {
   "IIS Express": {
     "commandName": "IISExpress",
     "launchBrowser": true,
     "launchUrl": "api/values",
     "environmentVariables": {
       "ASPNETCORE_ENVIRONMENT": "Development"
     }
   },
   "TextToEmail": {
     "commandName": "Project",
     "launchBrowser": true,
     "launchUrl": "api/values",
     "applicationUrl": "http://localhost:3238",
     "environmentVariables": {
       "ASPNETCORE_ENVIRONMENT": "Development"
     }
   }
 }
}

To test your project, first change into the new directory using:

>cd TextToEmail

And then run the application using the following command:

>dotnet run

You will see the following response in the browser when you navigate to localhost:<PORT_NUMBER>/api/values:

"value1"

We will use a couple of NuGet packages in our solution so let's add those to the TextToEmail.csproj file.

Open the TextToEmail.csproj file and update it with the following lines:

<Project Sdk="Microsoft.NET.Sdk.Web">

 <PropertyGroup>
   <TargetFramework>netcoreapp2.2</TargetFramework>
   <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
 </PropertyGroup>

 <ItemGroup>
   <PackageReference Include="Microsoft.AspNetCore.App" />
   <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
   <PackageReference Include="sendgrid" Version="9.10.0" />
   <PackageReference Include="twilio" Version="5.27.1" />
   <PackageReference Include="Twilio.AspNet.Core" Version="5.20.1" />
 </ItemGroup>
</Project>

Back in the command line, stop the project with CTRL + C, then run dotnet restore to ensure that these packages are downloaded and ready for use later.

The Twilio SMS webhook

We will need to create an API endpoint to act as a webhook for Twilio to use when a message comes in.

In the Controllers folder create a new file called TextController.cs and add the following code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Twilio;
using Twilio.AspNet.Core;
using Twilio.AspNet.Common;
using Twilio.Rest.Api.V2010.Account;
using Twilio.TwiML;
using Twilio.Types;

namespace TextToEmail.Controllers
{
   [Route("api/[controller]")]
   [ApiController]
   public class TextController : TwilioController
   {
       [HttpPost]
       public async Task<IActionResult> Post()
       {
           var from = Request.Form["From"];
           var body = Request.Form["Body"];
           var testContent = $@"<Response><Message>your number:{from} and your message: '{body}'</Message></Response>";
           return Content(testContent, "text/xml");
       }

   }
}

The above code will respond to an incoming SMS with a message containing the number the SMS came from and the body of that message. To try this our we'll need to use ngrok.

Setting up ngrok

ngrok creates a public facing URL that tunnels to our project running locally so we can test our endpoint without deploying to a server. Follow the instructions on the ngrok site to download and install it.

Once installed, run the following on your command line to start ngrok, replacing <PORT_NUMBER> with the port your application is listening on.

> ngrok http <PORT_NUMBER> -host-header="localhost:<PORT_NUMBER>"

You will then see an output similar to below.  

screenshot of ngrok

Copy the public facing URL which should be along the lines of https://12345.ngrok.io.

To enable Twilio to make the initial request that fires off our string of events, we need to set up the webhook.

Go to the Twilio console and find the number that you added for this project.  Next, add the API endpoint https://<NGROK_NUMBER>.ngrok.io/api/text from ngrok and paste into the A MESSAGE COMES IN section, then save.

screenshot of twilio console

If you now run your project and send an SMS to your number you will receive the message containing the from and body information we set up in response.

Setting up the Email service

Now we have the contents of our SMS captured, we can create a service that handles the email side of our application.

Best practice, in my opinion, would be to create an interface for our service and utilise .NET Core's built-in dependency injection. For simplicity, we will create a simple class.

Let's create a new file called Emailer.cs in the root of your solution and add the following code to it:

using System;
using System.Net;
using System.Threading.Tasks;
using SendGrid;
using SendGrid.Helpers.Mail;

namespace TextToEmail
{
   public class Emailer
   {
       private readonly string _sendGridApiKey;
       public Emailer()
       {
           _sendGridApiKey = Environment.GetEnvironmentVariable("SENDGRID_KEY");
       }
   }
}

In the above code, I have created a private readonly variable called _sendGridApiKey which we map our SendGrid API key to in the constructor below.  For more information check out this blog post on how to set up an environment variable on your specific operating system.

Let's also create a class to manage all the properties we need to send our email. Add the following private class just below the constructor in our Emailer class.  Be sure to update the code with your own email address and name.

       private class Email
       {
           public Email(string from, string body)
           {
               {
                   To = new EmailAddress("<YOUR_EMAIL>", "<YOUR_NAME>");
                   From = new EmailAddress("<YOUR_EMAIL>", "Text to Email App");
                   Subject = $"A new text message has been sent from {from}";
                   HtmlContent = $"<strong>{body}<strong>";
                   PlainTextContent = body;
               };
           }
           public EmailAddress From { get; set; }
           public EmailAddress To { get; set; }
           public string Subject { get; set; }
           public string PlainTextContent { get; set; }
           public string HtmlContent { get; set; }
       }

We could also create a new file for this Email class and make it public. However, we will only be using it in the Emailer class, so we may as well leave it there for simplicity.

Next, let's add a private method called SendEmail just after the constructor in the Emailer class and add the following code to it:

private async Task<Response> SendEmail(Email email)
       {
           var client = new SendGridClient(_sendGridApiKey);
           var msg = MailHelper.CreateSingleEmail(
               email.From, email.To, email.Subject, email.PlainTextContent, email.HtmlContent);
           var response = await client.SendEmailAsync(msg);
           return response;
       }

This code initiates the SendGrid client using our API key, then it creates the email message, finally sending the email and returning a Response called response.

As this is a private method we will need to add a public method called Send just before the SendEmail method and add the following code to it:

       public async Task<string> Send(string from, string body)
       {
           var email = new Email(from,body);

           var response = await SendEmail(email);

           var message = "Your message could not be processed at this time. Please try again later.";

           if (response.StatusCode == HttpStatusCode.Accepted)
           {
               message = "Thank you for your message, someone will be in touch soon!";
           }
           return message;
       }

This method will take our incoming from number and message body and create a new Email object.  This email object then gets passed to the SendEmail method and awaits the response.

If the HttpStatusCode is Accepted we know that our email was sent successfully and we can return a relevant message.  If it was anything else, we can return a message telling our user that we didn't receive their SMS properly and that they should try again later.

All that's left to do now, is to call our Emailer method from the TextController. Returning to the TextController.cs file, update the Post method with the following code:

       [HttpPost]
       public async Task<IActionResult> Post()
       {
           var from = Request.Form["From"];
           var body = Request.Form["Body"];
           var emailer = new Emailer();
           var message = await emailer.Send(from,body);
           var response = $"<Response><Message>{message}</Message></Response>";
           return Content(response, "text/xml");
       }

Time to test it out

Run your solution again and then send an SMS message your Twilio number once more.

You will receive the "Thank you for your message, someone will be in touch soon!" in response and an email to the email account you specified.

Sometimes, your email provider might block an email for some reason.  But you can see if your email was successfully received by SendGrid, even if it wasn't delivered, by checking out the activity section of your account.

gif of twilio and sendgrid logos

Summary

We've seen how we can quickly receive an incoming SMS message and send out an email.  A great update to the above code would be to add in some logging to the Emailer class so we can better debug when things go wrong.

Let me know what other cool ideas you have for Twilio SMS and Twilio SendGrid. I can't wait to see what you build!