Email Infrastructure

Deploy AWS SES email sending for AuthGate using Pulumi. This creates the SES domain identity, DKIM signing, MAIL FROM configuration, and an IAM user scoped to your domain.


Overview

AuthGate uses AWS SES to send transactional emails — verification codes and password reset links — for both the dashboard and the proxy email/password flow. The infrastructure is defined as code in the infra/ package using Pulumi.

The Pulumi stack creates:

  • SES Domain Identity — registers your domain with SES
  • DKIM — enables DomainKeys Identified Mail signing for deliverability
  • MAIL FROM — configures a custom bounce-handling subdomain (mail.yourdomain.com)
  • IAM User + Access Key — scoped credentials that can only send from *@yourdomain.com and *@*.yourdomain.com

Prerequisites

  • Pulumi CLI installed
  • AWS CLI configured with credentials that can manage SES and IAM
  • A domain you control (e.g. authgate.dev) with access to its DNS records
  • Node.js 20+ and pnpm 9+

Deploy with Pulumi

From the repository root, initialize the stack and deploy:

# Navigate to the infra package
cd infra

# Create a new stack (e.g. "dev" or "prod")
pulumi stack init dev

# Configure your domain and enable SES
pulumi config set authgate:sesDomain yourdomain.com
pulumi config set authgate:enableSes true

# Build and deploy
pnpm build
pulumi up

Pulumi will show a preview of the resources to be created. Confirm to proceed. Once complete, the stack outputs will display:

  • sesSmtpAccessKeyId — the IAM access key ID for SES
  • sesSmtpSecretAccessKey — the IAM secret access key (marked as secret)
  • sesDomain — the configured domain
  • sesDnsRecords — all DNS records you need to add

To view the secret access key:

pulumi stack output sesSmtpSecretAccessKey --show-secrets

Configure DNS records

After deploying, Pulumi outputs the DNS records you need to add at your domain registrar. You can view them at any time with:

pulumi stack output sesDnsRecords --json

SES domain verification

Add a TXT record to prove you own the domain:

TypeNameValue
TXT_amazonses.yourdomain.com(value from Pulumi output)

DKIM signing

Add three CNAME records for DKIM email authentication. Pulumi outputs these as an array:

TypeNameValue
CNAME{token1}._domainkey.yourdomain.com{token1}.dkim.amazonses.com
CNAME{token2}._domainkey.yourdomain.com{token2}.dkim.amazonses.com
CNAME{token3}._domainkey.yourdomain.com{token3}.dkim.amazonses.com

MAIL FROM subdomain

Add an MX and a TXT record for the mail. subdomain used for bounce handling:

TypeNameValue
MXmail.yourdomain.com10 feedback-smtp.us-east-1.amazonses.com
TXTmail.yourdomain.comv=spf1 include:amazonses.com ~all

Set environment variables

Add the SES credentials to your apps/web/.env.local:

AWS_SES_REGION=us-east-1
AWS_SES_ACCESS_KEY_ID=your_access_key_id
AWS_SES_SECRET_ACCESS_KEY=your_secret_access_key

Replace the values with the actual outputs from your Pulumi stack. The EMAIL_FROM variable is optional — it defaults to noreply@authgate.dev and is used as the fallback sender for dashboard emails.

# Optional — override the default dashboard sender address
EMAIL_FROM="AuthGate" <noreply@yourdomain.com>

Verify domain

After adding DNS records, verify that SES has picked them up:

  1. Open the AWS SES Console and check that your domain shows Verified status
  2. Check the DKIM status shows Success for all three CNAME records
  3. Check the MAIL FROM domain shows Verified

Per-project branding

AuthGate automatically brands emails per project. When an end user signs up or resets their password through the proxy flow, emails are sent from the project's subdomain:

"My App" <noreply@my-app.authgate.dev>

The sender name and subdomain are derived from the project's name and slug configured in the dashboard. No additional SES or DNS setup is needed for subdomains — the IAM policy allows sending from *@*.yourdomain.com automatically.

Dashboard emails (admin signup/reset) use the global EMAIL_FROM address or default to noreply@authgate.dev.


Infrastructure reference

The infrastructure code lives in the infra/ package:

FileDescription
infra/src/index.tsEntry point — wires SES + IAM together, exports stack outputs
infra/src/config.tsReads Pulumi config (authgate:sesDomain, authgate:enableSes)
infra/src/ses.tsCreates SES domain identity, DKIM, MAIL FROM, and outputs DNS records
infra/src/iam.tsCreates IAM user + access key scoped to *@domain and *@*.domain

Stack configuration

KeyDefaultDescription
authgate:sesDomainauthgate.devThe domain to register with SES
authgate:enableSesfalseSet to true to create SES resources

Stack outputs

OutputDescription
sesSmtpAccessKeyIdIAM access key ID for the SES sending user
sesSmtpSecretAccessKeyIAM secret access key (secret)
sesDomainThe configured SES domain
sesDnsRecordsObject containing all DNS records to configure

Destroying resources

To tear down the SES infrastructure:

cd infra
pulumi destroy --stack dev

This removes the SES domain identity, DKIM, MAIL FROM, IAM user, and access key. You should also remove the corresponding DNS records from your registrar.

Was this page helpful?