Domain Setup & DNS

Learn how to set up and verify your sending domains for email deliverability.

Domain Setup & DNS

Setting up your sending domain properly is crucial for email deliverability. This guide walks you through configuring DNS records for DKIM, SPF, and DMARC.

Why Domain Setup Matters

  • Deliverability: Properly configured domains avoid spam folders
  • Authentication: Prove you own the domain and are authorized to send
  • Reputation: Build sender reputation tied to your domain
  • Branding: Send from your own domain, not a shared one

Adding a Domain

Via Dashboard

  1. Navigate to Settings > Domains
  2. Click Add Domain
  3. Enter your domain (e.g., mail.yourcompany.com)
  4. Click Create

Via API

import { Transactional } from 'transactional-sdk';
 
const client = new Transactional({
  apiKey: process.env.TRANSACTIONAL_API_KEY,
});
 
const domain = await client.domains.create({
  name: 'mail.yourcompany.com',
});
 
console.log('Domain ID:', domain.id);
console.log('DNS Records:', domain.dnsRecords);

Required DNS Records

After adding a domain, you'll receive DNS records to add. Here's what each does:

1. DKIM (DomainKeys Identified Mail)

DKIM adds a digital signature to your emails, proving they haven't been tampered with.

Type: CNAME
Host: dkim._domainkey.mail.yourcompany.com
Value: dkim.transactional.email

Or if using a TXT record:

Type: TXT
Host: dkim._domainkey.mail.yourcompany.com
Value: v=DKIM1; k=rsa; p=MIGfMA0GCS...

2. Return-Path (Bounce Handling)

Allows Transactional to receive and process bounces:

Type: CNAME
Host: pm-bounces.mail.yourcompany.com
Value: pm.mtasv.net

3. SPF (Sender Policy Framework)

SPF tells receiving servers which mail servers are authorized to send email for your domain:

Type: TXT
Host: mail.yourcompany.com
Value: v=spf1 include:spf.transactional.email ~all

If you have an existing SPF record, add our include:

# Before
v=spf1 include:_spf.google.com ~all
 
# After
v=spf1 include:_spf.google.com include:spf.transactional.email ~all

DMARC tells receivers what to do with emails that fail authentication:

Type: TXT
Host: _dmarc.mail.yourcompany.com
Value: v=DMARC1; p=none; rua=mailto:dmarc@yourcompany.com

DMARC policies:

  • p=none: Monitor only, don't reject
  • p=quarantine: Send failed emails to spam
  • p=reject: Reject failed emails entirely

Start with p=none and move to stricter policies after monitoring.

Adding DNS Records

Cloudflare

# Using Cloudflare API
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records" \
  -H "Authorization: Bearer YOUR_CF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "CNAME",
    "name": "dkim._domainkey.mail",
    "content": "dkim.transactional.email",
    "ttl": 3600,
    "proxied": false
  }'

AWS Route 53

aws route53 change-resource-record-sets \
  --hosted-zone-id YOUR_ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "dkim._domainkey.mail.yourcompany.com",
        "Type": "CNAME",
        "TTL": 3600,
        "ResourceRecords": [{"Value": "dkim.transactional.email"}]
      }
    }]
  }'

GoDaddy

  1. Log in to GoDaddy
  2. Go to My Products > DNS
  3. Click Add under DNS Records
  4. Select record type (CNAME or TXT)
  5. Enter the host and value
  6. Save changes

Verifying Your Domain

After adding DNS records, verify your domain:

Via Dashboard

  1. Go to Settings > Domains
  2. Click on your domain
  3. Click Verify DNS

Via API

// Check DNS status
const domain = await client.domains.get(domainId);
console.log('DKIM Status:', domain.dkimStatus);
console.log('Return Path Status:', domain.returnPathStatus);
console.log('SPF Status:', domain.spfStatus);
 
// Trigger verification
await client.domains.verify(domainId);

Troubleshooting

DNS Records Not Found

DNS propagation can take up to 48 hours. Check propagation status:

# Check CNAME record
dig dkim._domainkey.mail.yourcompany.com CNAME
 
# Check TXT record
dig mail.yourcompany.com TXT

Or use online tools like MXToolbox or DNSChecker.

SPF Record Too Long

If your SPF record exceeds 255 characters or 10 DNS lookups:

# Option 1: Use SPF flattening
v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.0/24 include:spf.transactional.email ~all
 
# Option 2: Use a subdomain for transactional email
# Send from mail.yourcompany.com with its own SPF record

Multiple SPF Records

You can only have ONE SPF record per domain. Combine them:

# Wrong - two separate records
v=spf1 include:_spf.google.com ~all
v=spf1 include:spf.transactional.email ~all
 
# Correct - combined
v=spf1 include:_spf.google.com include:spf.transactional.email ~all

DKIM Signature Missing

If emails are sent without DKIM signatures:

  1. Verify the CNAME/TXT record is correct
  2. Check the domain is verified in the dashboard
  3. Ensure you're sending from the verified domain
// Wrong - sending from unverified domain
await client.emails.send({
  from: 'hello@unverified.com', // Not verified!
  to: 'user@example.com',
  subject: 'Test',
  html: '<p>Hello</p>',
});
 
// Correct - use verified domain
await client.emails.send({
  from: 'hello@mail.yourcompany.com', // Verified
  to: 'user@example.com',
  subject: 'Test',
  html: '<p>Hello</p>',
});

Best Practices

Use a Subdomain

Use a subdomain for transactional email (e.g., mail.yourcompany.com) to:

  • Separate transactional from marketing email reputation
  • Easier DNS management
  • Isolate issues

Monitor DMARC Reports

Set up DMARC reporting to monitor authentication:

v=DMARC1; p=none; rua=mailto:dmarc-reports@yourcompany.com; ruf=mailto:dmarc-forensics@yourcompany.com

Warm Up New Domains

New domains should be warmed up gradually:

// Week 1: 100 emails/day
// Week 2: 500 emails/day
// Week 3: 1,000 emails/day
// Week 4: 5,000 emails/day
// Continue doubling until at full volume

Keep Records Updated

When changing email providers, update DNS records:

# Remove old provider's SPF include
v=spf1 include:old-provider.com include:spf.transactional.email ~all
 
# After migration
v=spf1 include:spf.transactional.email ~all

Multiple Domains

You can add multiple domains for different use cases:

// Marketing emails
const marketingDomain = await client.domains.create({
  name: 'marketing.yourcompany.com',
});
 
// Transactional emails
const transactionalDomain = await client.domains.create({
  name: 'mail.yourcompany.com',
});
 
// Support emails
const supportDomain = await client.domains.create({
  name: 'support.yourcompany.com',
});

Next Steps