Email service abstraction with template rendering. Covers IEmailService interface, SendGrid/SES integration, HTML templates, and queue-based sending. Trigger: email, notification, SendGrid, SES, template, SMTP.
From dotnet-ai-kitnpx claudepluginhub faysilalshareef/dotnet-ai-kit --plugin dotnet-ai-kitThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
IEmailService abstracts email sending from provider implementationnamespace {Company}.{Domain}.Application.Interfaces;
public interface IEmailService
{
Task SendAsync(EmailMessage message, CancellationToken ct = default);
Task SendTemplatedAsync(string templateName, object model,
string toEmail, string? toName = null, CancellationToken ct = default);
}
public sealed record EmailMessage(
string ToEmail,
string ToName,
string Subject,
string HtmlBody,
string? PlainTextBody = null);
namespace {Company}.{Domain}.Infrastructure.Email;
public sealed class SendGridEmailService(
IOptions<EmailOptions> options,
ILogger<SendGridEmailService> logger) : IEmailService
{
private readonly SendGridClient _client = new(options.Value.ApiKey);
public async Task SendAsync(EmailMessage message, CancellationToken ct)
{
var msg = new SendGridMessage
{
From = new EmailAddress(options.Value.FromEmail, options.Value.FromName),
Subject = message.Subject,
HtmlContent = message.HtmlBody,
PlainTextContent = message.PlainTextBody
};
msg.AddTo(new EmailAddress(message.ToEmail, message.ToName));
var response = await _client.SendEmailAsync(msg, ct);
if (!response.IsSuccessStatusCode)
{
var body = await response.Body.ReadAsStringAsync(ct);
logger.LogError("SendGrid error: {Status} {Body}",
response.StatusCode, body);
}
}
public async Task SendTemplatedAsync(string templateName, object model,
string toEmail, string? toName, CancellationToken ct)
{
var template = await LoadTemplateAsync(templateName);
var html = RenderTemplate(template, model);
var subject = ExtractSubject(template, model);
await SendAsync(new EmailMessage(toEmail, toName ?? "", subject, html), ct);
}
private static string RenderTemplate(string template, object model)
{
var result = template;
foreach (var prop in model.GetType().GetProperties())
{
var value = prop.GetValue(model)?.ToString() ?? "";
result = result.Replace($"{{{{{prop.Name}}}}}", value);
}
return result;
}
}
public sealed class EmailOptions
{
public const string SectionName = "Email";
[Required]
public string Provider { get; init; } = "SendGrid"; // SendGrid, SES, SMTP
[Required]
public string ApiKey { get; init; } = string.Empty;
[Required, EmailAddress]
public string FromEmail { get; init; } = string.Empty;
public string FromName { get; init; } = "{Company}";
}
templates/
order-confirmation.html
welcome.html
password-reset.html
<!-- templates/order-confirmation.html -->
<html>
<body>
<h1>Order Confirmation</h1>
<p>Dear {{CustomerName}},</p>
<p>Your order #{{OrderNumber}} has been confirmed.</p>
<p>Total: {{Total}}</p>
</body>
</html>
services.AddOptions<EmailOptions>()
.BindConfiguration(EmailOptions.SectionName)
.ValidateDataAnnotations()
.ValidateOnStart();
services.AddScoped<IEmailService, SendGridEmailService>();
| Anti-Pattern | Correct Approach |
|---|---|
| Direct SendGrid calls in handlers | Use IEmailService abstraction |
| Synchronous email sending in request | Fire-and-forget via background job |
| Hardcoded email content | Use HTML templates with placeholders |
| Missing error handling | Log failures, don't throw to caller |
# Find email service
grep -r "IEmailService\|EmailService" --include="*.cs" src/
# Find SendGrid/SES
grep -r "SendGrid\|SES\|SmtpClient" --include="*.cs" src/
# Find email templates
find . -name "*.html" -path "*/templates/*"
IEmailService — extend, don't replace