StrongGrid
Release Notes | NuGet (stable) | MyGet (prerelease) |
---|
| | |
About
StrongGrid is a strongly typed library for SendGrid's v3 API.
It started out in February 2016 as a fork of SendGrid's own library. At the time, the SendGrid C# client for their API extensively used the dynamic
type which was very inconvenient and made it very difficult for developers. Furthermore, their C# client only covered the mail
end point but did not allow access to other end points in their email marketing
API such as creating lists and segments, importing contacts, etc. I submited a pull request to SendGrid in March 2016 but it was not accepted and eventually closed in June 2016.
In October 2016 I decided to release this library as a nuget package since SendGrid's library was still using dynamic
and lacking strong typing. As of February 14, 2017 dynamic
was removed from SendGrid's official csharp library and support for .Net Standard was added.
StrongGrid includes a client that allows you to interact with all the "resources" in the SendGrid API (e.g.: send an email, manage lists, contacts and segments, search for contacts matching criteria, create API keys, etc.).
StrongGrid also includes a parser for webhook sent from SendGrid to your own WebAPI. This parser supports the two types of webhooks that SendGrid can post to your API: the Event Webhook and the Inbound Parse Webhook.
Since November 2017, StrongGrid also includes a "warmup engine" that allows you to warmup IP addresses using a custom schedule.
If you need information about how to setup the SendGrid webhooks, please consult the following resources:
Installation
The easiest way to include StrongGrid in your C# project is by adding the nuget package to your project:
PM> Install-Package StrongGrid
Once you have the StrongGrid library properly referenced in your project, add the following namespace:
using StrongGrid;
.NET framework suport
StrongGrid supports the 4.6.1
.NET framework as well as .NET Core
.
Usage
Client
You declare your client variable like so:
var apiKey = "... your api key...";
var client = new Client(apiKey);
If you need to use a proxy, you can pass it to the Client:
var apiKey = "... your api key...";
var proxy = new WebProxy("http://myproxy:1234");
var client = new Client(apiKey, proxy);
One of the most common scenarios is to send transactional emails.
Here are a few examples:
var messageId = await client.Mail.SendToSingleRecipientAsync(to, from, subject, html, text).ConfigureAwait(false);
var messageId = await client.Mail.SendToMultipleRecipientsAsync(new[] { to1, to2, to3 }, from, subject, html, text).ConfigureAwait(false);
var attachments = new[]
{
Attachment.FromLocalFile(@"C:\MyDocuments\MySpreadsheet.xlsx"),
Attachment.FromLocalFile(@"C:\temp\Headshot.jpg")
};
var messageId = await client.Mail.SendToSingleRecipientAsync(to, from, subject, html, text, attachments: attachments).ConfigureAwait(false);
You have access to numerous 'resources' (such as Contacts, Lists, Segments, Settings, SenderAuthentication, etc) off of the Client and each resource offers several methods to such as retrieve, create, update, delete, etc.
Here are a few example:
var contactId = await client.Contacts.CreateAsync(email, firstName, lastName, customFields);
await client.Mail.SendToSingleRecipientAsync(to, from, subject, htmlContent, textContent);
var apiKeys = await client.ApiKeys.GetAllAsync();
await client.Suppressions.AddAddressToUnsubscribeGroupAsync(groupId, "test1@example.com");
var globalStats = await client.Statistics.GetGlobalStatisticsAsync(startDate, endDate);
var template = await client.Templates.CreateAsync("My template");
Dynamic templates
In August 2018, SendGrid released a new feature in their API that allows you to use the Handlebars syntax to specify merge fields in your content. Using this powerfull new feature in StrongGrid is very easy.
First, you must specify TemplateType.Dynamic
when creating a new template like in this example:
var dynamicTemplate = await client.Templates.CreateAsync("My dynamic template", TemplateType.Dynamic).ConfigureAwait(false);
Second, you create a version of your content where you use the Handlebars syntax to define the merge fields and you can also specify an optional "test data" that will be used by the SendGrid UI to show you a sample. Rest assured that this test data will never be sent to any recipient. The following code sample demonstrates creating a dynamic template version containing simple substitution for CreditBalance
, deep object replacements for Customer.first_name
and Customer.last_name
and an iterator that displays information about multiple orders.
var subject = "Dear {{Customer.first_name}}";
var htmlContent = @"
<html>
<body>
Hello {{Customer.first_name}} {{Customer.last_name}}.
You have a credit balance of {{CreditBalance}}<br/>
<ol>
{{#each Orders}}
<li>You ordered: {{this.item}} on: {{this.date}}</li>
{{/each}}
</ol>
</body>
</html>";
var textContent = "... this is the text content ...";
var testData = new
{
Customer = new
{
first_name = "aaa",
last_name = "aaa"
},
CreditBalance = 99.88,
Orders = new[]
{
new { item = "item1", date = "1/1/2018" },
new { item = "item2", date = "1/2/2018" },
new { item = "item3", date = "1/3/2018" }
}
};
await client.Templates.CreateVersionAsync(dynamicTemplate.Id, "Version 1", subject, htmlContent, textContent, true, EditorType.Code, testData).ConfigureAwait(false);
Finally, you can send an email to a recipient and specify the dynamic data that applies to them like so:
var dynamicData = new
{
Customer = new
{
first_name = "Bob",
last_name = "Smith"
},
CreditBalance = 56.78,
Orders = new[]
{
new { item = "shoes", date = "2/1/2018" },
new { item = "hat", date = "1/4/2018" }
}
};
var to = new MailAddress("bobsmith@hotmail.com", "Bob Smith");
var from = new MailAddress("test@example.com", "John Smith");
var messageId = await client.Mail.SendToSingleRecipientAsync(to, from, dynamicTemplate.Id, dynamicData).ConfigureAwait(false);
Parser
Here's a basic example of an API controller which parses the webhook from SendGrid into an array of Events:
namespace WebApplication1.Controllers
{
[Route("api/SendGridWebhooks")]
public class SendGridController : Controller
{
[HttpPost]
[Route("Events")]
public async Task<IActionResult> ReceiveEvents()
{
var parser = new WebhookParser();
var events = await parser.ParseWebhookEventsAsync(Request.Body).ConfigureAwait(false);
... do something with the events ...
return Ok();
}
}
}
Here's a basic example of an API controller which parses the webhook from SendGrid into an InboundEmail:
namespace WebApplication1.Controllers
{
[Route("api/SendGridWebhooks")]
public class SendGridController : Controller
{
[HttpPost]
[Route("InboundEmail")]
public IActionResult ReceiveInboundEmail()
{
var parser = new WebhookParser();
var inboundEmail = parser.ParseInboundEmailWebhook(Request.Body);
... do something with the inbound email ...
return Ok();
}
}
}
Warmup Engine
SendGrid already provides a way to warm up ip addresses but you have no control over this process. StrongGrid solves this issue by providing you a warmup engine that you can tailor to your needs.
Typical usage
var poolName = "warmup_pool";
var dailyVolumePerIpAddress = new[] { 50, 100, 500, 1000 };
var resetDays = 1;
var warmupSettings = new WarmupSettings(poolName, dailyVolumePerIpAddress, resetDays);
var warmupEngine = new WarmupEngine(warmupSettings, client);
var ipAddresses = new[] { "168.245.123.132", "168.245.123.133" };
await warmupEngine.PrepareWithExistingIpAddressesAsync(ipAddresses, CancellationToken.None).ConfigureAwait(false);
var result = warmupEngine.SendToSingleRecipientAsync(...);
var result = warmupEngine.SendToMultipleRecipientsAsync(...);
var result = warmupEngine.SendAsync(...);
The Send...
methods return a WarmupResult
object that will tell you whether the process is completed or not, and will also give you the messageId of the email sent using the IP pool (if applicable) and the messageId of the email sent using the default IP address (which is not being warmed up).
The WarmupEngine will send emails using the IP pool until the daily volume limit is achieved and any remaining email will be sent using the default IP address.
As you get close to your daily limit, it's possible that the Warmup engine may have to split a given "send" into two messages: one of which is sent using the ip pool and the other one sent using the default ip address.
Let's use an example to illustrate: let's say that you have 15 emails left before you reach your daily warmup limit and you try to send an email to 20 recipients. In this scenario the first 15 emails will be sent using the warmup ip pool and the remaining 5 emails will be sent using the default ip address.
More advanced usage
Recommended daily volume: If you are unsure what daily limits to use, SendGrid has provided a recommended schedule and StrongGrid provides a convenient method to use the recommended schedule tailored to the number of emails you expect to send in a typical day.
All you have to do is come up with a rough estimate of your daily volume and StrongGrid can configure the appropriate warmup settings.
Here's an example:
var poolName = "warmup_pool";
var estimatedDailyVolume = 50000;
var resetDays = 1;
var warmupSettings = WarmupSettings.FromSendGridRecomendedSettings(poolName, estimatedDailyVolume, resetDays);
Progress repository: By default StrongGrid's WarmupEngine will write progress information in a file on your computer's temp
folder but you can override this settings.
You can change the folder where this file is saved but you can also decide to use a completely different repository. Out of the box, StrongGrid provides FileSystemWarmupProgressRepository
and MemoryWarmupProgressRepository
.
It also provides an interface called IWarmupProgressRepository
which allows you to write your own implementation to save the progress data to a location more suitable to you such as a database, Azure, AWS, etc.
Please note that MemoryWarmupProgressRepository
in intended to be used for testing and we don't recommend using it in production. The main reason for this recommendation is that the data is stored in memory and it's lost when your computer is restarted.
This means that your warmup process would start all over from day 1 each time you computer is rebooted.
var warmupProgressRepository = new MemoryWarmupProgressRepository();
var warmupProgressRepository = new FileSystemWarmupProgressRepository();
var warmupProgressRepository = new FileSystemWarmupProgressRepository(@"C:\temp\myfolder\");
var warmupEngine = new WarmupEngine(warmupSettings, client, warmupProgressRepository);
Purchase new IP Addresses: You can purchase new IP addresses using SendGrid' UI, but StrongGrid's WarmupEngine makes it even easier.
Rather than invoking PrepareWithExistingIpAddressesAsync
(as demonstrated previously), you can invoke PrepareWithNewIpAddressesAsync
and StrongGrid will take care of adding new ip addresses to your account and add them to a new IP pool ready for warmup.
As a reminder, please note that the PrepareWithExistingIpAddressesAsync
and PrepareWithNewIpAddressesAsync
should only be invoked once.
Invoking either method a second time would result in an exception due to the fact that the IP pool has already been created.
var howManyAddresses = 2;
var subusers = new[] { "your_subuser" };
await warmupEngine.PrepareWithNewIpAddressesAsync(howManyAddresses, subusers, CancellationToken.None).ConfigureAwait(false);
End of warmup process: When the process is completed, the IP pool is deleted and the warmed up IP address(es) are returned to the default pool. You can subsequently invoke the client.Mail.SendAsync(...)
method to send your emails.
License