Send Emails using the SendGrid API with .NET 6 and C#

Niels Swimburger.NET 🍔 - Jan 5 '22 - - Dev Community

This blog post was written for Twilio and originally published at the Twilio blog.

Email has been around for decades, but sending emails at scale is still hard. With Twilio SendGrid, you can send emails without worrying about scalability. You can use the SendGrid APIs and SDKs to start sending emails within minutes. You could also use the SMTP protocol if you already have an existing codebase that relies on SMTP. In this post, you will learn how to send emails using the SendGrid .NET SDK and a .NET 6 console application.

Prerequisites

You will need the following things to follow along:

  • OS that supports .NET (Windows/Mac/Linux)
  • .NET 6 SDK (download)
  • A code editor or IDE (Recommended: VS Code with C# plugin, Visual Studio, JetBrains Rider)
  • A Twilio SendGrid account (signup)

Everything you will learn applies even if you’re using an older version of .NET (Core), but you will need to make minor adjustments.

Configuring your SendGrid account to send emails

There are two things you need to configure before you can send emails. First, you’ll need to set up Sender Authentication. This will verify that you own the email address or domain that you will send emails from. Second, you’ll need to create a SendGrid API Key with permission to send emails.

Sender Authentication

It is recommended to configure Domain Authentication which requires you to add a record to your DNS host. To keep things simple, you will use Single Sender Verification instead. This will verify that you own the single email address that you want to send emails from. Single Sender Verification is great for testing purposes, but it is not recommended for production.

Twilio recommends Domain Authentication for production environments. An authenticated domain proves to Inbox Service Providers you own the domain and removes the via sendgrid.net text that inbox providers would otherwise append to your from address.

Go to the SendGrid website and log in. Click on the Settings tab in the side menu. Once the settings tab opens up, click on Sender Authentication.

Side-navigation with a Settings group and multiple links in the group. The link "Sender Authentication" is highlighted.

Click on Get Started under the Single Sender Verification section.

A button saying "Get Started" to verify an individual email address.

This will open a form on the right-side panel. Fill out the form with your information and email address.

A form to create a sender. The form asks for contact information including the email address that will be used to send emails from.

Click Create after filling out the form. Another panel will appear on the right asking you to confirm your email address. An email has been sent to the email address you entered.

Go to your inbox, open the email from SendGrid, and click Verify Single Sender.

An email from SendGrid with a button saying "Verify Single Sender".

Your email address has been verified and you can now use it to send emails!

Create a SendGrid API key to send emails

Back on the SendGrid website, click on API Keys under the Settings tab. Click on Create API Key in the top right corner. This will open another form in the right-side panel. Give your API Key a useful name. You can assign different permissions to the API Key. For optimal security, you should only give the minimum amount of permissions that you need.

Click on Restricted Access.

A form to create an API Key. The form asks for a name for the key and what permissions to grant to the key.

Scroll down to the Mail Send accordion item and click on it to reveal the permissions underneath. Drag the slider to the right for the Mail Send permission.

A list of permissions that you can control using a slider bar next to each permission. The "Mail Send" accordion item is expanded to reveal the "Mail Send" permission underneath.

Scroll to the bottom of the form and click on Create & View. The API key will now be displayed on your screen. You will not be able to retrieve the API key again once you leave this screen.

Copy the secret somewhere safe.

API key is displayed to copy and store elsewhere. Key will not be shown again.

With the sender verified and the API Key created, you’re ready to write some code!

Creating a console app to send emails

Create a new console app

Open a shell on your machine and create a new folder using the following command:

mkdir SendGridMail
Enter fullscreen mode Exit fullscreen mode

Move into to the new folder:

cd SendGridMail
Enter fullscreen mode Exit fullscreen mode

Create a new console application using .NET CLI:

dotnet new console
Enter fullscreen mode Exit fullscreen mode

Run the project using the .NET CLI:

dotnet run
Enter fullscreen mode Exit fullscreen mode

You should see “ Hello, World! ” output to your shell.

Integrating Twilio SendGrid

Add the SendGrid NuGet package to your project using the .NET CLI:

dotnet add package SendGrid
Enter fullscreen mode Exit fullscreen mode

Open up the console project using a code editor or IDE and replace the contents of the Program.cs file with the following:

using SendGrid;
using SendGrid.Helpers.Mail;

var apiKey = Environment.GetEnvironmentVariable("SENDGRID_API_KEY");
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
    From = new EmailAddress("[REPLACE WITH YOUR EMAIL]", "[REPLACE WITH YOUR NAME]"),
    Subject = "Sending with Twilio SendGrid is Fun",
    PlainTextContent = "and easy to do anywhere, especially with C#"
};
msg.AddTo(new EmailAddress("[REPLACE WITH DESIRED TO EMAIL]", "[REPLACE WITH DESIRED TO NAME]"));
var response = await client.SendEmailAsync(msg);

// A success status code means SendGrid received the email request and will process it.
// Errors can still occur when SendGrid tries to send the email. 
// If email is not received, use this URL to debug: https://app.sendgrid.com/email_activity 
Console.WriteLine(response.IsSuccessStatusCode ? "Email queued successfully!" : "Something went wrong!");
Enter fullscreen mode Exit fullscreen mode

You will need to put the above code and any subsequent code inside of the Main method of the Program class if you are using older versions of .NET or older templates of .NET.

Update the placeholder strings:

  • replace "[REPLACE WITH YOUR EMAIL]" with the email address you verified with your SendGrid account.
  • replace "[REPLACE WITH YOUR NAME]" with your name.
  • replace "[REPLACE WITH DESIRED TO EMAIL]" with the email address you want to send an email towards.
  • replace "[REPLACE WITH DESIRED TO NAME]" with the recipient's name.

Save the Program.cs file.

The code above does the following:

  • Line 4: Get the API key from the environment variables and store it in the apiKey variable.
  • Line 5: Construct a new SendGridClient with the apiKey.
  • Line 6 - 11: Create a new SendGridMessage object with your email address as sender, and with a subject, and text content.
  • Line 12: Add a recipient of the email.
  • Line 13: Send the SendGridMessage to the SendGrid API.
  • Line 18: Verify if the SendGrid API accepted the request by checking if the response status code is in the HTTP 2XX range.

When the SendGrid API responds with a successful HTTP status code, that does not necessarily mean that the email was successfully received by the recipient. It does however mean that the SendGrid API has accepted your request and will send the email. If the recipient does not receive the email, you can use the Email Activity Feed to find out why.

The application expects the API key to be stored in the SENDGRID_API_KEY environment variable.

Run the following command if you’re using a Bash or similar shell:

export SENDGRID_API_KEY=[REPLACE WITH YOUR API KEY]
Enter fullscreen mode Exit fullscreen mode

Run the following command if you’re using PowerShell:

$Env:SENDGRID_API_KEY = "[REPLACE WITH YOUR API KEY]"
Enter fullscreen mode Exit fullscreen mode

Run the following command if you're using CMD:

set SENDGRID_API_KEY="[REPLACE WITH YOUR API KEY]"
Enter fullscreen mode Exit fullscreen mode

The environment variable will be available for the duration of your shell session. You'll have to set the environment variable again when opening a new shell.

Run the project using the .NET CLI:

dotnet run
Enter fullscreen mode Exit fullscreen mode

If all went well, the output should be " Email queued successfully!".

Open the inbox of the recipient to verify you received the email. If you don't have access, you can use the Email Activity Feed to see the status of the email.

Here's what the email should look like:

An email with title "Sending with Twilio SendGrid is Fun" and body "and easy to do anywhere, especially with C#

Bonus 1: Ask for user input

Chances are you don't always want to send the same email. You can ask for user input to make the application more flexible. Update Program.cs to match the content below:

using SendGrid;
using SendGrid.Helpers.Mail;

var apiKey = Environment.GetEnvironmentVariable("SENDGRID_API_KEY");
var client = new SendGridClient(apiKey);

Console.Write("To: ");
var toEmail = Console.ReadLine();

Console.Write("Subject: ");
var subject = Console.ReadLine();

Console.Write("Body: ");
var body = Console.ReadLine();

var msg = new SendGridMessage()
{
    From = new EmailAddress("[REPLACE WITH YOUR EMAIL]", "[REPLACE WITH YOUR NAME]"),
    Subject = subject,
    PlainTextContent = body
};
msg.AddTo(new EmailAddress(toEmail));
var response = await client.SendEmailAsync(msg);

// A success status code means SendGrid received the email request and will process it.
// Errors can still occur when SendGrid tries to send the email. 
// If email is not received, use this URL to debug: https://app.sendgrid.com/email_activity 
Console.WriteLine(response.IsSuccessStatusCode ? "Email queued successfully!" : "Something went wrong!");
Enter fullscreen mode Exit fullscreen mode

