AWS SES email provider

Amazon SES provider that implements email.ProviderPort against the SES API through the AWS SDK for Go v2.

Overview

SES is the AWS email service. It runs cheap per-message and authenticates through IAM. NewSESProvider returns email.ProviderPort, which is the type WithEmailProvider consumes. The provider slots into the bootstrap with no glue code.

The provider uses the AWS SDK for Go v2 with the standard credential chain (environment, shared config, EC2/ECS/Lambda role, IAM Identity Centre). On any AWS-hosted runtime it needs no static keys. Leave AWSKey and AWSSecret empty and the chain supplies credentials. Pass static keys only when the chain is unavailable.

Callers never pick an API. The provider sends through SendEmail for plain messages and switches to SendRawEmail with a built MIME message when the email carries attachments.

NewSESProvider returns an error when FromEmail is empty, so a misconfigured provider fails at construction, not at the first send. The provider is pure Go with no build tags or CGO, so it runs in any mode, including interpreted dev-i.

SES pins to a region. Emails sent through us-east-1 and emails sent through eu-west-1 operate as independent SES installations with separate verified identities, suppression lists, and reputation. Pick the region closest to your recipients.

The provider emits OpenTelemetry metrics for send attempts and durations (email.provider.ses.send.total and email.provider.ses.send.duration), each labelled with status and send_type. All methods are safe for concurrent use.

A built-in client-side rate limiter caps throughput at 50 calls per second with a burst of 100. Send blocks on the limiter before each call to keep the provider within the SES quota. This default applies to every send, including the per-message loop behind SendBulk.

Requirements

  • An AWS account with SES enabled in the chosen region. New accounts start in the SES sandbox (verified senders only). Request production access in the SES console before going live.
  • A verified sender identity matching FromEmail, either a verified email address (sandbox) or a verified domain (production).
  • IAM credentials with ses:SendEmail and ses:SendRawEmail permissions. Provide them through the standard AWS chain, or set both AWSKey and AWSSecret for static credentials. Static keys apply only when you set both fields. Supplying one alone falls back to the chain.
  • Network egress to the region's SES endpoint (for example email.eu-west-1.amazonaws.com).

Configuration

import (
    "context"

    "piko.sh/piko/wdk/email/email_provider_ses"
)

provider, err := email_provider_ses.NewSESProvider(ctx, email_provider_ses.SESProviderArgs{
    Region:    "eu-west-1",            // empty = AWS SDK default region resolution
    FromEmail: "[email protected]",  // required; must be a verified identity
    AWSKey:    "",                     // optional; leave empty to use the credential chain
    AWSSecret: "",                     // optional; pair with AWSKey for static credentials
})
if err != nil {
    return err
}

For local testing against a LocalStack-hosted SES, set AWSLocalEndpoint to the LocalStack endpoint URL.

To wire the provider into an existing email service without holding the value yourself, call email_provider_ses.Register(ctx, emailService, args). It builds the provider and registers it under the name ses. The trailing variadic options are func(*SESProviderArgs) mutators that adjust the args before construction.

Bootstrap

ssr := piko.New(
    piko.WithEmailProvider("ses", provider),
    piko.WithDefaultEmailProvider("ses"),
)

Bulk sending

SES has no native bulk send for discrete messages, so SupportsBulkSending reports false. SendBulk loops over the batch and calls Send for each message, subject to the same rate limiter. It collects every failure into a MultiError and returns it once the batch finishes. There is no single API call and no atomic batch.

Tradeoffs

The SES dashboard is sparse compared to dedicated email service providers. It has no built-in marketing-list management, no behavioural analytics, and no template editor. SES sends messages and exposes delivery events through other AWS services (CloudWatch, SNS, EventBridge). The rest falls to your own tooling. Teams that need both transactional and marketing mail typically pair SES with a separate marketing tool.

See also

Other email providers:

  • SendGrid, combined transactional and marketing.
  • Postmark, transactional-only, fast delivery.
  • Mailgun, strong EU presence, flexible routing rules.
  • Mailchimp Transactional, the former Mandrill.
  • SMTP, generic backend for self-hosted or vendor-neutral relays.
  • Gmail, Gmail SMTP with app passwords (dev / low-volume).

Framework docs:

External: