Skip to main content
The @wraps.dev/pulumi package provides a WrapsEmail Pulumi ComponentResource that deploys SES infrastructure — IAM roles, configuration sets, event pipelines, and DNS records — directly into your Pulumi stack. Use it when you manage your AWS infrastructure with Pulumi.
If you prefer to deploy infrastructure with a single command rather than managing it in code, use the CLI instead. Both approaches deploy identical resources.

Installation

npm install @wraps.dev/pulumi
The package requires @pulumi/pulumi and @pulumi/aws, which your Pulumi project already provides:
npm install @pulumi/pulumi @pulumi/aws

Prerequisites

  • Node.js 20+
  • Pulumi 3.x CLI installed
  • @pulumi/aws 6.x or 7.x
  • AWS credentials configured

Quick start

import { WrapsEmail } from '@wraps.dev/pulumi';

// Minimal: Vercel OIDC
const email = new WrapsEmail('email', {
  vercel: {
    teamSlug: 'my-team',
    projectName: 'my-app',
  },
});

// Export the role ARN to set as an environment variable in Vercel
export const roleArn = email.roleArn;
export const configSetName = email.configSetName;
Deploy with:
pulumi up

Configuration options

Authentication

vercel
VercelOIDCConfig
Vercel OIDC configuration. Mutually exclusive with oidc.
oidc
OIDCConfig
Custom OIDC provider for GitHub Actions, GitLab CI, or other OIDC-compatible platforms. Mutually exclusive with vercel.

Domain

domain
string
Primary sending domain. Creates an SES domain identity with DKIM. DKIM tokens are exported as stack outputs for DNS configuration.
dns
DNSConfig
DNS provider configuration for automatic record creation. Supports Route53, Cloudflare, and Vercel.
mailFromSubdomain
string
default:"mail"
Subdomain for the MAIL FROM domain. Combined with domain — e.g. mail + example.commail.example.com.

Open/click tracking

tracking
TrackingConfig
Open and click tracking configuration.

Event tracking

events
EventsConfig
Enables the event pipeline: EventBridge → SQS → Lambda → DynamoDB.

Email settings

reputationMetrics
boolean
default:"true"
Enable SES reputation metrics in CloudWatch.
tlsRequired
boolean
default:"false"
Require TLS for all outbound connections.
sendingEnabled
boolean
default:"true"
Enable sending on the SES configuration set.
dedicatedIp
boolean
default:"false"
Provision a dedicated sending IP address. Adds approximately $25/month to AWS costs.
suppressionList
SuppressionListConfig
Bounce and complaint suppression.

SMTP

smtp
SMTPConfig
Create an IAM user with SMTP credentials for legacy systems.

Transform functions

transform
TransformFunctions
Escape hatch to customize any underlying Pulumi resource before creation. Each function receives the default resource args and returns modified args.
const email = new WrapsEmail('email', {
  // ...
  transform: {
    // Switch DynamoDB to provisioned billing
    table: (args) => ({ ...args, billingMode: 'PROVISIONED' }),
    // Increase Lambda memory
    lambda: (args) => ({ ...args, memorySize: 1024 }),
  },
});
Available transform keys: role, oidcProvider, configSet, domainIdentity, table, queue, dlq, lambda, eventRule, certificate, distribution.

Tags

tags
Record<string, string>
Tags to apply to all provisioned resources. Merged with the default ManagedBy: wraps-pulumi tag.

Outputs

All outputs are pulumi.Output<T> and can be exported from your Pulumi program or passed to other resources.
OutputTypeDescription
roleArnOutput<string>IAM role ARN for SDK authentication
regionOutput<string>AWS region
configSetNameOutput<string>SES configuration set name
domainOutput<string | undefined>Verified domain (if configured)
mailFromDomainOutput<string | undefined>MAIL FROM domain (if configured)
dkimTokensOutput<string[] | undefined>DKIM tokens for DNS configuration
tableNameOutput<string | undefined>DynamoDB table name (if history enabled)
queueUrlOutput<string | undefined>SQS queue URL (if events enabled)
dlqUrlOutput<string | undefined>SQS dead-letter queue URL
lambdaArnOutput<string | undefined>Lambda function ARN (if history enabled)
customTrackingDomainOutput<string | undefined>Custom tracking domain (if configured)
httpsTrackingEnabledOutput<boolean>Whether HTTPS tracking is enabled
cloudFrontDomainOutput<string | undefined>CloudFront distribution domain (if HTTPS tracking enabled)
acmCertificateValidationRecordsOutput<Array<...> | undefined>ACM certificate validation records (if HTTPS tracking enabled)
archiveArnOutput<string | undefined>Mail Manager archive ARN (if archiving enabled)
archivingEnabledOutput<boolean>Whether archiving is enabled
smtpUserArnOutput<string | undefined>SMTP IAM user ARN (if SMTP enabled)
smtpEndpointOutput<string | undefined>SMTP endpoint (if SMTP enabled)
smtpUsernameOutput<string | undefined>SMTP username — store securely
smtpPasswordOutput<string | undefined>SMTP password — store securely
envVarsOutput<{ WRAPS_AWS_ROLE_ARN, WRAPS_AWS_REGION, WRAPS_CONFIG_SET? }>Convenience object with all env vars
smtpUsername and smtpPassword are shown once in pulumi up output. Store them in a secrets manager immediately — they cannot be retrieved again without rotating the access key.

Accessing underlying resources

All Pulumi resources are accessible via .nodes for advanced use cases:
const email = new WrapsEmail('email', { /* ... */ });

// Always present
email.nodes.role;       // aws.iam.Role
email.nodes.configSet;  // aws.ses.ConfigurationSet

// Present when events are configured
email.nodes.table;     // aws.dynamodb.Table
email.nodes.queue;     // aws.sqs.Queue
email.nodes.dlq;       // aws.sqs.Queue
email.nodes.lambda;    // aws.lambda.Function
email.nodes.eventRule; // aws.cloudwatch.EventRule

// Present when OIDC is configured
email.nodes.oidcProvider; // aws.iam.OpenIdConnectProvider

// Present when domain is configured
email.nodes.domainIdentity; // aws.ses.DomainIdentity
email.nodes.domainDkim;     // aws.ses.DomainDkim

// Present when SMTP is enabled
email.nodes.smtpUser;      // aws.iam.User
email.nodes.smtpAccessKey; // aws.iam.AccessKey

Full example program

import * as pulumi from '@pulumi/pulumi';
import { WrapsEmail } from '@wraps.dev/pulumi';

const email = new WrapsEmail('email', {
  // Vercel OIDC authentication
  vercel: {
    teamSlug: 'my-team',
    projectName: 'my-app',
  },

  // Domain with automatic Route53 DNS
  domain: 'example.com',
  dns: { provider: 'route53', hostedZoneId: 'Z1234567890ABCDEF' },
  mailFromSubdomain: 'mail',

  // Event tracking with 90-day history
  events: {
    types: ['SEND', 'DELIVERY', 'BOUNCE', 'COMPLAINT', 'OPEN', 'CLICK'],
    storeHistory: true,
    retention: '90days',
  },

  // Tag all resources
  tags: {
    Environment: 'production',
  },
});

// Export values to set as environment variables in your application
export const roleArn = email.roleArn;
export const region = email.region;
export const configSetName = email.configSetName;

// Or use the convenience object
export const envVars = email.envVars;

Build docs developers (and LLMs) love