Overview

Domains must be added and verified before you can receive emails. Inbound handles DNS verification and AWS SES configuration automatically.

List Domains

Retrieve all domains in your account:
import { Inbound } from '@inboundemail/sdk'

const inbound = new Inbound({ apiKey: process.env.INBOUND_API_KEY! })

// List all domains
const domains = await inbound.domains.list()

// Filter by status
const verifiedDomains = await inbound.domains.list({
  status: 'verified',
  canReceive: 'true'
})

// Check DNS records
const domainsWithCheck = await inbound.domains.list({
  check: 'true' // Performs real-time DNS verification
})

List Parameters

limit
number
default:"50"
Maximum number of results (1-100)
offset
number
default:"0"
Number of results to skip
status
string
Filter by verification status: pending, verified, failed
canReceive
string
Filter by email capability: true or false
check
string
Perform real-time DNS verification: true or false

Response Structure

interface DomainWithStats {
  id: string
  domain: string
  status: string
  canReceiveEmails: boolean
  hasMxRecords: boolean
  domainProvider: string | null
  providerConfidence: string | null
  lastDnsCheck: Date | null
  lastSesCheck: Date | null
  isCatchAllEnabled: boolean
  catchAllEndpointId: string | null
  createdAt: Date
  updatedAt: Date
  stats: {
    totalEmailAddresses: number
    activeEmailAddresses: number
    hasCatchAll: boolean
  }
  catchAllEndpoint?: {
    id: string
    name: string
    type: string
    isActive: boolean
  } | null
}

Add Domain

Add a new domain to receive emails:
const domain = await inbound.domains.create({
  domain: 'yourdomain.com'
})

console.log('Domain added:', domain.domain)
console.log('Status:', domain.status)
console.log('DNS Records to add:')

domain.dnsRecords.forEach(record => {
  console.log(`${record.type} ${record.name} ${record.value}`)
})

DNS Records

After adding a domain, you’ll receive DNS records to add:
interface DnsRecord {
  type: 'MX' | 'TXT' | 'CNAME'
  name: string
  value: string
}
Example DNS records:
  • MX Record: Routes emails to AWS SES
  • TXT Records: Domain verification and DKIM authentication
  • CNAME Records: DKIM signing keys

Get Domain Details

const domain = await inbound.domains.get('domain_abc123')

console.log('Domain:', domain.domain)
console.log('Status:', domain.status)
console.log('Can receive emails:', domain.canReceiveEmails)
console.log('Email addresses:', domain.stats.totalEmailAddresses)

if (domain.catchAllEndpoint) {
  console.log('Catch-all routes to:', domain.catchAllEndpoint.name)
}

Configure Catch-All

Route all emails to a domain (except specific addresses) to a single endpoint:
// Enable catch-all
const updated = await inbound.domains.update('domain_abc123', {
  isCatchAllEnabled: true,
  catchAllEndpointId: 'endp_xyz789'
})

// Disable catch-all
const disabled = await inbound.domains.update('domain_abc123', {
  isCatchAllEnabled: false,
  catchAllEndpointId: null
})

Update Parameters

isCatchAllEnabled
boolean
required
Enable or disable catch-all routing
catchAllEndpointId
string | null
required
Endpoint ID for catch-all emails (null to disable)
Catch-all receives emails sent to any address at your domain that doesn’t have a specific email address configured.

Domain Verification

Check Verification Status

async function checkDomainStatus(domainId: string) {
  const domain = await inbound.domains.get(domainId)
  
  if (domain.status === 'verified' && domain.canReceiveEmails) {
    console.log('✅ Domain is ready to receive emails')
  } else {
    console.log('⏳ Domain verification pending')
    console.log('Status:', domain.status)
    console.log('Has MX records:', domain.hasMxRecords)
    
    // Get detailed DNS check
    const domainsWithCheck = await inbound.domains.list({
      check: 'true'
    })
    
    const domainCheck = domainsWithCheck.data.find(d => d.id === domainId)
    if (domainCheck?.verificationCheck) {
      console.log('DNS Records Status:')
      domainCheck.verificationCheck.dnsRecords?.forEach(record => {
        console.log(`${record.type}: ${record.status}`)
      })
    }
  }
}

DNS Provider Detection

Inbound automatically detects your DNS provider:
const domain = await inbound.domains.get('domain_abc123')

if (domain.domainProvider) {
  console.log('DNS Provider:', domain.domainProvider)
  console.log('Confidence:', domain.providerConfidence)
  
  // Show provider-specific instructions
  const instructions = getDnsInstructions(domain.domainProvider)
  console.log(instructions)
}

Practical Examples

Multi-Domain Setup

