Deprecated: The mail.* methods are deprecated. Use email.received.* methods instead.All mail.* methods will continue to work but show console warnings.Migration Guide: Replace inbound.mail.* with inbound.email.received.*

Migration to Unified Email API

The unified email API provides a cleaner structure:
// ❌ OLD (Deprecated - but still works)
const emails = await inbound.mail.list()
const email = await inbound.mail.get('email_id')

// ✅ NEW (Recommended)
const emails = await inbound.email.received.list()
const email = await inbound.email.received.get('email_id')

// 🔄 OR use universal email.get() for any email type
const email = await inbound.email.get('email_id') // Works for received OR sent emails

Unified Email Management

See the complete guide for the unified email API

Overview (Legacy Documentation)

The Mail API allows you to manage emails received at your configured addresses.

List Emails

Retrieve emails from your inbox with filtering and pagination:
import { Inbound } from '@inboundemail/sdk'

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

// List all emails
const emails = await inbound.mail.list()

// With filters
const filteredEmails = await inbound.mail.list({
  limit: 20,
  offset: 0,
  search: 'invoice',
  domain: 'example.com',
  timeRange: '7d',
  includeArchived: false
})

// Filter by specific email address
const userEmails = await inbound.mail.list({
  emailAddress: 'support@example.com',
  limit: 50
})

// Filter by email ID (useful for email threads)
const threadEmails = await inbound.mail.list({
  emailId: 'email_abc123',
  includeArchived: true
})

console.log(`Found ${emails.emails.length} emails`)
console.log(`Total: ${emails.pagination.total}`)

List Parameters

limit
number
default:"50"
Maximum number of results (1-100)
offset
number
default:"0"
Number of results to skip for pagination
Search emails by subject, sender, or content
status
string
Filter by processing status: all, processed, failed
domain
string
Filter emails by recipient domain
timeRange
string
Time range filter: 24h, 7d, 30d, 90d
includeArchived
boolean
default:"false"
Include archived emails in results
emailAddress
string
Filter emails by a specific email address (searches in to, from, cc, bcc fields)
emailId
string
Filter emails by a specific email ID (useful for getting all emails in a thread)

Response Structure

interface GetMailResponse {
  emails: EmailItem[]
  pagination: {
    limit: number
    offset: number
    total: number
    hasMore?: boolean
  }
}

interface EmailItem {
  id: string
  emailId: string
  messageId: string | null
  subject: string
  from: string
  fromName: string | null
  recipient: string
  preview: string
  receivedAt: Date
  isRead: boolean
  readAt: Date | null
  isArchived: boolean
  archivedAt: Date | null
  hasAttachments: boolean
  attachmentCount: number
  parseSuccess: boolean | null
  parseError: string | null
  createdAt: Date
}

Get Email Details

Retrieve complete details for a specific email:
const emailDetails = await inbound.mail.get('email_abc123')

console.log('Subject:', emailDetails.subject)
console.log('From:', emailDetails.from)
console.log('Text:', emailDetails.textBody)
console.log('HTML:', emailDetails.htmlBody)
console.log('Attachments:', emailDetails.attachments.length)

Response Structure

interface GetMailByIdResponse {
  id: string
  emailId: string
  subject: string
  from: string
  to: string
  textBody: string
  htmlBody: string
  receivedAt: Date
  attachments: Array<{
    filename: string
    contentType: string
    size: number
    contentId?: string
  }>
}

Reply to Emails

Reply to received emails directly through the mail API:
// Reply to an email
await inbound.mail.reply({
  emailId: 'email_abc123',
  to: 'customer@example.com',
  subject: 'Re: Your inquiry',
  textBody: 'Thank you for your message. We will get back to you soon.',
  htmlBody: '<p>Thank you for your message. We will get back to you soon.</p>'
})

Reply Parameters

emailId
string
required
ID of the email to reply to
to
string
required
Recipient email address
subject
string
required
Email subject line
textBody
string
required
Plain text version of the email
htmlBody
string
HTML version of the email

Practical Examples

Email Address Filtering

// Get all emails for a specific customer
const customerEmails = await inbound.mail.list({
  emailAddress: 'customer@example.com',
  timeRange: '30d',
  includeArchived: true
})

console.log(`Found ${customerEmails.emails.length} emails for customer@example.com`)

// Process customer support emails
const supportEmails = await inbound.mail.list({
  emailAddress: 'support@yourcompany.com',
  status: 'processed',
  limit: 100
})

// Auto-reply to support emails
for (const email of supportEmails.emails) {
  if (!email.isRead) {
    await inbound.mail.reply({
      emailId: email.id,
      to: email.from,
      subject: `Re: ${email.subject}`,
      textBody: 'Thank you for contacting support. We have received your message and will respond within 24 hours.'
    })
  }
}