The updated code asks for user input using Console.ReadLine to get the subject, body, and recipient email address. Run the project again and answer the prompts:

dotnet run
Enter fullscreen mode Exit fullscreen mode

Bonus 2: Make the project more configurable

Currently, the sender's email address and the name are hardcoded, and the SendGrid API Key is configured through an environment variable. This is perfectly fine for a proof of concept, but you'll want to make the project more configurable. That's why you'll take advantage of the very pluggable configuration system that ships as part of .NET.

Add the following NuGet packages using the .NET CLI:

dotnet add package Microsoft.Extensions.Hosting 
dotnet add package Microsoft.Extensions.Configuration.UserSecrets
Enter fullscreen mode Exit fullscreen mode

Update the Program.cs file to match the content below:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SendGrid;
using SendGrid.Helpers.Mail;

using IHost host = Host.CreateDefaultBuilder(args).Build();
var config = host.Services.GetRequiredService<IConfiguration>();

var apiKey = config.GetValue<string>("SendGridApiKey");
var fromEmail = config.GetValue<string>("FromEmail");
var fromName = config.GetValue<string>("FromName");
if(string.IsNullOrEmpty(apiKey)) throw new Exception("SendGridApiKey should not be null or empty");
if(string.IsNullOrEmpty(fromEmail)) throw new Exception("FromEmail should not be null or empty");
if(string.IsNullOrEmpty(fromName)) throw new Exception("FromName should not be null or empty");

Console.Write("To:");
var toEmail = Console.ReadLine();

Console.Write("Subject:");
var subject = Console.ReadLine();

Console.Write("Body:");
var body = Console.ReadLine();

var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
    From = new EmailAddress(fromEmail, fromName),
    Subject = subject,
    PlainTextContent = body
};
msg.AddTo(new EmailAddress(toEmail));
var response = await client.SendEmailAsync(msg);

// A success status code means SendGrid received the email request and will process it.
// Errors can still occur when SendGrid tries to send the email. 
// If email is not received, use this URL to debug: https://app.sendgrid.com/email_activity 
Console.WriteLine(response.IsSuccessStatusCode ? "Email queued successfully!" : "Something went wrong!");
Enter fullscreen mode Exit fullscreen mode

Host.CreateDefaultBuilder(args).Build(); will use multiple configuration sources by default, but most importantly:

  • it will load configuration from appsettings.json if it exists
  • It will load configuration from .NET user secrets when the project runs with the environment set to "Development".

Read more about the default configuration sources at Microsoft Docs.

Create a new file named appsettings.json and add the following contents:

{
  "FromEmail": "[ENTER YOUR FROM EMAIL]",
  "FromName": "[ENTER YOUR FROM NAME]"
}

Enter fullscreen mode Exit fullscreen mode

This file will be used to configure the sender's email and name.

Using a JSON file as configuration works well to configure sender details, but is not a good fit for the API key. You can use user secrets for the API key.

Run the following command to initialize user secrets for your project:

dotnet user-secrets init
Enter fullscreen mode Exit fullscreen mode

Run the following command to set the API key as a user secret:

dotnet user-secrets set SendGridApiKey [PASTE IN YOUR SENDGRID API KEY]
Enter fullscreen mode Exit fullscreen mode

You can also set the sender email address as a user secret if you don't want to store your email address in the JSON file:

dotnet user-secrets set FromEmail [ENTER YOUR FROM EMAIL]
Enter fullscreen mode Exit fullscreen mode

The user secrets configuration will override the appsettings.json configuration.

As mentioned before, the user secrets will only be loaded when the environment is set as "Development". To do this, you can set an environment variable "DOTNET_ENVIRONMENT" to "Development". You can also pass it in as a command-line argument like this:

dotnet run --environment Development
Enter fullscreen mode Exit fullscreen mode

The result should be exactly the same, but your application configuration is very flexible now.

If you deploy this console application somewhere else, the configuration can be changed using environment variables, command-line arguments, and JSON files.

User secrets are a great way to store secrets and load them into your configuration with .NET. User secrets prevent you from accidentally checking in your secrets to source control by storing the secrets outside of your project source. It is important to note that these secrets are still stored in plain text, just elsewhere in your personal folder.

Bonus 3: Configure SendGridClient as a service for dependency injection

