@wraps.dev/pulumi
Pulumi component for deploying Wraps email infrastructure to your AWS account. Zero credentials stored, full AWS ownership, SST-style API with transform functions.
Installation
npm install @wraps.dev/pulumi
Requirements: Node.js 20+, Pulumi 3.x, @pulumi/aws 6.x or 7.x
Quick Start
import { WrapsEmail } from "@wraps.dev/pulumi";// Minimal setup with Vercel OIDCconst email = new WrapsEmail("email", { vercel: { teamSlug: "my-team", projectName: "my-app", },});// Export the role ARN for your Vercel environmentexport const roleArn = email.roleArn;export const configSetName = email.configSetName;export const envVars = email.envVars;With Domain and Event Tracking
const email = new WrapsEmail("email", { vercel: { teamSlug: "my-team", projectName: "my-app", }, domain: "example.com", events: { types: ["SEND", "DELIVERY", "BOUNCE", "COMPLAINT", "OPEN", "CLICK"], storeHistory: true, retention: "90days", },});// Export DKIM tokens for DNS configurationexport const dkimTokens = email.dkimTokens;Full Configuration
const email = new WrapsEmail("email", { // Authentication (choose one) vercel: { teamSlug: "my-team", projectName: "my-app", }, // Or custom OIDC: // oidc: { // providerUrl: "https://token.actions.githubusercontent.com", // audience: "sts.amazonaws.com", // subjectPattern: "repo:my-org/my-repo:*", // }, // Domain configuration domain: "example.com", mailFromSubdomain: "mail", // Creates mail.example.com // DNS provider (auto-creates DNS records) dns: { provider: "route53", hostedZoneId: "Z1234567890", }, // Or Cloudflare: // dns: { provider: "cloudflare", zoneId: "abc123", apiToken: pulumi.secret("token") }, // Event tracking events: { types: ["SEND", "DELIVERY", "BOUNCE", "COMPLAINT", "OPEN", "CLICK"], storeHistory: true, retention: "90days", // "7days" | "30days" | "90days" | "6months" | "1year" | "unlimited" }, // Email settings reputationMetrics: true, tlsRequired: false, sendingEnabled: true, // Suppression list suppressionList: { enabled: true, reasons: ["BOUNCE", "COMPLAINT"], }, // SMTP credentials (for legacy systems) smtp: { enabled: false, }, // Resource tags tags: { Environment: "production", }, // Transform underlying resources transform: { table: (args) => ({ ...args, billingMode: "PROVISIONED", }), },});Constructor Args
| Property | Type | Description |
|---|---|---|
vercel | VercelOIDCConfig | Vercel OIDC configuration (teamSlug, projectName) |
oidc | OIDCConfig | Custom OIDC provider (GitHub Actions, GitLab, etc.) |
domain | string | Primary sending domain with DKIM |
dns | DNSConfig | DNS provider for automatic record creation |
mailFromSubdomain | string | MAIL FROM subdomain (default: "mail") |
events | EventsConfig | Event tracking and history storage |
smtp | SMTPConfig | SMTP credentials for legacy systems |
reputationMetrics | boolean | Enable SES reputation metrics (default: true) |
tags | Record<string, string> | Tags to apply to all resources |
transform | TransformFunctions | Transform functions for resource customization |
Outputs
| Property | Type | Description |
|---|---|---|
roleArn | Output<string> | IAM role ARN for SDK authentication |
region | Output<string> | AWS region |
configSetName | Output<string> | SES configuration set name |
dkimTokens | Output<string[]> | DKIM tokens for DNS configuration |
tableName | Output<string> | DynamoDB table name (if history enabled) |
queueUrl | Output<string> | SQS queue URL (if events enabled) |
smtpUsername | Output<string> | SMTP username (if SMTP enabled) |
smtpPassword | Output<string> | SMTP password (if SMTP enabled) |
envVars | Output<object> | Environment variables for your app |
Transform Functions
Transform functions let you customize underlying Pulumi resources before creation. Each function receives the default resource args and returns modified args.
const email = new WrapsEmail("email", { vercel: { teamSlug: "my-team", projectName: "my-app" }, domain: "example.com", events: { types: ["SEND"], storeHistory: true }, // Transform underlying Pulumi resources before creation transform: { // Customize IAM role role: (args) => ({ ...args, maxSessionDuration: 7200, // 2 hours }), // Customize DynamoDB table table: (args) => ({ ...args, billingMode: "PROVISIONED", readCapacity: 5, writeCapacity: 5, }), // Customize SQS queue queue: (args) => ({ ...args, visibilityTimeoutSeconds: 120, }), // Customize Lambda function lambda: (args) => ({ ...args, memorySize: 1024, timeout: 60, }), // Customize CloudFront distribution distribution: (args) => ({ ...args, priceClass: "PriceClass_100", // US/Europe only }), },});Available Transform Functions
| Function | Resource Type | When Available |
|---|---|---|
role | aws.iam.RoleArgs | Always |
oidcProvider | aws.iam.OpenIdConnectProviderArgs | If OIDC configured |
configSet | aws.ses.ConfigurationSetArgs | Always |
table | aws.dynamodb.TableArgs | If events.storeHistory |
queue | aws.sqs.QueueArgs | If events configured |
lambda | aws.lambda.FunctionArgs | If events.storeHistory |
distribution | aws.cloudfront.DistributionArgs | If HTTPS tracking |
Accessing Underlying Resources
Access the underlying Pulumi resources via the .nodes property for advanced customization.
const email = new WrapsEmail("email", { /* ... */ });// Access raw Pulumi resources via .nodesemail.nodes.role; // aws.iam.Roleemail.nodes.configSet; // aws.ses.ConfigurationSetemail.nodes.domainIdentity; // aws.ses.DomainIdentity (if domain)email.nodes.domainDkim; // aws.ses.DomainDkim (if domain)email.nodes.table; // aws.dynamodb.Table (if events.storeHistory)email.nodes.queue; // aws.sqs.Queue (if events)email.nodes.dlq; // aws.sqs.Queue (if events)email.nodes.lambda; // aws.lambda.Function (if events.storeHistory)email.nodes.eventRule; // aws.cloudwatch.EventRule (if events)email.nodes.oidcProvider; // aws.iam.OpenIdConnectProvider (if OIDC)email.nodes.distribution; // aws.cloudfront.Distribution (if HTTPS tracking)// Example: Add custom policy to roleconst customPolicy = new aws.iam.RolePolicy("custom", { role: email.nodes.role.name, policy: JSON.stringify({ Version: "2012-10-17", Statement: [{ Action: ["ses:ListIdentities"], Effect: "Allow", Resource: "*", }], }),});Available Nodes
| Property | Type | When Available |
|---|---|---|
role | aws.iam.Role | Always |
oidcProvider | aws.iam.OpenIdConnectProvider | If OIDC configured |
configSet | aws.ses.ConfigurationSet | Always |
domainIdentity | aws.ses.DomainIdentity | If domain configured |
table | aws.dynamodb.Table | If events.storeHistory |
queue | aws.sqs.Queue | If events configured |
lambda | aws.lambda.Function | If events.storeHistory |
distribution | aws.cloudfront.Distribution | If HTTPS tracking |
DNS Providers
Automatically create DNS records with your preferred provider.
// Route53 (automatic DNS records)const emailRoute53 = new WrapsEmail("email", { domain: "example.com", dns: { provider: "route53", hostedZoneId: "Z1234567890", },});// Cloudflareconst emailCloudflare = new WrapsEmail("email", { domain: "example.com", dns: { provider: "cloudflare", zoneId: "abc123def456", apiToken: pulumi.secret(process.env.CLOUDFLARE_API_TOKEN!), },});// Vercel DNSconst emailVercel = new WrapsEmail("email", { domain: "example.com", dns: { provider: "vercel", apiToken: pulumi.secret(process.env.VERCEL_TOKEN!), teamId: "team_xxx", },});GitHub Actions OIDC
Use custom OIDC configuration for GitHub Actions or other providers.
const email = new WrapsEmail("email", { oidc: { providerUrl: "https://token.actions.githubusercontent.com", audience: "sts.amazonaws.com", subjectPattern: "repo:my-org/my-repo:*", }, domain: "example.com",});Environment Variables Output
Convenience output for environment variables to configure your application.
const email = new WrapsEmail("email", { /* ... */ });// Convenience output for environment variablesexport const envVars = email.envVars;// Returns:// {// WRAPS_AWS_ROLE_ARN: "arn:aws:iam::123456789:role/wraps-email-role",// WRAPS_AWS_REGION: "us-east-1",// WRAPS_CONFIG_SET: "wraps-email-tracking",// }Using with @wraps.dev/email SDK
After deploying, use the @wraps.dev/email SDK to send emails:
import { WrapsEmail } from "@wraps.dev/email";const email = new WrapsEmail();await email.send({ from: "hello@example.com", to: "user@example.com", subject: "Hello from Wraps!", html: "<h1>Welcome!</h1>",});Next Steps
Check out the package on npm for the latest version and changelog.
View PackageLearn how to send emails with the @wraps.dev/email SDK.
SDK ReferenceLearn more about Pulumi and infrastructure as code.
Pulumi Docs
