Overview
Domains are the foundation of email receiving in Inbound. Before you can create email addresses, you need to add and verify a domain. Inbound uses AWS SES for email receiving, which requires DNS record verification and MX record configuration.
Every domain in Inbound goes through a verification process:
Add the domain to Inbound
Add DNS records (TXT, MX, DKIM, SPF, DMARC)
AWS SES verifies the records
Domain becomes active and can receive emails
Schema Definition
From the database schema (lib/db/schema.ts:72-99):
export const emailDomains = pgTable ( 'email_domains' , {
id: varchar ( 'id' , { length: 255 }). primaryKey (),
domain: varchar ( 'domain' , { length: 255 }). notNull (). unique (),
status: varchar ( 'status' , { length: 50 }). notNull (), // 'pending', 'verified', 'failed'
verificationToken: varchar ( 'verification_token' , { length: 255 }),
canReceiveEmails: boolean ( 'can_receive_emails' ). default ( false ),
hasMxRecords: boolean ( 'has_mx_records' ). default ( false ),
domainProvider: varchar ( 'domain_provider' , { length: 100 }),
providerConfidence: varchar ( 'provider_confidence' , { length: 20 }),
lastDnsCheck: timestamp ( 'last_dns_check' ),
lastSesCheck: timestamp ( 'last_ses_check' ),
// MAIL FROM domain (removes "via amazonses.com")
mailFromDomain: varchar ( 'mail_from_domain' , { length: 255 }),
mailFromDomainStatus: varchar ( 'mail_from_domain_status' , { length: 50 }),
mailFromDomainVerifiedAt: timestamp ( 'mail_from_domain_verified_at' ),
// Catch-all configuration
isCatchAllEnabled: boolean ( 'is_catch_all_enabled' ). default ( false ),
catchAllEndpointId: varchar ( 'catch_all_endpoint_id' , { length: 255 }),
catchAllReceiptRuleName: varchar ( 'catch_all_receipt_rule_name' , { length: 255 }),
// DMARC reporting
receiveDmarcEmails: boolean ( 'receive_dmarc_emails' ). default ( false ),
tenantId: varchar ( 'tenant_id' , { length: 255 }), // SES tenant isolation
createdAt: timestamp ( 'created_at' ). defaultNow (),
updatedAt: timestamp ( 'updated_at' ). defaultNow (),
userId: varchar ( 'user_id' , { length: 255 }). notNull (),
});
Domain Status Lifecycle
Status Values
pending - Domain created, waiting for DNS verification
verified - DNS records verified, can receive emails
failed - Verification failed, check DNS records
Adding a Domain
Using the SDK
import { Inbound } from 'inboundemail'
const inbound = new Inbound ( process . env . INBOUND_API_KEY ! )
// Add a domain
const domain = await inbound . domains . create ({
domain: 'yourdomain.com'
})
console . log ( domain )
// {
// id: 'dom_abc123',
// domain: 'yourdomain.com',
// status: 'pending',
// canReceiveEmails: false,
// hasMxRecords: false,
// dnsRecords: [
// {
// type: 'TXT',
// name: '_amazonses.yourdomain.com',
// value: 'amazonses:ABCxyz123...',
// description: 'AWS SES verification record',
// isRequired: true
// },
// {
// type: 'MX',
// name: 'yourdomain.com',
// value: '10 inbound-smtp.us-east-2.amazonaws.com',
// description: 'Email receiving MX record',
// isRequired: true
// },
// // DKIM records...
// ]
// }
Direct API Request
From the implementation (app/api/e2/domains/create.ts:81-524):
curl -X POST https://inbound.new/api/e2/domains \
-H "Authorization: Bearer ${ INBOUND_API_KEY }" \
-H "Content-Type: application/json" \
-d '{
"domain": "yourdomain.com"
}'
The API automatically:
Validates the domain format
Checks for conflicts with existing domains
Initiates AWS SES verification
Generates required DNS records (TXT, MX, DKIM)
Configures batch catch-all rules for email receiving
Associates the domain with your SES tenant
DNS Records
Required DNS Records
Inbound requires several DNS records for full functionality:
1. Verification TXT Record
Type: TXT
Name: _amazonses.yourdomain.com
Value: amazonses:ABCxyz123456...
TTL: 1800
This record proves you own the domain to AWS SES. It’s automatically generated when you add the domain.
2. MX Record (Email Receiving)
Type: MX
Name: yourdomain.com
Value: 10 inbound-smtp.us-east-2.amazonaws.com
Priority: 10
TTL: 1800
Important : If your domain already has MX records (e.g., for Google Workspace or Microsoft 365), adding Inbound’s MX record will create a conflict. You’ll need to:
Remove existing MX records, OR
Use a subdomain for Inbound (e.g., mail.yourdomain.com)
3. DKIM Records (3 TXT records)
Type: TXT
Name: abc123._domainkey.yourdomain.com
Value: abc123.dkim.amazonses.com
TTL: 1800
DKIM (DomainKeys Identified Mail) proves your emails are authentic. AWS SES generates 3 DKIM tokens that you add as TXT records.
4. SPF Record (Recommended)
Type: TXT
Name: yourdomain.com
Value: v=spf1 include:amazonses.com ~all
TTL: 1800
5. DMARC Record (Recommended)
Type: TXT
Name: _dmarc.yourdomain.com
Value: v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com
TTL: 1800
Mail-From Domain (Optional)
The Mail-From domain removes the “via amazonses.com” label in Gmail:
Type: MX
Name: mail.yourdomain.com
Value: 10 feedback-smtp.us-east-2.amazonses.com
Priority: 10
Type: TXT
Name: mail.yourdomain.com
Value: v=spf1 include:amazonses.com ~all
Inbound automatically configures the Mail-From domain as mail.yourdomain.com when you add a domain. This improves email deliverability and sender reputation.
Verifying DNS Records
From the implementation (app/api/e2/domains/get.ts:145-793):
// Check domain verification status
const domain = await inbound . domains . get ( 'dom_abc123' , {
check: true // Performs live DNS verification
})
console . log ( domain . verificationCheck )
// {
// dnsRecords: [
// {
// type: 'TXT',
// name: '_amazonses.yourdomain.com',
// value: 'amazonses:ABCxyz...',
// isVerified: true
// },
// {
// type: 'MX',
// name: 'yourdomain.com',
// value: '10 inbound-smtp.us-east-2.amazonaws.com',
// isVerified: true
// },
// // ...
// ],
// sesStatus: 'Success',
// dkimStatus: 'Success',
// dkimVerified: true,
// mailFromDomain: 'mail.yourdomain.com',
// mailFromStatus: 'Success',
// mailFromVerified: true,
// isFullyVerified: true,
// lastChecked: '2024-01-15T10:30:00Z'
// }
Verification Check Process
When you request ?check=true:
DNS lookup - Checks all required DNS records
SES status check - Queries AWS SES verification status
DKIM check - Verifies DKIM tokens are properly configured
Mail-From check - Verifies Mail-From domain status
Database update - Updates domain status if verification succeeds
// Example verification check code
const results = await verifyDnsRecords ([
{ type: 'TXT' , name: '_amazonses.yourdomain.com' , value: 'amazonses:...' },
{ type: 'MX' , name: 'yourdomain.com' , value: '10 inbound-smtp...' },
// ... DKIM records
])
const allVerified = results . every ( r => r . isVerified )
if ( allVerified && sesStatus === 'Success' ) {
await db
. update ( emailDomains )
. set ({ status: 'verified' , canReceiveEmails: true })
. where ( eq ( emailDomains . id , domain . id ))
}
Subdomain Verification
Subdomains automatically inherit verification from their parent domain! If you have example.com verified, you can immediately use mail.example.com without additional verification.
From the implementation (app/api/e2/domains/create.ts:238-386):
// Adding a subdomain
const subdomain = await inbound . domains . create ({
domain: 'mail.yourdomain.com'
})
// Response indicates inheritance
{
id : 'dom_xyz789' ,
domain : 'mail.yourdomain.com' ,
status : 'verified' , // Immediately verified!
parentDomain : 'yourdomain.com' ,
message : 'Subdomain inherits verification from yourdomain.com' ,
dnsRecords : [
{
type: 'MX' ,
name: 'mail.yourdomain.com' ,
value: '10 inbound-smtp.us-east-2.amazonaws.com' ,
description: 'Add this MX record to receive emails at this subdomain' ,
isRequired: true
}
]
}
Subdomain Benefits
Instant verification - No waiting for DNS propagation
Separate email routing - Different MX records than parent
Isolated catch-all - Different catch-all configuration
Inherited DKIM/SPF - Uses parent domain’s authentication
Domain Provider Detection
Inbound automatically detects your domain provider:
{
domainProvider : 'Cloudflare' ,
providerConfidence : 'high' // 'high', 'medium', 'low'
}
Supported providers include: Cloudflare, Namecheap, GoDaddy, Google Domains, AWS Route53, and more. Provider detection helps with DNS setup instructions.
Catch-All Configuration
Catch-all routes ANY email to your domain (not just specific addresses) to an endpoint:
// Enable catch-all
const updated = await inbound . domains . update ( 'dom_abc123' , {
isCatchAllEnabled: true ,
catchAllEndpointId: 'endp_xyz789'
})
// Now emails to ANY address @yourdomain.com route to the endpoint:
// unknown@yourdomain.com → endpoint
// random@yourdomain.com → endpoint
// support@yourdomain.com → endpoint (if no specific email address exists)
Catch-all priority : Specific email addresses always take priority over catch-all. If you have support@yourdomain.com configured, it will route to its endpoint, not the catch-all.
Catch-All Use Cases
Development/testing - Catch all emails during development
Wildcard support - Support ticket systems with dynamic addresses
Lead capture - Catch misspelled or random addresses
Spam filtering - Route unknown senders to a separate endpoint
DMARC Reporting
Enable DMARC report receiving to monitor email authentication:
const domain = await inbound . domains . update ( 'dom_abc123' , {
receiveDmarcEmails: true
})
// DMARC reports sent to dmarc@yourdomain.com will be received
// These are XML reports from ISPs about your email authentication
Listing Domains
// List all domains
const domains = await inbound . domains . list ({
limit: 50 ,
offset: 0
})
// Filter by status
const verifiedDomains = await inbound . domains . list ({
status: 'verified'
})
{
data : [
{
id: 'dom_abc123' ,
domain: 'yourdomain.com' ,
status: 'verified' ,
canReceiveEmails: true ,
hasMxRecords: true ,
isCatchAllEnabled: false ,
emailAddressCount: 5 ,
createdAt: '2024-01-15T10:30:00Z'
}
],
pagination : {
limit : 50 ,
offset : 0 ,
total : 3 ,
hasMore : false
}
}
Common Issues and Solutions
Best Practices
Domain Setup
Use subdomains for Inbound if your main domain already receives email
Add all DNS records at once to speed up verification
Wait 24-48 hours for DNS propagation before troubleshooting
Use check: true parameter to verify DNS records are correct
Set up DMARC reporting to monitor email authentication
Production Considerations
Never delete a domain that has active email addresses
Test email receiving before switching production traffic
Monitor lastDnsCheck and lastSesCheck for verification issues
Keep an eye on AWS SES sending/receiving limits
Configure Mail-From domain to improve deliverability
DNS Provider Tips
Cloudflare : Disable proxy (orange cloud) for MX and TXT records
Namecheap : Use ”@” for root domain, not “yourdomain.com”
GoDaddy : Remove default MX records before adding Inbound’s
Google Domains : TTL minimum is 5 minutes
Route53 : Use simple routing policy for MX records
Next Steps
Once your domain is verified:
Create email addresses to receive emails
Set up endpoints for webhook delivery
Configure webhooks to process incoming emails
Enable catch-all for wildcard email receiving