Email Thread Management

// Get all emails in a specific thread using emailId
const threadEmails = await inbound.mail.list({
  emailId: 'original_email_123',
  includeArchived: true
})

console.log(`Thread contains ${threadEmails.emails.length} emails`)

// Sort by date to see conversation flow
const sortedThread = threadEmails.emails.sort(
  (a, b) => new Date(a.receivedAt).getTime() - new Date(b.receivedAt).getTime()
)

// Display conversation history
sortedThread.forEach((email, index) => {
  console.log(`${index + 1}. ${email.subject} - ${email.from} (${email.receivedAt})`)
})

// Reply to the latest email in thread
const latestEmail = sortedThread[sortedThread.length - 1]
await inbound.mail.reply({
  emailId: latestEmail.id,
  to: latestEmail.from,
  subject: `Re: ${latestEmail.subject}`,
  textBody: 'Thank you for your follow-up message.'
})

Advanced Filtering Combinations

// Combine email address filter with other filters
const recentCustomerEmails = await inbound.mail.list({
  emailAddress: 'vip-customer@example.com',
  timeRange: '7d',
  status: 'processed',
  includeArchived: false
})

// Get unread emails from a specific address
const unreadEmails = recentCustomerEmails.emails.filter(email => !email.isRead)

console.log(`VIP customer has ${unreadEmails.length} unread emails`)

Search and Process Emails

// Search for unprocessed orders
const orderEmails = await inbound.mail.list({
  search: 'order',
  timeRange: '24h',
  status: 'processed'
})

for (const email of orderEmails.emails) {
  // Get full email details
  const details = await inbound.mail.get(email.id)
  
  // Process order
  const orderNumber = extractOrderNumber(details.textBody)
  await processOrder(orderNumber)
  
  // Reply to confirm
  await inbound.mail.reply({
    emailId: email.id,
    to: email.from,
    subject: `Order ${orderNumber} Confirmed`,
    textBody: `Your order ${orderNumber} has been received and is being processed.`
  })
}

Pagination Example

async function getAllEmails() {
  const allEmails: EmailItem[] = []
  let offset = 0
  const limit = 100
  
  while (true) {
    const response = await inbound.mail.list({
      limit,
      offset,
      timeRange: '30d'
    })
    
    allEmails.push(...response.emails)
    
    if (!response.pagination.hasMore) break
    offset += limit
  }
  
  return allEmails
}

Archive Old Emails

// Get emails older than 30 days
const oldEmails = await inbound.mail.list({
  timeRange: '90d',
  includeArchived: false
})

// Filter emails older than 30 days
const thirtyDaysAgo = new Date()
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30)

const toArchive = oldEmails.emails.filter(
  email => new Date(email.receivedAt) < thirtyDaysAgo
)

// Archive them (using your own archive logic)
for (const email of toArchive) {
  await archiveEmail(email.id)
}

Email Analytics

// Get email statistics
const emails = await inbound.mail.list({
  timeRange: '7d',
  limit: 100
})

const stats = {
  total: emails.pagination.total,
  withAttachments: emails.emails.filter(e => e.hasAttachments).length,
  failed: emails.emails.filter(e => !e.parseSuccess).length,
  domains: [...new Set(emails.emails.map(e => 
    e.recipient.split('@')[1]
  ))],
  avgResponseTime: calculateAvgResponseTime(emails.emails)
}

console.log('Weekly email stats:', stats)

Error Handling

try {
  const emails = await inbound.mail.list()
} catch (error) {
  if (error.message.includes('401')) {
    console.error('Invalid API key')
  } else if (error.message.includes('429')) {
    console.error('Rate limit exceeded')
  } else if (error.message.includes('Cannot filter by both emailAddress and emailId')) {
    console.error('Use either emailAddress OR emailId, not both')
  } else {
    console.error('API error:', error.message)
  }
}

Filter Validation

The emailAddress and emailId parameters cannot be used together in the same request. Use emailAddress to find all emails involving a specific address, or use emailId to find all emails in a specific thread.
// ✅ Correct - Filter by email address
const addressEmails = await inbound.mail.list({
  emailAddress: 'user@example.com'
})

// ✅ Correct - Filter by email ID
const threadEmails = await inbound.mail.list({
  emailId: 'email_abc123'
})

// ❌ Incorrect - Both filters together will return an error
try {
  await inbound.mail.list({
    emailAddress: 'user@example.com',
    emailId: 'email_abc123'  // This will cause a 400 error
  })
} catch (error) {
  console.error('Cannot use both emailAddress and emailId filters')
}

Next Steps