Skip to main content
Version: v1.0.6

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)
WebhookUrlstring—URL for event webhooks
TrackingSettingsstring—JSON 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("noreply@yourdomain.com")
.ToEmail("user@example.com")
.WithText("Welcome to the app!")
.WithSubject("Welcome!")
.Build();

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

HTML email​

new MessageBuilder()
.FromEmail("noreply@yourdomain.com")
.ToEmail("user@example.com")
.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("noreply@yourdomain.com")
.ToEmail("user@example.com")
.WithContent(multipart)
.WithSubject("Verify your email")
.Build();

Email with attachment​

new MessageBuilder()
.FromEmail("noreply@yourdomain.com")
.ToEmail("user@example.com")
.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("noreply@yourdomain.com")
.ToEmail("user@example.com")
.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