PollySendGrid 1.0.0
dotnet add package PollySendGrid --version 1.0.0
NuGet\Install-Package PollySendGrid -Version 1.0.0
<PackageReference Include="PollySendGrid" Version="1.0.0" />
<PackageVersion Include="PollySendGrid" Version="1.0.0" />
<PackageReference Include="PollySendGrid" />
paket add PollySendGrid --version 1.0.0
#r "nuget: PollySendGrid, 1.0.0"
#:package PollySendGrid@1.0.0
#addin nuget:?package=PollySendGrid&version=1.0.0
#tool nuget:?package=PollySendGrid&version=1.0.0
PollySendGrid
Polly v8 resilience for SendGrid — add retry, timeout, and circuit-breaker to any email send in two lines.
var client = new SendGridClient(apiKey);
var resilient = client.WithPolly(pipeline => pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(2),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
ShouldHandle = SendGridTransientErrors.IsTransient,
})
.AddTimeout(TimeSpan.FromSeconds(30)));
var response = await resilient.SendEmailAsync(msg);
Why PollySendGrid?
SendGrid imposes rate limits and occasionally returns transient errors. Dropped emails mean missed notifications, failed password resets, and lost revenue. This library wraps the response check in Polly v8 so every transient error is retried automatically:
| Problem | Solution |
|---|---|
| HTTP 429 rate limit exceeded | Auto-thrown as SendGridTransientException and retried |
| HTTP 500 transient server error | Auto-thrown as SendGridTransientException and retried |
| HTTP 503 service unavailable | Auto-thrown as SendGridTransientException and retried |
HttpRequestException network failure |
Caught by SendGridTransientErrors.IsTransient |
| Cascading failures during an outage | Wrap with AddCircuitBreaker |
Installation
dotnet add package PollySendGrid
dotnet add package Polly.Core
Quick-start
1. Manual wiring
var client = new SendGridClient(apiKey);
var resilient = client.WithPolly(p => p
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(2),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
ShouldHandle = SendGridTransientErrors.IsTransient,
}));
var msg = MailHelper.CreateSingleEmail(from, to, subject, plainText, htmlContent);
var response = await resilient.SendEmailAsync(msg);
2. Dependency injection
builder.Services.AddPollySendGrid(apiKey, pipeline => pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(2),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
ShouldHandle = SendGridTransientErrors.IsTransient,
})
.AddTimeout(TimeSpan.FromSeconds(30)));
public class EmailService(ResilientSendGridClient client)
{
public Task<Response> SendAsync(SendGridMessage msg, CancellationToken ct)
=> client.SendEmailAsync(msg, ct);
}
Transient error reference
| Condition | Why it's transient |
|---|---|
SendGridTransientException (HTTP 429) |
Rate limit — back off and retry |
SendGridTransientException (HTTP 500) |
Transient server error |
SendGridTransientException (HTTP 503) |
Service maintenance or overload |
HttpRequestException |
Network failure |
Note:
SendGridTransientExceptionis thrown automatically byResilientSendGridClientwhen the response status code is inSendGridTransientErrors.StatusCodes. You do not throw it yourself.
API reference
| Member | Description |
|---|---|
ResilientSendGridClient.Inner |
The underlying ISendGridClient |
SendEmailAsync(msg, ct) |
Sends an email through the pipeline |
ExecuteAsync<T>(operation, ct) |
Runs any ISendGridClient operation through the pipeline |
SendGridTransientErrors.IsTransient |
PredicateBuilder for 429/500/503 + HttpRequestException |
SendGridTransientErrors.StatusCodes |
IReadOnlySet<HttpStatusCode> — TooManyRequests, InternalServerError, ServiceUnavailable |
client.WithPolly(pipeline) |
Wraps ISendGridClient with a pre-built pipeline |
client.WithPolly(configure) |
Builds pipeline inline and wraps the client |
services.AddPollySendGrid(configure) |
DI registration (requires ISendGridClient in DI) |
services.AddPollySendGrid(apiKey, configure) |
DI registration with API key shortcut |
Target frameworks
.NET 6 ✅ · .NET 8 ✅ · .NET 9 ✅
Related packages
| Package | Description |
|---|---|
| PollyAzureBlob | Polly v8 for Azure Blob Storage |
| PollyAzureServiceBus | Polly v8 for Azure Service Bus |
| PollyAzureKeyVault | Polly v8 for Azure Key Vault |
| PollyAzureEventHub | Polly v8 for Azure Event Hubs |
| PollyCosmosDb | Polly v8 for Azure Cosmos DB |
| PollyElasticsearch | Polly v8 for Elasticsearch |
| PollyRedis | Polly v8 for StackExchange.Redis |
| PollyEFCore | Polly v8 for Entity Framework Core |
| PollyDapper | Polly v8 for Dapper |
| PollyMongo | Polly v8 for MongoDB |
| PollyNpgsql | Polly v8 for Npgsql (PostgreSQL) |
| PollySqlClient | Polly v8 for Microsoft.Data.SqlClient |
| PollyGrpc | Polly v8 for gRPC |
| PollyRabbitMQ | Polly v8 for RabbitMQ |
| PollyKafka | Polly v8 for Confluent.Kafka |
| PollySignalR | Polly v8 for SignalR |
| PollyOpenAI | Polly v8 for OpenAI .NET SDK |
| PollyMediatR | Polly v8 for MediatR |
| PollyHealthChecks | Polly v8 for ASP.NET Core Health Checks |
| PollyBackoff | Polly v8 backoff helpers |
License
MIT © Justin Bannister
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net6.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Polly.Core (>= 8.7.0)
- SendGrid (>= 9.29.3)
-
net8.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Polly.Core (>= 8.7.0)
- SendGrid (>= 9.29.3)
-
net9.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Polly.Core (>= 8.7.0)
- SendGrid (>= 9.29.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 77 | 6/24/2026 |
1.0.0: Initial release. ResilientSendGridClient wraps ISendGridClient in a Polly v8 ResiliencePipeline. Automatically throws SendGridTransientException for 429, 500, and 503 responses so Polly can retry them. Supports net6.0, net8.0, and net9.0.