Domain Verification Guide
Set up DKIM, SPF, and DMARC for your domain.
Set up DKIM, SPF, and DMARC for your domain to improve deliverability and protect your sender reputation.
Email authentication proves to receiving servers that your emails are legitimate and haven't been tampered with. If you're new to email infrastructure, learn how email actually works first. Without authentication:
The Wraps CLI can automatically create all required DNS records during wraps email init if you have the appropriate environment variables set for your DNS provider.
| DNS Provider | Required Environment Variable | Optional |
|---|---|---|
| AWS Route53 | (uses AWS credentials) | AWS_PROFILE |
| Vercel DNS | VERCEL_TOKEN | VERCEL_TEAM_ID |
| Cloudflare | CLOUDFLARE_API_TOKEN | CLOUDFLARE_ZONE_ID |
Create an API token at vercel.com/account/tokens
export VERCEL_TOKEN=your_token_here# Optional: for team accountsexport VERCEL_TEAM_ID=team_xxxxxCreate an API token at dash.cloudflare.com/profile/api-tokens. The token needs Zone.DNS (Edit) permission.
export CLOUDFLARE_API_TOKEN=your_token_here# Optional: auto-detected if not setexport CLOUDFLARE_ZONE_ID=your_zone_idNo additional setup required if you have a hosted zone for your domain. The CLI uses your existing AWS credentials.
Skip manual DNS setup
With automatic DNS management, you can skip Steps 2-4 below. The CLI will create DKIM, SPF, DMARC, and MX records for you during wraps email init.
If you prefer to add DNS records manually, or your DNS provider isn't supported, follow the steps below.
npx @wraps.dev/cli email domains add -d yourdomain.comAfter adding your domain, SES generates 3 DKIM tokens. You need to add these as CNAME records in your DNS.
npx @wraps.dev/cli email domains get-dkim -d yourdomain.comSES will display 3 CNAME records that you need to add to your DNS:

Copy all 3 CNAME records and add them in your DNS provider (Route 53, Cloudflare, Namecheap, etc.). The format looks like:
# You'll get 3 CNAME records like this:abc123._domainkey.yourdomain.com → abc123.dkim.amazonses.comdef456._domainkey.yourdomain.com → def456.dkim.amazonses.comghi789._domainkey.yourdomain.com → ghi789.dkim.amazonses.com
Important: Record Name Format
Copy the exact record names from SES. Don't add extra underscores or modify them. Some DNS providers automatically append your domain, so you may only need to enter the part before your domain name.
Good news: SPF is automatic!
When you send through Amazon SES, the MAIL FROM domain is a subdomain of amazonses.com, which already has SPF configured. No additional setup required.
If you want to use a custom MAIL FROM domain (advanced), see the AWS documentation.
DMARC tells receiving mail servers what to do when emails fail authentication checks. SES will prompt you to set up DMARC:

Add this TXT record to your DNS:
# Add this TXT record to your DNS:Name: _dmarc.yourdomain.comType: TXTValue: v=DMARC1; p=quarantine; sp=quarantine; np=reject; rua=mailto:dmarc@yourdomain.com| Policy | Value | Action |
|---|---|---|
| Monitor | p=none | No enforcement, just collect reports |
| Quarantine | p=quarantine | Send failing emails to spam |
| Reject | p=reject | Reject failing emails entirely |
Recommended: Start with quarantine
Use p=quarantine to start. Once you've confirmed all legitimate emails pass, you can upgrade to p=reject.
After adding DNS records, verify everything is configured correctly:
npx @wraps.dev/cli email domains verify -d yourdomain.comDNS propagation takes up to 72 hours
DKIM verification typically completes within a few hours, but can take up to 72 hours for DNS to propagate worldwide.
SES rewrites every tracked link to r.us-east-1.awstrack.me before it reaches the inbox. That host is shared by every SES customer, and it is what your recipients see when they hover a link. A custom tracking domain replaces it with a hostname under your own domain, such as track.mail.yourdomain.com.
This only matters when open or click tracking is on. With both off, SES leaves your links alone and there is nothing to rewrite.
The redirect domain is a property of the SES configuration set, not of the domain identity. Wraps creates one configuration set per domain you add, so every added domain carries its own tracking domain. SES also requires the redirect domain to sit under the sending domain, and the CLI enforces that: track.mail.yourdomain.com is valid for mail.yourdomain.com, while track.yourdomain.com is not. The default suggestion is always track.<domain>.
That rule decides what happens with subdomains. If you added mail.yourdomain.com with wraps email domains add, it has its own configuration set and needs its own tracking domain. If you only added yourdomain.com and send as a subdomain of it, the send falls back to your primary domain's configuration set and those links use the primary's tracking domain. Several sending domains cannot share one tracking host.
Run it as two commands. The HTTPS step refuses to start until a tracking domain exists.
# 1. Set the tracking domainnpx @wraps.dev/cli email domains config -d mail.yourdomain.com \ --tracking-domain track.mail.yourdomain.com# 2. Then turn on HTTPS for itnpx @wraps.dev/cli email domains config -d mail.yourdomain.com --tracking-httpsYour primary domain is the exception. Its tracking domain belongs to the Pulumi stack, so domains config rejects it. Use wraps email upgrade and choose "Add/change custom tracking domain" instead. To go back to the shared SES host, pass --tracking-domain none.
A tracking domain needs one CNAME. Wraps creates it for you on Route 53, Vercel, and Cloudflare. On every other provider the CLI prints the record and you add it by hand.
# CNAME for the tracking domain (plain HTTP tracking):Name: track.mail.yourdomain.comType: CNAMEValue: r.us-east-1.awstrack.meThe value is r.<region>.awstrack.me for plain HTTP tracking. With HTTPS enabled it becomes your CloudFront distribution domain instead, and the CLI swaps the record for you.
--tracking-https requests an ACM certificate and puts a CloudFront distribution in front of the tracking domain, both in your own AWS account. Certificate validation takes 5 to 30 minutes. The distribution is created only once the certificate reaches ISSUED, so run the same command again after that to finish the switch.
HTTPS costs one CloudFront distribution
Fractions of a cent per 10,000 tracking requests, and the certificate is free. It is still one more piece of infrastructure in your account to keep track of. Plain HTTP tracking works without it, and the links say http:// when recipients hover them.
There is no flag that covers all your domains, because each one needs its own hostname. wraps email domains list --json reports every managed domain and its current tracking domain, so a loop covers the rest.
npx @wraps.dev/cli email domains list --json \ | jq -r '.data.domains[] | select(.managed and (.isPrimary | not) and (.trackingDomain == null)) | .domain' \ | while read -r d; do npx @wraps.dev/cli email domains config -d "$d" --tracking-domain "track.$d" doneThe --domain flag is required in JSON mode, which is why this loops rather than running one command. Add a second pass with --tracking-https once the CNAMEs resolve. Full flag details live in the email CLI reference.
wraps email domains verify after verification to apply it--tracking-https once the certificate is ISSUED to create the distributionamazon.com blocks ACM from issuing the certificateNow that your domain is verified, request production access for faster approval.
Production AccessStart sending authenticated emails with the Wraps SDK.
Email Quickstart