You've made your application more configurable using the default host builder, but you can also further integrate SendGrid into your application. The SendGrid SDK for .NET has an extra NuGet package that will add the SendGrid client to the dependency injection container.

This is most commonly used for ASP.NET, but as you can see, you can also use ASP.NET's great built-in features by manually adding them into your console applications.

Run the following command to add the SendGrid dependency injection package:

dotnet add package SendGrid.Extensions.DependencyInjection
Enter fullscreen mode Exit fullscreen mode

Update the Program.cs file:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SendGrid;
using SendGrid.Helpers.Mail;
using SendGrid.Extensions.DependencyInjection;

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) => services.AddSendGrid(options => 
        options.ApiKey = context.Configuration.GetValue<string>("SendGridApiKey")
    ))
    .Build();
var config = host.Services.GetRequiredService<IConfiguration>();

var apiKey = config.GetValue<string>("SendGridApiKey");
var fromEmail = config.GetValue<string>("FromEmail");
var fromName = config.GetValue<string>("FromName");
if(string.IsNullOrEmpty(apiKey)) throw new Exception("SendGridApiKey should not be null or empty");
if(string.IsNullOrEmpty(fromEmail)) throw new Exception("FromEmail should not be null or empty");
if(string.IsNullOrEmpty(fromName)) throw new Exception("FromName should not be null or empty");

Console.Write("To: ");
var toEmail = Console.ReadLine();

Console.Write("Subject: ");
var subject = Console.ReadLine();

Console.Write("Body: ");
var body = Console.ReadLine();

var client = host.Services.GetRequiredService<ISendGridClient>();
var msg = new SendGridMessage()
{
    From = new EmailAddress(fromEmail, fromName),
    Subject = subject,
    PlainTextContent = body
};
msg.AddTo(new EmailAddress(toEmail));
var response = await client.SendEmailAsync(msg);

// A success status code means SendGrid received the email request and will process it.
// Errors can still occur when SendGrid tries to send the email. 
// If email is not received, use this URL to debug: https://app.sendgrid.com/email_activity 
Console.WriteLine(response.IsSuccessStatusCode ? "Email queued successfully!" : "Something went wrong!");
Enter fullscreen mode Exit fullscreen mode

You can configure additional services inside of the lambda passed to ConfigureServices.

Inside of this lambda, SendGrid is added as a service. To configure the options of SendGrid, another lambda is used and passed into AddSendGrid. The lambda-inception can be tricky, so make sure to verify all your parentheses match the code above.

Instead of constructing the SendGridClient as you did before, the program now requests an instance of ISendGridClient from the dependency injection container using host.Services.GetRequiredService<ISendGridClient>().

If you extend this application even further, you can also use constructor injection to receive any service.

Run the application again to verify everything still works as expected:

dotnet run --environment Development
Enter fullscreen mode Exit fullscreen mode

Conclusion

Twilio SendGrid helps you send and receive emails at scale.

You learned how to send emails using the SendGrid API and .NET 6 by following these steps:

  • You verified your email address as a single sender to send emails from.
  • You created a SendGrid API Key with permission to send emails
  • You created a .NET 6 console application and integrated the SendGrid .NET SDK to send emails
  • You used the default host builder to set up flexible configuration and extensible dependency injection.

Using what you learned here, you can also start integrating SendGrid into your ASP.NET Core applications. Twilio has a lot of other products you can integrate. Check out this tutorial on how to receive text messages using Twilio Programmable SMS and forward them using SendGrid emails with C# and ASP.NET Core.

Additional resources

Check out the following resources for more information on the topics and tools presented in this tutorial:

SendGrid .NET SDK source code on GitHub – The SendGrid .NET SDK you used in this tutorial is open source! This GitHub repository contains helpful documentation on how to integrate with SendGrid using .NET. You can read the source code to better understand what's happening or submit issues if something isn't working as expected.

Configure Console app on Microsoft Docs – Learn how to configure .NET console applications using the host builder. You can further improve on the existing code by introducing the Options pattern described in the documentation.

Source Code to this tutorial on GitHub - Use this source code if you run into any issues, or submit an issue on this GitHub repo if you run into problems.

Niels Swimberghe is a Belgian software engineer and technical content creator at Twilio, working from the United States. Get in touch with Niels on Twitter @RealSwimburger and follow Niels’ personal blog on .NET, Azure, and web development at swimburger.net.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .