Skip to main content

SendGrid Email Connector

Transactional and bulk email via the SendGrid v3 API.

Package

dotnet add package Ratatosk.Sendgrid

Required settings

ParameterTypeDescription
ApiKeystringSendGrid API key (starts with SG.)

Optional settings

ParameterTypeDefaultDescription
SandboxModeboolfalseWhen true, no email is actually sent (for testing)
WebhookUrlstringURL for event webhooks
TrackingSettingsstringJSON with click/open tracking settings

Schema

PropertyValue
ProviderSendGrid
TypeEmail
Version1.1.0
CapabilitiesSendMessages, BulkMessaging, Templates, HealthCheck
Content typesPlainText, Html, Multipart, Template
EndpointsEmailAddress (send + receive)
AuthenticationAPI Key

Send examples

Plain text email

var settings = new ConnectionSettings()
.SetParameter("ApiKey", "SG...");

var connector = new SendGridEmailConnector(SendGridChannelSchemas.SendGridEmail, settings);
await connector.InitializeAsync(ct);

var email = new MessageBuilder()
.WithId("email-1")
.FromEmail("[email protected]")
.ToEmail("[email protected]")
.WithText("Welcome to the app!")
.WithSubject("Welcome!")
.Build();

var result = await connector.SendMessageAsync(email, ct);

HTML email

new MessageBuilder()
.FromEmail("[email protected]")
.ToEmail("[email protected]")
.WithHtml("<h1>Welcome!</h1><p>Thanks for signing up, <b>{{name}}</b>.</p>")
.WithSubject("Welcome!")
.Build();

Multipart email (text + HTML)

var multipart = new MultipartContent();
multipart.Parts.Add(new TextContent("Welcome to the app! Please verify your email."));
multipart.Parts.Add(new HtmlContent(
"<h1>Welcome!</h1><p>Please <a href='{{link}}'>verify your email</a>.</p>"));

new MessageBuilder()
.FromEmail("[email protected]")
.ToEmail("[email protected]")
.WithContent(multipart)
.WithSubject("Verify your email")
.Build();

Email with attachment

new MessageBuilder()
.FromEmail("[email protected]")
.ToEmail("[email protected]")
.WithHtml("<p>Please find the attached report.</p>", html =>
{
html.Attachments.Add(new MessageAttachment(
"report", "report.pdf", "application/pdf", base64PdfContent));
})
.WithSubject("Monthly Report")
.Build();

Template email (SendGrid dynamic templates)

new MessageBuilder()
.FromEmail("[email protected]")
.ToEmail("[email protected]")
.WithContent(new TemplateContent("d-abc123def456", new Dictionary<string, object?>
{
["name"] = "Alice",
["verification_link"] = "https://example.com/verify?token=xyz"
}))
.WithSubject("Welcome!")
.Build();

Batch send

var batch = new MessageBatch();
batch.Messages.Add(email1);
batch.Messages.Add(email2);
batch.Messages.Add(email3);

var result = await connector.SendBatchAsync(batch, ct);
Console.WriteLine($"Batch sent: {result.Data?.BatchId}");

if (result.Data != null)
{
foreach (var (msgId, sendResult) in result.Data.MessageResults)
Console.WriteLine($" {msgId}: {sendResult.Status} ({sendResult.RemoteMessageId})");
}

Sandbox mode (testing)

new ConnectionSettings()
.SetParameter("ApiKey", "SG...")
.SetParameter("SandboxMode", true);

Message properties

PropertyTypeDescription
SubjectstringEmail subject line (required)
TrackingSettingsstringJSON string for click/open tracking configuration
ReplyTostringReply-to email address

Webhook handling

SendGrid posts event data (delivered, opened, clicked, bounced, spam reports) as JSON POST to your webhook URL:

[HttpPost("/webhooks/sendgrid")]
public async Task<IActionResult> SendGridWebhook(CancellationToken ct)
{
using var reader = new StreamReader(Request.Body);
var body = await reader.ReadToEndAsync(ct);
var source = MessageSource.Json(body);

var result = await _connector.ReceiveMessageStatusAsync(source, ct);
// Process status updates...

return Ok();
}

Validate X-Twilio-Email-Event-Webhook-Signature header when using signed webhooks.

Error codes

SendGrid-specific error codes are defined in SendGridErrorCodes with domain "SendGrid".

CodeDescription
INVALID_EMAIL_ADDRESSEmail address format is invalid
MISSING_EMAIL_CONTENTEmail content (subject, body) is missing

Standard MessagingErrorCodes are also used — see the error codes reference.

Original provider codes

SendGrid errors are mapped from HTTP status codes in the connector. There is no custom error code mapping from SendGrid API error codes. HTTP 429 Too Many Requests maps to RATE_LIMIT_EXCEEDED; all other non-success status codes map to SEND_MESSAGE_FAILED.

Troubleshooting

SymptomLikely causeFix
INVALID_CREDENTIALSAPI key is invalidGenerate a new API key in SendGrid UI
PROVIDER_VALIDATION_FAILEDInvalid sender emailVerify sender domain (SPF/DKIM setup)
Delivery not happeningSender not verifiedVerify sender email or domain in SendGrid
Emails going to spamPoor sender reputationCheck SendGrid reputation reports
Template not renderingTemplate ID wrongVerify template ID in SendGrid UI
Event webhooks not arrivingWebhook URL not configuredSubscribe to events in SendGrid Mail Settings

SendGridChannelSchemas

// Full email schema (send, bulk, templates)
SendGridChannelSchemas.SendGridEmail