Create AWS SES Configuration Sets

The aws:ses/configurationSet:ConfigurationSet resource, part of the Pulumi AWS provider, defines an SES configuration set that groups email sending settings and enables event tracking across multiple sending identities. This guide focuses on three capabilities: basic configuration set creation, TLS policy enforcement, and custom tracking domain setup.

Configuration sets work with SES sending identities and may reference custom domains for link tracking. The examples are intentionally small. Combine them with your own verified domains, event destinations, and monitoring setup.

Create a named configuration set

Most SES deployments start by creating a configuration set with a unique name to group email settings.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const test = new aws.ses.ConfigurationSet("test", {name: "some-configuration-set-test"});
import pulumi
import pulumi_aws as aws

test = aws.ses.ConfigurationSet("test", name="some-configuration-set-test")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ses"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := ses.NewConfigurationSet(ctx, "test", &ses.ConfigurationSetArgs{
			Name: pulumi.String("some-configuration-set-test"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var test = new Aws.Ses.ConfigurationSet("test", new()
    {
        Name = "some-configuration-set-test",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ses.ConfigurationSet;
import com.pulumi.aws.ses.ConfigurationSetArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var test = new ConfigurationSet("test", ConfigurationSetArgs.builder()
            .name("some-configuration-set-test")
            .build());

    }
}
resources:
  test:
    type: aws:ses:ConfigurationSet
    properties:
      name: some-configuration-set-test

The name property establishes a unique identifier for the configuration set. Without additional properties, the configuration set uses SES defaults: TLS is optional, reputation metrics are disabled, and sending is enabled. You’ll reference this name when sending emails or attaching event destinations.

Enforce TLS encryption for email delivery

Organizations with security requirements often mandate encrypted connections for all outbound email.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const test = new aws.ses.ConfigurationSet("test", {
    name: "some-configuration-set-test",
    deliveryOptions: {
        tlsPolicy: "Require",
    },
});
import pulumi
import pulumi_aws as aws

test = aws.ses.ConfigurationSet("test",
    name="some-configuration-set-test",
    delivery_options={
        "tls_policy": "Require",
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ses"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := ses.NewConfigurationSet(ctx, "test", &ses.ConfigurationSetArgs{
			Name: pulumi.String("some-configuration-set-test"),
			DeliveryOptions: &ses.ConfigurationSetDeliveryOptionsArgs{
				TlsPolicy: pulumi.String("Require"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var test = new Aws.Ses.ConfigurationSet("test", new()
    {
        Name = "some-configuration-set-test",
        DeliveryOptions = new Aws.Ses.Inputs.ConfigurationSetDeliveryOptionsArgs
        {
            TlsPolicy = "Require",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ses.ConfigurationSet;
import com.pulumi.aws.ses.ConfigurationSetArgs;
import com.pulumi.aws.ses.inputs.ConfigurationSetDeliveryOptionsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var test = new ConfigurationSet("test", ConfigurationSetArgs.builder()
            .name("some-configuration-set-test")
            .deliveryOptions(ConfigurationSetDeliveryOptionsArgs.builder()
                .tlsPolicy("Require")
                .build())
            .build());

    }
}
resources:
  test:
    type: aws:ses:ConfigurationSet
    properties:
      name: some-configuration-set-test
      deliveryOptions:
        tlsPolicy: Require

The deliveryOptions block controls transport security. Setting tlsPolicy to “Require” forces SES to use TLS when delivering messages to recipient mail servers. If the recipient server doesn’t support TLS, delivery fails rather than falling back to unencrypted connections.

Email campaigns that track link clicks can use a custom domain for redirects instead of Amazon’s default tracking domain.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const test = new aws.ses.ConfigurationSet("test", {
    name: "some-configuration-set-test",
    trackingOptions: {
        customRedirectDomain: "sub.example.com",
    },
});
import pulumi
import pulumi_aws as aws

test = aws.ses.ConfigurationSet("test",
    name="some-configuration-set-test",
    tracking_options={
        "custom_redirect_domain": "sub.example.com",
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ses"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := ses.NewConfigurationSet(ctx, "test", &ses.ConfigurationSetArgs{
			Name: pulumi.String("some-configuration-set-test"),
			TrackingOptions: &ses.ConfigurationSetTrackingOptionsArgs{
				CustomRedirectDomain: pulumi.String("sub.example.com"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var test = new Aws.Ses.ConfigurationSet("test", new()
    {
        Name = "some-configuration-set-test",
        TrackingOptions = new Aws.Ses.Inputs.ConfigurationSetTrackingOptionsArgs
        {
            CustomRedirectDomain = "sub.example.com",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ses.ConfigurationSet;
import com.pulumi.aws.ses.ConfigurationSetArgs;
import com.pulumi.aws.ses.inputs.ConfigurationSetTrackingOptionsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var test = new ConfigurationSet("test", ConfigurationSetArgs.builder()
            .name("some-configuration-set-test")
            .trackingOptions(ConfigurationSetTrackingOptionsArgs.builder()
                .customRedirectDomain("sub.example.com")
                .build())
            .build());

    }
}
resources:
  test:
    type: aws:ses:ConfigurationSet
    properties:
      name: some-configuration-set-test
      trackingOptions:
        customRedirectDomain: sub.example.com

The trackingOptions block configures link and open tracking. The customRedirectDomain property replaces Amazon’s default tracking domain with your own subdomain, maintaining brand consistency in tracked links. You must configure DNS records separately to point this domain to Amazon SES.

Beyond these examples

These snippets focus on specific configuration set features: configuration set naming, TLS enforcement, and custom tracking domains. They’re intentionally minimal rather than full email sending solutions.

The examples may reference pre-existing infrastructure such as DNS records for custom tracking domains, which must be configured separately. They focus on configuring the set rather than provisioning everything around it.

To keep things focused, common configuration set patterns are omitted, including:

  • Reputation metrics publishing (reputationMetricsEnabled)
  • Sending enable/disable controls (sendingEnabled)
  • Event destinations (SNS, Kinesis Firehose, CloudWatch)
  • IP pool assignment

These omissions are intentional: the goal is to illustrate how each configuration set feature is wired, not provide drop-in email modules. See the SES ConfigurationSet resource reference for all available configuration options.

Let's create AWS SES Configuration Sets

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Setup
Can I rename my configuration set after creation?
No, the name property is immutable. Changing it forces resource replacement, so plan your naming convention carefully.
Is email sending enabled by default?
Yes, sendingEnabled defaults to true. Set it to false if you want to create a disabled configuration set initially.
Are reputation metrics published to CloudWatch automatically?
No, reputationMetricsEnabled defaults to false. Enable it explicitly if you want bounce and complaint rates published to CloudWatch.
Email Delivery & TLS
How do I require TLS connections for emails sent through this configuration set?
Configure deliveryOptions with tlsPolicy set to "Require" to enforce TLS for all messages using this configuration set.
Monitoring & Tracking
How do I set up custom redirect domains for email tracking?
Use trackingOptions with customRedirectDomain set to your subdomain (e.g., "sub.example.com").
What's the limitation with trackingOptions?
The custom redirect domain functionality is best effort and may not work reliably in all cases.
What does lastFreshStart indicate?
It shows the date and time when reputation metrics for the configuration set were last reset (known as a fresh start).

Using a different cloud?

Explore integration guides for other cloud providers: