Setting Up DMARC for AWS SES: Developer Guide
Technical guide for developers: Configure SPF, DKIM, and DMARC for Amazon SES. Includes CLI commands, code examples, and best practices.

Introduction
Amazon Simple Email Service (SES) is a powerful, cost-effective email platform for developers. However, proper authentication configuration is critical for deliverability and avoiding the SES spam folder.
This technical guide covers complete email authentication setup for AWS SES, including CLI commands and infrastructure-as-code examples.
What you'll learn:
- Configure SES domain identity with SPF and DKIM
- Implement DMARC policy
- Handle multiple sending domains
- Monitor and troubleshoot authentication
- Best practices for production deployments
Prerequisites:
- AWS account with SES access
- Domain with DNS management
- AWS CLI installed and configured
- Basic understanding of DNS and email authentication
Step 1: Verify Domain in SES
1.1: Verify Domain Identity (Console)
Open SES Console
- Navigate to SES Console
- Select your region
Create Domain Identity
- Click "Identities" → "Create identity"
- Select "Domain"
- Enter your domain:
yourdomain.com - Check "Assign a default configuration set" (optional)
- Click "Create identity"
Copy DNS Records
- SES provides DNS records to add:
- Domain verification (TXT or CNAME)
- DKIM records (3 CNAME records)
- (Optionally) Custom MAIL FROM
- SES provides DNS records to add:
1.2: Verify Domain Identity (CLI)
# Verify domain identity
aws ses verify-domain-identity --domain yourdomain.com --region us-east-1
# Get DKIM tokens
aws ses verify-domain-dkim --domain yourdomain.com --region us-east-1Output:
{
"DkimTokens": [
"token1abc123",
"token2def456",
"token3ghi789"
]
}1.3: Verify Domain via CloudFormation
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SESIdentity:
Type: AWS::SES::EmailIdentity
Properties:
EmailIdentity: yourdomain.com
DkimSigningAttributes:
NextSigningKeyLength: RSA_2048_BIT1.4: Verify Domain via Terraform
resource "aws_ses_domain_identity" "main" {
domain = "yourdomain.com"
}
resource "aws_ses_domain_dkim" "main" {
domain = aws_ses_domain_identity.main.domain
}Step 2: Configure DNS Records
2.1: Add Domain Verification Record
SES provides a verification token. Add TXT record:
- Name:
_amazonses.yourdomain.com - Type: TXT
- Value: Verification token from SES
Example:
_amazonses.yourdomain.com TXT "abc123def456ghi789..."2.2: Add DKIM Records
SES provides three DKIM tokens. Create three CNAME records:
token1abc123._domainkey.yourdomain.com CNAME token1abc123.dkim.amazonses.com
token2def456._domainkey.yourdomain.com CNAME token2def456.dkim.amazonses.com
token3ghi789._domainkey.yourdomain.com CNAME token3ghi789.dkim.amazonses.comUsing Route 53 CLI:
# Get hosted zone ID
ZONE_ID=$(aws route53 list-hosted-zones-by-name --dns-name yourdomain.com \
--query "HostedZones[0].Id" --output text)
# Add DKIM CNAME records
aws route53 change-resource-record-sets --hosted-zone-id $ZONE_ID --change-batch '{
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "token1abc123._domainkey.yourdomain.com",
"Type": "CNAME",
"TTL": 1800,
"ResourceRecords": [{"Value": "token1abc123.dkim.amazonses.com"}]
}
},
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "token2def456._domainkey.yourdomain.com",
"Type": "CNAME",
"TTL": 1800,
"ResourceRecords": [{"Value": "token2def456.dkim.amazonses.com"}]
}
},
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "token3ghi789._domainkey.yourdomain.com",
"Type": "CNAME",
"TTL": 1800,
"ResourceRecords": [{"Value": "token3ghi789.dkim.amazonses.com"}]
}
}
]
}'2.3: Verify DKIM Status
Console: Check identity status (should show "Verified" with DKIM enabled)
CLI:
aws ses get-identity-dkim-attributes --identities yourdomain.com --region us-east-1Expected output:
{
"DkimAttributes": {
"yourdomain.com": {
"DkimEnabled": true,
"DkimVerificationStatus": "Success",
"DkimTokens": ["token1abc123", "token2def456", "token3ghi789"]
}
}
}Step 3: Configure SPF for SES
3.1: Basic SPF Record
Add TXT record:
- Name:
@oryourdomain.com - Type: TXT
- Value:
v=spf1 include:amazonses.com ~all
3.2: SPF with Multiple Services
If using SES + other services:
v=spf1 include:amazonses.com include:_spf.google.com ~all3.3: Regional SPF Considerations
Important: SES sends from regional endpoints. The include amazonses.com covers all regions.
Alternative (region-specific):
- US East (N. Virginia):
include:ses-email.us-east-1.amazonses.com - US West (Oregon):
include:ses-email.us-west-2.amazonses.com - EU (Ireland):
include:ses-email.eu-west-1.amazonses.com
Using include:amazonses.com is recommended (covers all regions).
3.4: Add SPF via Route 53 CLI
ZONE_ID=$(aws route53 list-hosted-zones-by-name --dns-name yourdomain.com \
--query "HostedZones[0].Id" --output text)
aws route53 change-resource-record-sets --hosted-zone-id $ZONE_ID --change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "yourdomain.com",
"Type": "TXT",
"TTL": 300,
"ResourceRecords": [{"Value": "\"v=spf1 include:amazonses.com ~all\""}]
}
}]
}'3.5: Verify SPF
dig yourdomain.com TXTOr use: SPF Checker →
Step 4: Configure Custom MAIL FROM (Optional but Recommended)
4.1: Why Use Custom MAIL FROM?
By default, SES uses amazonses.com as the MAIL FROM domain, which causes SPF alignment issues with DMARC.
Custom MAIL FROM benefits:
- Proper SPF alignment
- Better DMARC compliance
- Professional appearance
4.2: Set Custom MAIL FROM Domain
Choose subdomain: bounce.yourdomain.com or mail.yourdomain.com
Via Console:
- Go to SES Identity
- Click "Custom MAIL FROM domain"
- Enter subdomain:
bounce.yourdomain.com - Choose "Use a default value" or "Reject email"
- Save
Via CLI:
aws ses set-identity-mail-from-domain \
--identity yourdomain.com \
--mail-from-domain bounce.yourdomain.com \
--behavior-on-mx-failure UseDefaultValue \
--region us-east-14.3: Add DNS Records for Custom MAIL FROM
SES requires two records:
MX record:
- Name:
bounce.yourdomain.com - Type: MX
- Value:
10 feedback-smtp.us-east-1.amazonses.com - Priority: 10
SPF record:
- Name:
bounce.yourdomain.com - Type: TXT
- Value:
v=spf1 include:amazonses.com ~all
Route 53 CLI:
aws route53 change-resource-record-sets --hosted-zone-id $ZONE_ID --change-batch '{
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "bounce.yourdomain.com",
"Type": "MX",
"TTL": 300,
"ResourceRecords": [{"Value": "10 feedback-smtp.us-east-1.amazonses.com"}]
}
},
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "bounce.yourdomain.com",
"Type": "TXT",
"TTL": 300,
"ResourceRecords": [{"Value": "\"v=spf1 include:amazonses.com ~all\""}]
}
}
]
}'4.4: Verify Custom MAIL FROM
aws ses get-identity-mail-from-domain-attributes \
--identities yourdomain.com \
--region us-east-1Step 5: Implement DMARC
5.1: Create DMARC Record
Add TXT record:
- Name:
_dmarc.yourdomain.com - Type: TXT
- Value:
v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com; fo=1
5.2: Route 53 CLI
aws route53 change-resource-record-sets --hosted-zone-id $ZONE_ID --change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "_dmarc.yourdomain.com",
"Type": "TXT",
"TTL": 300,
"ResourceRecords": [{"Value": "\"v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com; fo=1\""}]
}
}]
}'5.3: Progressive DMARC Policy
Monitoring (week 1-4):
v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.comQuarantine (week 5-8):
v=DMARC1; p=quarantine; pct=100; rua=mailto:dmarc@yourdomain.com; adkim=r; aspf=rReject (week 9+):
v=DMARC1; p=reject; pct=100; rua=mailto:dmarc@yourdomain.com; adkim=r; aspf=r5.4: Verify DMARC
dig _dmarc.yourdomain.com TXTOr use: DMARC Checker →
Step 6: Send Test Email
6.1: Send Test via AWS SDK (Python)
import boto3
ses = boto3.client('ses', region_name='us-east-1')
response = ses.send_email(
Source='test@yourdomain.com',
Destination={'ToAddresses': ['recipient@example.com']},
Message={
'Subject': {'Data': 'Test Email - DMARC Verification'},
'Body': {'Text': {'Data': 'This is a test email to verify authentication.'}}
}
)
print(f"Email sent. Message ID: {response['MessageId']}")6.2: Send Test via CLI
aws ses send-email \
--from test@yourdomain.com \
--to recipient@example.com \
--subject "Test Email" \
--text "Test authentication" \
--region us-east-16.3: Verify Email Headers
- Send to Gmail/Outlook
- View original message
- Check Authentication-Results header
Expected:
Authentication-Results: mx.google.com;
dkim=pass header.i=@yourdomain.com;
spf=pass smtp.mailfrom=yourdomain.com;
dmarc=passStep 7: Production Best Practices
7.1: Use Configuration Sets
Track sends, opens, clicks, bounces:
aws ses create-configuration-set \
--configuration-set Name=production-emails \
--region us-east-17.2: Set Up Event Publishing
Monitor bounces and complaints:
aws ses put-configuration-set-event-destination \
--configuration-set-name production-emails \
--event-destination '{
"Name": "CloudWatch",
"Enabled": true,
"MatchingEventTypes": ["send","bounce","complaint"],
"CloudWatchDestination": {
"DimensionConfigurations": [{
"DimensionName": "ses:configuration-set",
"DimensionValueSource": "messageTag",
"DefaultDimensionValue": "production-emails"
}]
}
}'7.3: Monitor Sending Reputation
aws ses get-account-sending-enabled --region us-east-1
aws ses get-send-quota --region us-east-17.4: Handle Bounces and Complaints
Set up SNS topic for notifications:
aws ses set-identity-notification-topic \
--identity yourdomain.com \
--notification-type Bounce \
--sns-topic arn:aws:sns:us-east-1:123456789012:ses-bouncesTroubleshooting
Issue: DKIM verification fails
Symptoms: DKIM status shows "Pending" or "Failed"
Solution:
- Verify all three CNAME records are added correctly
- Check for typos in DKIM tokens
- Wait up to 72 hours for DNS propagation
- Use
digto verify CNAME records
Issue: SPF alignment fails with DMARC
Symptoms: SPF passes but DMARC fails alignment
Solution:
- Configure custom MAIL FROM domain
- Ensure custom MAIL FROM has proper MX and SPF records
- Use relaxed alignment in DMARC:
aspf=r
Issue: Emails in sandbox mode
Symptoms: Can only send to verified addresses
Solution: Request production access:
# Submit request via AWS Support Console
# Or use CLI to check status:
aws ses get-account-sending-enabledInfrastructure as Code Examples
Complete Terraform Example
resource "aws_ses_domain_identity" "main" {
domain = "yourdomain.com"
}
resource "aws_ses_domain_dkim" "main" {
domain = aws_ses_domain_identity.main.domain
}
resource "aws_ses_domain_mail_from" "main" {
domain = aws_ses_domain_identity.main.domain
mail_from_domain = "bounce.${aws_ses_domain_identity.main.domain}"
}
resource "aws_route53_record" "dkim" {
count = 3
zone_id = aws_route53_zone.main.zone_id
name = "${element(aws_ses_domain_dkim.main.dkim_tokens, count.index)}._domainkey"
type = "CNAME"
ttl = 300
records = ["${element(aws_ses_domain_dkim.main.dkim_tokens, count.index)}.dkim.amazonses.com"]
}
resource "aws_route53_record" "spf" {
zone_id = aws_route53_zone.main.zone_id
name = ""
type = "TXT"
ttl = 300
records = ["v=spf1 include:amazonses.com ~all"]
}
resource "aws_route53_record" "dmarc" {
zone_id = aws_route53_zone.main.zone_id
name = "_dmarc"
type = "TXT"
ttl = 300
records = ["v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com"]
}The Bottom Line
AWS SES authentication setup involves:
- Domain verification: Verify domain identity in SES
- DKIM: Add three CNAME records (auto-configured)
- SPF: Add
include:amazonses.com - Custom MAIL FROM: Configure for proper SPF alignment
- DMARC: Progressive policy enforcement
Timeline:
- Setup: 30-45 minutes
- DNS propagation: 1-24 hours
- Monitoring: 2-4 weeks
- Full enforcement: 6-8 weeks
Next Steps
Verify your AWS SES configuration:
Need automated DMARC monitoring? Start free trial →
Related Articles:
Ready to improve your email deliverability?
Start monitoring your DMARC reports and get insights into your email authentication setup.
Start Free TrialRelated Articles
platform guidesHow to Set Up DMARC for Microsoft 365 (Office 365 Guide)
Complete step-by-step guide to configure SPF, DKIM, and DMARC for Microsoft 365. Includes DNS record examples and troubleshooting tips.
platform guidesDMARC Setup for Zoho Mail: Complete Configuration Guide
Step-by-step guide to configure SPF, DKIM, and DMARC for Zoho Mail. Protect your domain and improve email deliverability with proper authentication.
platform guidesHow to Set Up DMARC, SPF and DKIM for Constant Contact
Complete guide to configuring SPF, DKIM, and DMARC for Constant Contact. Fix authentication issues and improve email deliverability.