Receber por email
← Voltar para o catálogo

dotnet-email-service-aws-ses

Implements email service using AWS SES for .NET APIs. Designed for applications with HTML template support, placeholder replacement, and Result pattern error handling.

66estrelas
Atualizado há 5 meses

Ver no GitHub ↗

Como adicionar

/plugin marketplace add ronnythedev/dotnet-clean-architecture-skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/dotnet-email-service-aws-ses/svg)](https://www.skillteca.com.br/skills/dotnet-email-service-aws-ses)

Skills relacionadas

Ver todas de Desenvolvimento →

Alerta por categoria

Receba novas skills de Desenvolvimento toda segunda

1 email curto, só com as skills novas de Desenvolvimento. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

AWS SES Email Service

Overview

This skill implements email delivery via AWS SES for APIs:

  • AWS SES Integration - Production-ready email delivery
  • HTML Templates - File-based templates with placeholder replacement
  • Result Pattern - No exceptions, returns Result<T> for error handling
  • Enable/Disable Toggle - Development mode without actual sending

Quick Reference

| Component | Purpose | Location | |-----------|---------|----------| | IEmailService | Email abstraction interface | Application/Abstractions/Email | | AwsSesEmailService | AWS SES implementation | Infrastructure/Email | | EmailOptions | AWS SES configuration | Infrastructure/Email | | EmailErrors | Error definitions | Application/Abstractions/Email |

Email Structure

/Application/Abstractions/
├── Email/
│   ├── IEmailService.cs
│   └── EmailErrors.cs

/Infrastructure/
├── Email/
│   ├── EmailOptions.cs
│   └── AwsSesEmailService.cs

/Api/
├── EmailTemplates/
│   ├── appointment-reminder.html
│   ├── appointment-reminder-es.html
│   ├── test-results-ready.html
│   ├── prescription-ready.html
│   ├── welcome.html
│   └── password-reset.html

Template: Email Service Interface

// src/{name}.application/Abstractions/Email/IEmailService.cs
using {name}.domain.abstractions;

namespace {name}.application.Abstractions.Email;

/// <summary>
/// Service for sending emails via AWS SES
/// Returns Result pattern for error handling (no exceptions)
/// </summary>
public interface IEmailService
{
    /// <summary>
    /// Send an email using a template file with placeholder replacements
    /// </summary>
    /// <param name="toEmail">Recipient email address</param>
    /// <param name="subject">Email subject</param>
    /// <param name="templateName">Name of the template file (without extension)</param>
    /// <param name="placeholders">Dictionary of placeholder keys and replacement values</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>Result indicating success or failure</returns>
    Task<r> SendTemplatedEmailAsync(
        string toEmail,
        string subject,
        string templateName,
        Dictionary<string, string> placeholders,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// Send an email with raw HTML content
    /// </summary>
    /// <param name="toEmail">Recipient email address</param>
    /// <param name="subject">Email subject</param>
    /// <param name="htmlBody">HTML content of the email</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>Result indicating success or failure</returns>
    Task<r> SendHtmlEmailAsync(
        string toEmail,
        string subject,
        string htmlBody,
        CancellationToken cancellationToken = default);
}

Template: Email Errors

// src/{name}.application/Abstractions/Email/EmailErrors.cs
using {name}.domain.abstractions;

namespace {name}.application.Abstractions.Email;

public static class EmailErrors
{
    public static readonly Error SendFailed = new(
        "Email.SendFailed",
        "Failed to send email. Please try again later.");

    public static readonly Error TemplateNotFound = new(
        "Email.TemplateNotFound",
        "Email template not found.");

    public static readonly Error InvalidRecipient = new(
        "Email.InvalidRecipient",
        "Invalid recipient email address.");

    public static readonly Error EmailDisabled = new(
        "Email.Disabled",
        "Email sending is currently disabled.");
}

Template: Email Options

// src/{name}.infrastructure/Email/EmailOptions.cs
namespace {name}.infrastructure.Email;

public sealed class EmailOptions
{
    public const string SectionName = "Email";

    /// <summary>
    /// AWS region for SES (e.g., "us-east-1")
    /// </summary>
    public string AwsRegion { get; init; } = "us-east-1";

    /// <summary>
    /// AWS access key ID (optional - use IAM role in production)
    /// </summary>
    public string? AwsAccessKeyId { get; init; }

    /// <summary>
    /// AWS secret access key (optional - use IAM role in production)
    /// </summary>
    public string? AwsSecretAccessKey { get; init; }

    /// <summary>
    /// Email address to send from
    /// </summary>
    public string FromAddress { get; init; } = string.Empty;

    /// <summary>
    /// Display name for the sender (e.g., "Support Team")
    /// </summary>
    public string FromName { get; init; } = string.Empty;

    /// <summary>
    /// Whether email sending is enabled (disable for development)
    /// </summary>
    public bool Enabled { get; init; } = false;

    /// <summary>
    /// Path to email templates directory (relative to app base)
    /// </summary>
    public string TemplatesPath { get; init; } = "EmailTemplates";
}

appsettings.json

{
  "Email": {
    "AwsRegion": "us-east-1",
    "AwsAccessKeyId": "",
    "AwsSecretAccessKey": "",
    "FromAddress": "noreply@healthcare.example.com",
    "FromName": "Supoort Team",
    "Enabled": true,
    "TemplatesPath": "EmailTemplates"
  }
}

Template: AWS SES Email Service Implementation

// src/{name}.infrastructure/Email/AwsSesEmailService.cs
using Amazon;
using Amazon.SimpleEmailV2;
using Amazon.SimpleEmailV2.Model;
using {name}.application.Abstractions.Email;
using {name}.domain.abstractions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace {name}.infrastructure.Email;

internal sealed class AwsSesEmailService : IEmailService
{
    private readonly EmailOptions _options;
    private readonly ILogger<AwsSesEmailService> _logger;
    private readonly IAmazonSimpleEmailServiceV2 _sesClient;
    private readonly string _templatesPath;

    public AwsSesEmailService(
        IOptions<EmailOptions> options,
        ILogger<AwsSesEmailService> logger)
    {
        _options = options.Value;
        _logger = logger;

        // Initialize SES v2 client
        var region = RegionEndpoint.GetBySystemName(_options.AwsRegion);

        if (!string.IsNullOrEmpty(_options.AwsAccessKeyId) &&
            !string.IsNullOrEmpty(_options.AwsSecretAccessKey))
        {
            // Use explicit credentials (dev/staging)
            _sesClient = new AmazonSimpleEmailServiceV2Client(
                _options.AwsAccessKeyId,
                _options.AwsSecretAccessKey,
                region);
        }
        else
        {
            // Use IAM role or environment credentials (production)
            _sesClient = new AmazonSimpleEmailServiceV2Client(region);
        }

        // Set templates path relative to application base directory
        _templatesPath = Path.Combine(
            AppDomain.CurrentDomain.BaseDirectory, 
            _options.TemplatesPath);
    }

    public async Task<r> SendTemplatedEmailAsync(
        string toEmail,
        string subject,
        string templateName,
        Dictionary<string, string> placeholders,
        CancellationToken cancellationToken = default)
    {
        // Load template file
        var templatePath = Path.Combine(_templatesPath, $"{templateName}.html");

        if (!File.Exists(templatePath))
        {
            _logger.LogError("Email template not found: {TemplatePath}", templatePath);
            return Result.Failure(EmailErrors.TemplateNotFound);
        }

        var htmlBody = await File.ReadAllTextAsync(templatePath, cancellationToken);

        // Replace placeholders using {{key}} syntax
        foreach (var (key, value) in placeholders)
        {
            htmlBody = htmlBody.Replace($"{{{{{key}}}}}", value);
        }

        return await SendHtmlEmailAsync(toEmail, subject, htmlBody, cancellationToken);
    }

    public async Task<r> SendHtmlEmailAsync(
        string toEmail,
        string subject,
        string htmlBody,
        CancellationToken cancellati
Compartilhar X LinkedIn