async function setupCompanyDomains() {
  const domains = [
    'company.com',
    'company.co.uk',
    'company-support.com'
  ]
  
  // Add all domains
  const addedDomains = await Promise.all(
    domains.map(domain => inbound.domains.create({ domain }))
  )
  
  // Display DNS records for each
  addedDomains.forEach(domain => {
    console.log(`\nDNS Records for ${domain.domain}:`)
    domain.dnsRecords.forEach(record => {
      console.log(`${record.type} ${record.name} ${record.value}`)
    })
  })
  
  return addedDomains
}

Automated Verification Check

async function waitForVerification(domainId: string, maxAttempts = 30) {
  let attempts = 0
  
  while (attempts < maxAttempts) {
    const domain = await inbound.domains.get(domainId)
    
    if (domain.status === 'verified' && domain.canReceiveEmails) {
      console.log('✅ Domain verified and ready!')
      return domain
    }
    
    console.log(`Attempt ${attempts + 1}: Status = ${domain.status}`)
    
    // Wait 2 minutes between checks
    await new Promise(resolve => setTimeout(resolve, 120000))
    attempts++
  }
  
  throw new Error('Domain verification timeout')
}

Catch-All Configuration

async function setupCatchAll(domainId: string) {
  // Create catch-all endpoint
  const catchAllEndpoint = await inbound.endpoints.create({
    name: 'Domain Catch-All',
    type: 'webhook',
    description: 'Handles all unmatched emails',
    config: {
      url: 'https://api.yourdomain.com/catch-all',
      timeout: 30,
      retryAttempts: 3
    }
  })
  
  // Enable catch-all on domain
  const domain = await inbound.domains.update(domainId, {
    isCatchAllEnabled: true,
    catchAllEndpointId: catchAllEndpoint.id
  })
  
  console.log('Catch-all configured for:', domain.domain)
  
  // Create specific addresses that override catch-all
  const specificAddresses = ['support', 'sales', 'billing']
  
  for (const address of specificAddresses) {
    await inbound.emailAddresses.create({
      address: `${address}@${domain.domain}`,
      domainId: domainId,
      endpointId: 'endp_specific_handler'
    })
  }
}

Domain Analytics

async function getDomainAnalytics() {
  const domains = await inbound.domains.list({
    check: 'true'
  })
  
  const analytics = domains.data.map(domain => ({
    domain: domain.domain,
    status: domain.status,
    emailAddresses: domain.stats.totalEmailAddresses,
    activeAddresses: domain.stats.activeEmailAddresses,
    hasCatchAll: domain.stats.hasCatchAll,
    provider: domain.domainProvider || 'Unknown',
    lastChecked: domain.lastDnsCheck,
    health: domain.canReceiveEmails ? 'Healthy' : 'Issues'
  }))
  
  // Summary stats
  const summary = {
    total: analytics.length,
    verified: analytics.filter(d => d.status === 'verified').length,
    withCatchAll: analytics.filter(d => d.hasCatchAll).length,
    healthy: analytics.filter(d => d.health === 'Healthy').length
  }
  
  return { analytics, summary }
}

DNS Record Helper

function formatDnsRecords(dnsRecords: DnsRecord[]) {
  const grouped = {
    mx: [] as DnsRecord[],
    txt: [] as DnsRecord[],
    cname: [] as DnsRecord[]
  }
  
  dnsRecords.forEach(record => {
    grouped[record.type.toLowerCase()]?.push(record)
  })
  
  return `
## MX Record (Email Routing)
${grouped.mx.map(r => `${r.name}${r.value}`).join('\n')}

## TXT Records (Verification)
${grouped.txt.map(r => `${r.name}\n"${r.value}"`).join('\n\n')}

## CNAME Records (DKIM)
${grouped.cname.map(r => `${r.name}${r.value}`).join('\n')}
  `.trim()
}

Best Practices

  • Verify domains immediately after adding DNS records
  • Use catch-all for domains to avoid missing emails
  • Monitor domain status regularly
  • Keep DNS records even after verification
  • Set up both specific addresses and catch-all for flexibility
  • Use subdomains for different environments (staging.domain.com)

Troubleshooting

Domain Not Verifying

async function troubleshootDomain(domainId: string) {
  const domains = await inbound.domains.list({ check: 'true' })
  const domain = domains.data.find(d => d.id === domainId)
  
  if (!domain) {
    console.error('Domain not found')
    return
  }
  
  console.log('Domain Status:', domain.status)
  console.log('Has MX Records:', domain.hasMxRecords)
  console.log('Can Receive:', domain.canReceiveEmails)
  
  if (domain.verificationCheck?.dnsRecords) {
    console.log('\nDNS Record Status:')
    domain.verificationCheck.dnsRecords.forEach(record => {
      const icon = record.status === 'verified' ? '✅' : '❌'
      console.log(`${icon} ${record.type} ${record.name}: ${record.status}`)
    })
  }
  
  if (!domain.hasMxRecords) {
    console.log('\n⚠️  MX record not found. Emails cannot be received.')
  }
}

Next Steps