Email API Examples
The following examples demonstrate the unified email API structure with organized namespaces for received and sent emails.Universal Email Retrieval
The new universalemail.get()
method works for both received and sent emails:
app/api/email/[id]/route.ts
Copy
import { NextRequest, NextResponse } from 'next/server'
import { Inbound } from '@inboundemail/sdk'
const inbound = new Inbound(process.env.INBOUND_API_KEY!)
export async function GET(
request: NextRequest,
{ params }: { params: { id: string } }
) {
try {
// Universal method - works for ANY email ID
const email = await inbound.email.get(params.id)
if (!email) {
return NextResponse.json(
{ error: 'Email not found' },
{ status: 404 }
)
}
return NextResponse.json({
message: 'Email found',
subject: email.subject,
// Type checking helps determine email type
type: 'from' in email ? 'received' : 'sent'
})
} catch (error) {
return NextResponse.json(
{ error: 'Failed to fetch email' },
{ status: 500 }
)
}
}
Webhook Handler with Email Processing
app/api/webhook/route.ts
Copy
import { NextRequest, NextResponse } from 'next/server'
import { Inbound } from '@inboundemail/sdk'
import type { InboundWebhookPayload } from '@inboundemail/sdk'
const inbound = new Inbound(process.env.INBOUND_API_KEY!)
export async function POST(request: NextRequest) {
try {
const payload: InboundWebhookPayload = await request.json()
const { email } = payload
// Get full email details
const emailDetails = await inbound.email.received.get(email.id)
// Smart auto-reply system
if (emailDetails.subject.toLowerCase().includes('support')) {
await inbound.email.received.reply({
emailId: email.id,
to: emailDetails.from,
subject: `Re: ${emailDetails.subject}`,
textBody: `
Thank you for contacting support!
We have received your message and will respond within 24 hours.
Ticket ID: ${email.id}
`,
htmlBody: `
<h2>Thank you for contacting support!</h2>
<p>We have received your message and will respond within 24 hours.</p>
<p><strong>Ticket ID:</strong> ${email.id}</p>
`
})
// Mark as read and add to support queue
await inbound.email.received.markRead(email.id)
}
// Handle order confirmations
if (emailDetails.subject.toLowerCase().includes('order')) {
await processOrderEmail(emailDetails)
}
// Handle feedback emails
if (emailDetails.from.includes('feedback')) {
await handleFeedback(emailDetails)
}
return NextResponse.json({ success: true })
} catch (error) {
console.error('Webhook error:', error)
return NextResponse.json(
{ error: 'Webhook processing failed' },
{ status: 500 }
)
}
}
async function processOrderEmail(email: any) {
// Extract order information
const orderMatch = email.textBody?.match(/order\s+#?(\w+)/i)
const orderNumber = orderMatch?.[1]
if (orderNumber) {
// Send order confirmation
await inbound.email.send({
from: 'orders@yourdomain.com',
to: email.from,
subject: `Order ${orderNumber} Confirmed`,
html: `
<h2>Order Confirmation</h2>
<p>Hi there!</p>
<p>Your order <strong>${orderNumber}</strong> has been confirmed and is being processed.</p>
<p>You'll receive a shipping notification once your order is on its way.</p>
`
})
// Archive the original email
await inbound.email.received.archive(email.id)
}
}
async function handleFeedback(email: any) {
// Auto-reply to feedback
await inbound.email.received.reply({
emailId: email.id,
to: email.from,
subject: `Thank you for your feedback!`,
textBody: 'We appreciate your feedback and will use it to improve our service.'
})
// Forward to product team
await inbound.email.send({
from: 'system@yourdomain.com',
to: 'product@yourdomain.com',
subject: `Customer Feedback: ${email.subject}`,
html: `
<h3>New Customer Feedback</h3>
<p><strong>From:</strong> ${email.from}</p>
<p><strong>Subject:</strong> ${email.subject}</p>
<div>
<h4>Message:</h4>
<div>${email.htmlBody || email.textBody}</div>
</div>
`
})
}
Email Processing Pipeline
lib/email-processor.ts
Copy
import { Inbound } from '@inboundemail/sdk'
const inbound = new Inbound(process.env.INBOUND_API_KEY!)
export class EmailProcessor {
/**
* Process emails using the unified API
*/
async processReceivedEmails() {
// Get recent unread emails
const emails = await inbound.email.received.list({
timeRange: '24h',
includeArchived: false,
limit: 100
})
console.log(`Processing ${emails.emails.length} emails`)
for (const email of emails.emails) {
if (email.isRead) continue
try {
await this.processEmail(email.id)
console.log(`✅ Processed email: ${email.subject}`)
} catch (error) {
console.error(`❌ Failed to process email ${email.id}:`, error)
}
}
}
/**
* Process individual email with smart routing
*/
async processEmail(emailId: string) {
// Get full email details
const email = await inbound.email.received.get(emailId)
// Determine processing based on content
const processors = [
this.handleCustomerSupport,
this.handleOrderInquiries,
this.handleNewsletterSignups,
this.handleGeneralInquiries
]
for (const processor of processors) {
const handled = await processor.call(this, email)
if (handled) {
await inbound.email.received.markRead(emailId)
break
}
}
}
/**
* Handle customer support emails
*/
async handleCustomerSupport(email: any): Promise<boolean> {
const supportKeywords = ['support', 'help', 'issue', 'problem', 'bug']
const isSupport = supportKeywords.some(keyword =>
email.subject.toLowerCase().includes(keyword) ||
email.textBody?.toLowerCase().includes(keyword)
)
if (!isSupport) return false
// Create support ticket
const ticketId = `TICKET-${Date.now()}`
// Auto-reply with ticket information
await inbound.email.received.reply({
emailId: email.id,
to: email.from,
subject: `Support Ticket Created: ${ticketId}`,
htmlBody: `
<h2>Support Ticket Created</h2>
<p>Hi ${this.extractName(email.from)},</p>
<p>We've created a support ticket for your inquiry.</p>
<p><strong>Ticket ID:</strong> ${ticketId}</p>
<p><strong>Subject:</strong> ${email.subject}</p>
<p>Our support team will respond within 24 hours.</p>
<p>Best regards,<br>Support Team</p>
`
})
// Forward to support team
await inbound.email.send({
from: 'system@yourdomain.com',
to: 'support@yourdomain.com',
subject: `[${ticketId}] ${email.subject}`,
html: `
<h3>New Support Ticket</h3>
<p><strong>Ticket ID:</strong> ${ticketId}</p>
<p><strong>From:</strong> ${email.from}</p>
<p><strong>Priority:</strong> ${this.determinePriority(email)}</p>
<div>
<h4>Original Message:</h4>
<div>${email.htmlBody || email.textBody}</div>
</div>
`
})
return true
}
/**
* Handle order-related inquiries
*/
async handleOrderInquiries(email: any): Promise<boolean> {
const orderKeywords = ['order', 'purchase', 'payment', 'shipping']
const isOrder = orderKeywords.some(keyword =>
email.subject.toLowerCase().includes(keyword)
)
if (!isOrder) return false
// Extract order number if present
const orderMatch = email.textBody?.match(/order\s+#?(\w+)/i)
const orderNumber = orderMatch?.[1]
await inbound.email.received.reply({
emailId: email.id,
to: email.from,
subject: `Re: ${email.subject}`,
htmlBody: `
<h2>Order Inquiry Received</h2>
<p>Hi ${this.extractName(email.from)},</p>
<p>Thank you for your order inquiry.</p>
${orderNumber ? `<p><strong>Order Number:</strong> ${orderNumber}</p>` : ''}
<p>Our order fulfillment team will respond within 2-4 hours with an update.</p>
<p>For urgent order questions, please call 1-800-SUPPORT.</p>
<p>Best regards,<br>Order Support Team</p>
`
})
return true
}
/**
* Handle newsletter signups
*/
async handleNewsletterSignups(email: any): Promise<boolean> {
const isNewsletterSignup = email.subject.toLowerCase().includes('newsletter') ||
email.textBody?.toLowerCase().includes('subscribe')
if (!isNewsletterSignup) return false
// Welcome email for newsletter signup
await inbound.email.send({
from: 'newsletter@yourdomain.com',
to: email.from,
subject: 'Welcome to Our Newsletter!',
html: `
<h2>Welcome to Our Newsletter!</h2>
<p>Hi ${this.extractName(email.from)},</p>
<p>Thank you for subscribing to our newsletter!</p>
<p>You'll receive weekly updates about:</p>
<ul>
<li>Product announcements</li>
<li>Industry insights</li>
<li>Exclusive offers</li>
</ul>
<p>You can unsubscribe at any time using the link in our emails.</p>
<p>Welcome aboard!</p>
`
})
// Archive the signup email
await inbound.email.received.archive(email.id)
return true
}
/**
* Handle general inquiries
*/
async handleGeneralInquiries(email: any): Promise<boolean> {
// This catches all other emails
await inbound.email.received.reply({
emailId: email.id,
to: email.from,
subject: `Re: ${email.subject}`,
textBody: `
Hi ${this.extractName(email.from)},
Thank you for reaching out to us!
We have received your message and will respond within 1-2 business days.
For urgent matters, please call us at 1-800-SUPPORT.
Best regards,
Customer Service Team
`
})
return true
}
// Utility methods
private extractName(fromAddress: string): string {
const match = fromAddress.match(/^(.+?)\s*</)
return match?.[1]?.trim() || 'there'
}
private determinePriority(email: any): string {
const urgentKeywords = ['urgent', 'critical', 'asap', 'emergency']
const isUrgent = urgentKeywords.some(keyword =>
email.subject.toLowerCase().includes(keyword) ||
email.textBody?.toLowerCase().includes(keyword)
)
return isUrgent ? 'HIGH' : 'NORMAL'
}
}
// Usage
export async function runEmailProcessor() {
const processor = new EmailProcessor()
await processor.processReceivedEmails()
}
Webhook Handler with Type Assignment
Example showing anInboundWebhookPayload
GET request where the type is assigned to the route request:
app/api/webhook/route.ts
Copy
import { NextRequest, NextResponse } from 'next/server'
import { Inbound } from '@inboundemail/sdk'
import type { InboundWebhookPayload } from '@inboundemail/sdk'
const inbound = new Inbound({
apiKey: process.env.INBOUND_API_KEY!
})
export async function GET(request: NextRequest) {
try {
// Example: Type assignment for webhook payload structure
const webhookExample: InboundWebhookPayload = {
event: 'email.received',
timestamp: new Date().toISOString(),
email: {
id: 'email_sample_123',
messageId: '<sample@inbound.new>',
subject: 'Example Email',
recipient: 'demo@yourdomain.com',
receivedAt: new Date(),
from: {
text: 'John Doe <john@example.com>',
addresses: [{
name: 'John Doe',
address: 'john@example.com'
}]
},
to: {
text: 'demo@yourdomain.com',
addresses: [{
name: null,
address: 'demo@yourdomain.com'
}]
},
parsedData: {
messageId: '<sample@inbound.new>',
date: new Date(),
subject: 'Example Email',
from: null,
to: null,
cc: null,
bcc: null,
replyTo: null,
inReplyTo: undefined,
references: undefined,
textBody: 'This is an example email body.',
htmlBody: '<p>This is an example email body.</p>',
attachments: [],
headers: {},
priority: undefined
},
cleanedContent: {
html: '<p>This is an example email body.</p>',
text: 'This is an example email body.',
hasHtml: true,
hasText: true,
attachments: [],
headers: {}
}
},
endpoint: {
id: 'endp_sample_123',
name: 'Example Webhook',
type: 'webhook'
}
}
// Return the typed webhook structure
return NextResponse.json({
message: 'Webhook payload example',
description: 'This demonstrates the InboundWebhookPayload type structure',
example: webhookExample,
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('Error in webhook example:', error)
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
)
}
}
export async function POST(request: NextRequest) {
try {
const payload: InboundWebhookPayload = await request.json()
// Process the webhook payload
console.log('Received email:', payload.email.subject)
// Example: Auto-reply to emails
if (payload.email.subject?.includes('support')) {
await inbound.reply(payload.email, {
from: 'support@yourdomain.com',
text: 'Thanks for contacting support. We\'ll get back to you soon!',
html: '<p>Thanks for contacting support. We\'ll get back to you soon!</p>'
})
}
return NextResponse.json({ success: true })
} catch (error) {
console.error('Webhook processing error:', error)
return NextResponse.json(
{ error: 'Failed to process webhook' },
{ status: 500 }
)
}
}
Complete Email Service Setup
Full implementation of an email service with domain setup, endpoints, and addresses:services/email-service.ts
Copy
import { Inbound } from '@inboundemail/sdk'
import type {
DomainWithStats,
EndpointWithStats,
EmailAddressWithDomain
} from '@inboundemail/sdk'
export class EmailService {
private inbound: Inbound
constructor() {
this.inbound = new Inbound({
apiKey: process.env.INBOUND_API_KEY!,
defaultReplyFrom: 'noreply@yourdomain.com'
})
}
/**
* Complete setup for a new domain
*/
async setupDomain(domainName: string, webhookUrl: string) {
// 1. Add domain
console.log('Adding domain...')
const domain = await this.inbound.domains.create({
domain: domainName
})
console.log('DNS Records to add:')
domain.dnsRecords.forEach(record => {
console.log(`${record.type} ${record.name} → ${record.value}`)
})
// 2. Create webhook endpoint
console.log('\nCreating webhook endpoint...')
const webhook = await this.inbound.endpoints.create({
name: `${domainName} Webhook`,
type: 'webhook',
description: `Main webhook for ${domainName}`,
config: {
url: webhookUrl,
timeout: 30,
retryAttempts: 3,
headers: {
'X-Domain': domainName,
'X-API-Key': process.env.WEBHOOK_SECRET!
}
}
})
// 3. Wait for domain verification
console.log('\nWaiting for domain verification...')
const verifiedDomain = await this.waitForVerification(domain.id)
// 4. Enable catch-all
console.log('\nEnabling catch-all...')
await this.inbound.domains.update(domain.id, {
isCatchAllEnabled: true,
catchAllEndpointId: webhook.id
})
// 5. Create specific email addresses
console.log('\nCreating email addresses...')
const addresses = await this.createStandardAddresses(
domainName,
domain.id,
webhook.id
)
return {
domain: verifiedDomain,
webhook,
addresses
}
}
/**
* Wait for domain verification with timeout
*/
private async waitForVerification(
domainId: string,
maxAttempts = 30
): Promise<DomainWithStats> {
for (let i = 0; i < maxAttempts; i++) {
const domain = await this.inbound.domains.get(domainId)
if (domain.status === 'verified' && domain.canReceiveEmails) {
return domain as DomainWithStats
}
console.log(`Verification attempt ${i + 1}/${maxAttempts}...`)
await new Promise(resolve => setTimeout(resolve, 120000)) // 2 minutes
}
throw new Error('Domain verification timeout')
}
/**
* Create standard email addresses
*/
private async createStandardAddresses(
domain: string,
domainId: string,
endpointId: string
) {
const standardAddresses = [
'support', 'info', 'hello', 'contact',
'admin', 'noreply', 'notifications'
]
const addresses = await Promise.all(
standardAddresses.map(prefix =>
this.inbound.emailAddresses.create({
address: `${prefix}@${domain}`,
domainId,
endpointId
})
)
)
return addresses
}
/**
* Get email analytics
*/
async getAnalytics() {
const [domains, endpoints, emails] = await Promise.all([
this.inbound.domains.list(),
this.inbound.endpoints.list(),
this.inbound.mail.list({ limit: 100 })
])
return {
domains: {
total: domains.data.length,
verified: domains.data.filter(d => d.status === 'verified').length,
withCatchAll: domains.data.filter(d => d.isCatchAllEnabled).length
},
endpoints: {
total: endpoints.data.length,
webhooks: endpoints.data.filter(e => e.type === 'webhook').length,
active: endpoints.data.filter(e => e.isActive).length,
totalDeliveries: endpoints.data.reduce(
(sum, e) => sum + e.deliveryStats.total, 0
)
},
emails: {
total: emails.pagination.total,
recent: emails.emails.length,
withAttachments: emails.emails.filter(e => e.hasAttachments).length
}
}
}
}
Customer Support System
Complete support ticket system with email integration:app/api/support/webhook/route.ts
Copy
import { NextRequest, NextResponse } from 'next/server'
import { Inbound, isInboundWebhook } from '@inboundemail/sdk'
import type { InboundWebhookPayload, InboundWebhookEmail } from '@inboundemail/sdk'
import { createTicket, updateTicket, getTicketByEmail } from '@/lib/tickets'
const inbound = new Inbound({
apiKey: process.env.INBOUND_API_KEY!,
defaultReplyFrom: 'support@yourdomain.com'
})
export async function POST(request: NextRequest) {
try {
const payload: InboundWebhookPayload = await request.json()
if (!isInboundWebhook(payload)) {
return NextResponse.json({ error: 'Invalid payload' }, { status: 400 })
}
const { email } = payload
const senderAddress = email.from?.addresses[0]?.address
if (!senderAddress) {
console.error('No sender address found')
return NextResponse.json({ error: 'Invalid sender' }, { status: 400 })
}
// Check if this is a reply to existing ticket
const existingTicket = await getTicketByEmail(senderAddress, email.subject)
if (existingTicket) {
// Update existing ticket
await updateTicket(existingTicket.id, {
status: 'customer_replied',
lastReply: new Date(),
messages: [
...existingTicket.messages,
{
from: senderAddress,
subject: email.subject,
body: email.cleanedContent.text || '',
html: email.cleanedContent.html || '',
receivedAt: new Date(email.receivedAt),
attachments: email.cleanedContent.attachments.length
}
]
})
// Notify support team
await notifySupportTeam(existingTicket, email)
} else {
// Create new ticket
const ticket = await createTicket({
customerEmail: senderAddress,
customerName: email.from?.addresses[0]?.name || 'Customer',
subject: email.subject || 'No subject',
priority: determinePriority(email),
category: categorizeEmail(email),
firstMessage: {
body: email.cleanedContent.text || '',
html: email.cleanedContent.html || '',
attachments: email.cleanedContent.attachments.length
}
})
// Send auto-reply
await sendAutoReply(email, ticket.id)
}
return NextResponse.json({ success: true })
} catch (error) {
console.error('Support webhook error:', error)
return NextResponse.json(
{ error: 'Failed to process support email' },
{ status: 500 }
)
}
}
/**
* Determine ticket priority based on email content
*/
function determinePriority(email: InboundWebhookEmail): 'low' | 'medium' | 'high' | 'urgent' {
const subject = email.subject?.toLowerCase() || ''
const body = email.cleanedContent.text?.toLowerCase() || ''
if (subject.includes('urgent') || body.includes('urgent')) {
return 'urgent'
}
if (subject.includes('error') || subject.includes('broken')) {
return 'high'
}
if (subject.includes('question') || subject.includes('how to')) {
return 'low'
}
return 'medium'
}
/**
* Categorize email based on content
*/
function categorizeEmail(email: InboundWebhookEmail): string {
const content = `${email.subject} ${email.cleanedContent.text}`.toLowerCase()
if (content.includes('billing') || content.includes('payment')) {
return 'billing'
}
if (content.includes('bug') || content.includes('error')) {
return 'technical'
}
if (content.includes('feature') || content.includes('request')) {
return 'feature_request'
}
return 'general'
}
/**
* Send auto-reply for new tickets
*/
async function sendAutoReply(email: InboundWebhookEmail, ticketId: string) {
const replyHtml = `
<div style="font-family: Arial, sans-serif;">
<h2>Thank you for contacting support!</h2>
<p>We've received your message and created ticket #${ticketId}.</p>
<p>Our support team will respond within 24 hours.</p>
<hr>
<p style="color: #666; font-size: 12px;">
Ticket ID: ${ticketId}<br>
Priority: ${determinePriority(email)}<br>
Category: ${categorizeEmail(email)}
</p>
</div>
`
await inbound.reply(email, {
subject: `Support Ticket #${ticketId} - ${email.subject}`,
html: replyHtml,
text: `Thank you for contacting support! Ticket #${ticketId} created.`,
headers: {
'X-Ticket-ID': ticketId
}
})
}
/**
* Notify support team of customer reply
*/
async function notifySupportTeam(ticket: any, email: InboundWebhookEmail) {
await inbound.emails.send({
from: 'system@yourdomain.com',
to: ['support-team@yourdomain.com'],
subject: `Customer Reply - Ticket #${ticket.id}`,
html: `
<h3>Customer replied to ticket #${ticket.id}</h3>
<p><strong>From:</strong> ${email.from?.text}</p>
<p><strong>Subject:</strong> ${email.subject}</p>
<hr>
<div>${email.cleanedContent.html || email.cleanedContent.text}</div>
<hr>
<a href="https://support.yourdomain.com/tickets/${ticket.id}">View Ticket</a>
`
})
}
Email Newsletter System
Newsletter subscription and distribution system:services/newsletter-service.ts
Copy
import { Inbound } from '@inboundemail/sdk'
import type { InboundWebhookPayload } from '@inboundemail/sdk'
export class NewsletterService {
private inbound: Inbound
constructor() {
this.inbound = new Inbound({
apiKey: process.env.INBOUND_API_KEY!
})
}
/**
* Handle newsletter commands via email
*/
async handleNewsletterEmail(payload: InboundWebhookPayload) {
const { email } = payload
const senderEmail = email.from?.addresses[0]?.address
const subject = email.subject?.toLowerCase() || ''
const body = email.cleanedContent.text?.toLowerCase() || ''
if (!senderEmail) return
// Handle subscribe
if (subject.includes('subscribe') || body.includes('subscribe')) {
await this.handleSubscribe(senderEmail, email.id)
}
// Handle unsubscribe
else if (subject.includes('unsubscribe') || body.includes('unsubscribe')) {
await this.handleUnsubscribe(senderEmail, email.id)
}
// Handle other commands
else if (email.recipient === 'newsletter@yourdomain.com') {
await this.sendHelpMessage(senderEmail, email.id)
}
}
/**
* Subscribe user to newsletter
*/
private async handleSubscribe(email: string, emailId: string) {
// Add to database
const subscriber = await addSubscriber(email)
// Send confirmation
await this.inbound.emails.send({
from: 'newsletter@yourdomain.com',
to: email,
subject: 'Welcome to our newsletter!',
html: `
<h1>You're subscribed!</h1>
<p>Welcome to our newsletter. You'll receive updates weekly.</p>
<p>To unsubscribe, reply with "unsubscribe" in the subject.</p>
<hr>
<p style="font-size: 12px; color: #666;">
Subscriber ID: ${subscriber.id}<br>
<a href="https://yourdomain.com/unsubscribe/${subscriber.unsubscribeToken}">
Unsubscribe
</a>
</p>
`,
headers: {
'List-Unsubscribe': `<mailto:newsletter@yourdomain.com?subject=unsubscribe>`,
'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click'
}
})
}
/**
* Send newsletter to all subscribers
*/
async sendNewsletter(
subject: string,
htmlContent: string,
textContent: string
) {
const subscribers = await getActiveSubscribers()
const batchSize = 50
console.log(`Sending newsletter to ${subscribers.length} subscribers`)
for (let i = 0; i < subscribers.length; i += batchSize) {
const batch = subscribers.slice(i, i + batchSize)
await Promise.all(
batch.map(subscriber =>
this.inbound.emails.send({
from: 'newsletter@yourdomain.com',
to: subscriber.email,
subject,
html: this.personalizeContent(htmlContent, subscriber),
text: this.personalizeContent(textContent, subscriber),
headers: {
'List-Unsubscribe': `<https://yourdomain.com/unsubscribe/${subscriber.unsubscribeToken}>`,
'List-ID': '<newsletter.yourdomain.com>',
'Precedence': 'bulk'
}
}).catch(error => {
console.error(`Failed to send to ${subscriber.email}:`, error)
})
)
)
// Rate limiting
await new Promise(resolve => setTimeout(resolve, 1000))
}
console.log('Newsletter sent successfully')
}
/**
* Personalize content with subscriber data
*/
private personalizeContent(content: string, subscriber: any): string {
return content
.replace('{name}', subscriber.name || 'Subscriber')
.replace('{email}', subscriber.email)
.replace('{unsubscribe_link}',
`https://yourdomain.com/unsubscribe/${subscriber.unsubscribeToken}`
)
}
}
// Database helper functions (implement according to your database)
async function addSubscriber(email: string) {
// Add to database
return { id: 'sub_123', email, unsubscribeToken: 'token_123' }
}
async function getActiveSubscribers() {
// Get from database
return []
}
Order Processing System
E-commerce order processing via email:services/order-email-service.ts
Copy
import { Inbound } from '@inboundemail/sdk'
import type { InboundWebhookEmail } from '@inboundemail/sdk'
export class OrderEmailService {
private inbound: Inbound
constructor() {
this.inbound = new Inbound({
apiKey: process.env.INBOUND_API_KEY!
})
}
/**
* Process order confirmation emails
*/
async processOrderEmail(email: InboundWebhookEmail) {
// Extract order details
const orderDetails = this.extractOrderDetails(email)
if (!orderDetails) {
console.error('Could not extract order details')
return
}
// Create order in system
const order = await createOrder({
customerEmail: email.from?.addresses[0]?.address!,
...orderDetails
})
// Send confirmation
await this.sendOrderConfirmation(email, order)
// Notify warehouse
await this.notifyWarehouse(order)
}
/**
* Extract order details from email
*/
private extractOrderDetails(email: InboundWebhookEmail) {
const text = email.cleanedContent.text || ''
// Extract order number
const orderMatch = text.match(/Order #(\d+)/i)
const orderNumber = orderMatch?.[1]
// Extract items (simplified example)
const itemsMatch = text.match(/Items:([\s\S]*?)Total:/i)
const itemsText = itemsMatch?.[1] || ''
// Extract total
const totalMatch = text.match(/Total: \$?([\d.]+)/i)
const total = totalMatch?.[1] ? parseFloat(totalMatch[1]) : 0
if (!orderNumber) return null
return {
orderNumber,
items: this.parseItems(itemsText),
total
}
}
/**
* Send order confirmation
*/
private async sendOrderConfirmation(
originalEmail: InboundWebhookEmail,
order: any
) {
const confirmationHtml = `
<div style="font-family: Arial, sans-serif; max-width: 600px;">
<h1>Order Confirmed! 🎉</h1>
<p>Thank you for your order. We've received it and will process it shortly.</p>
<div style="background: #f5f5f5; padding: 20px; margin: 20px 0;">
<h2>Order Details</h2>
<p><strong>Order Number:</strong> ${order.orderNumber}</p>
<p><strong>Total:</strong> $${order.total.toFixed(2)}</p>
<p><strong>Status:</strong> Processing</p>
</div>
<h3>Items Ordered:</h3>
<ul>
${order.items.map((item: any) =>
`<li>${item.name} - Quantity: ${item.quantity} - $${item.price}</li>`
).join('')}
</ul>
<p>You'll receive a shipping notification once your order ships.</p>
<hr>
<p style="font-size: 12px; color: #666;">
Track your order:
<a href="https://shop.yourdomain.com/track/${order.trackingId}">
Track Order
</a>
</p>
</div>
`
await this.inbound.reply(originalEmail, {
from: 'orders@yourdomain.com',
subject: `Order Confirmation - #${order.orderNumber}`,
html: confirmationHtml,
text: `Order confirmed! Order #${order.orderNumber}. Total: $${order.total}`
})
}
/**
* Parse items from text
*/
private parseItems(itemsText: string): any[] {
// Simplified parsing - implement according to your format
const lines = itemsText.trim().split('\n')
return lines.map(line => {
const parts = line.split('-').map(p => p.trim())
return {
name: parts[0] || 'Unknown Item',
quantity: parseInt(parts[1]) || 1,
price: parseFloat(parts[2]) || 0
}
}).filter(item => item.name !== 'Unknown Item')
}
/**
* Notify warehouse of new order
*/
private async notifyWarehouse(order: any) {
await this.inbound.emails.send({
from: 'system@yourdomain.com',
to: 'warehouse@yourdomain.com',
subject: `New Order for Fulfillment - #${order.orderNumber}`,
html: `
<h2>New Order for Fulfillment</h2>
<p>Order #${order.orderNumber} is ready for processing.</p>
<p>Customer: ${order.customerEmail}</p>
<p>Items: ${order.items.length}</p>
<p>Priority: ${order.priority || 'Standard'}</p>
<a href="https://warehouse.yourdomain.com/orders/${order.id}">
View Order Details
</a>
`
})
}
}
// Helper function (implement according to your system)
async function createOrder(orderData: any) {
return {
id: 'order_123',
trackingId: 'track_123',
...orderData
}
}
Email-to-SMS Bridge
Forward urgent emails as SMS messages:services/email-to-sms.ts
Copy
import { Inbound } from '@inboundemail/sdk'
import type { InboundWebhookPayload } from '@inboundemail/sdk'
// Assume you have an SMS service like Twilio
import { sendSMS } from '@/lib/sms'
export class EmailToSMSBridge {
private inbound: Inbound
private urgentKeywords = ['urgent', 'emergency', 'critical', 'asap', 'immediately']
constructor() {
this.inbound = new Inbound({
apiKey: process.env.INBOUND_API_KEY!
})
}
/**
* Process email and send SMS if urgent
*/
async processEmail(payload: InboundWebhookPayload) {
const { email } = payload
// Check if urgent
if (!this.isUrgent(email)) {
return
}
// Get recipient phone number based on email address
const phoneNumber = await this.getPhoneNumber(email.recipient)
if (!phoneNumber) {
console.log(`No phone number found for ${email.recipient}`)
return
}
// Create SMS message
const smsMessage = this.createSMSMessage(email)
// Send SMS
await sendSMS({
to: phoneNumber,
body: smsMessage
})
// Send confirmation email
await this.sendSMSConfirmation(email, phoneNumber)
}
/**
* Check if email is urgent
*/
private isUrgent(email: any): boolean {
const subject = email.subject?.toLowerCase() || ''
const body = email.cleanedContent.text?.toLowerCase() || ''
return this.urgentKeywords.some(keyword =>
subject.includes(keyword) || body.includes(keyword)
)
}
/**
* Create SMS message from email
*/
private createSMSMessage(email: any): string {
const from = email.from?.addresses[0]?.address || 'Unknown'
const subject = email.subject || 'No subject'
const preview = email.cleanedContent.text?.substring(0, 100) || ''
return `URGENT EMAIL from ${from}: ${subject}. ${preview}...`
}
/**
* Send confirmation that SMS was sent
*/
private async sendSMSConfirmation(email: any, phoneNumber: string) {
await this.inbound.reply(email, {
from: 'notifications@yourdomain.com',
subject: 'Urgent message forwarded to SMS',
html: `
<p>Your urgent message has been forwarded as an SMS to ${phoneNumber}.</p>
<p>Original message:</p>
<blockquote style="border-left: 3px solid #ccc; padding-left: 10px;">
${email.cleanedContent.html || email.cleanedContent.text}
</blockquote>
`
})
}
/**
* Get phone number for email recipient
*/
private async getPhoneNumber(email: string): Promise<string | null> {
// Implement lookup logic based on your user database
const phoneMap: Record<string, string> = {
'oncall@yourdomain.com': '+1234567890',
'support@yourdomain.com': '+0987654321'
}
return phoneMap[email] || null
}
}
Complete Application Example
Full Next.js application with email integration:app/layout.tsx
Copy
import { Inbound } from '@inboundemail/sdk'
import { EmailProvider } from '@/contexts/email-context'
// Initialize SDK globally
const inbound = new Inbound({
apiKey: process.env.INBOUND_API_KEY!,
defaultReplyFrom: 'app@yourdomain.com'
})
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<EmailProvider inbound={inbound}>
{children}
</EmailProvider>
</body>
</html>
)
}
contexts/email-context.tsx
Copy
'use client'
import { createContext, useContext } from 'react'
import type { InboundEmailClient } from '@inboundemail/sdk'
const EmailContext = createContext<InboundEmailClient | null>(null)
export function EmailProvider({
children,
inbound
}: {
children: React.ReactNode
inbound: InboundEmailClient
}) {
return (
<EmailContext.Provider value={inbound}>
{children}
</EmailContext.Provider>
)
}
export function useInbound() {
const context = useContext(EmailContext)
if (!context) {
throw new Error('useInbound must be used within EmailProvider')
}
return context
}
app/dashboard/page.tsx
Copy
'use client'
import { useEffect, useState } from 'react'
import { useInbound } from '@/contexts/email-context'
import type { EmailItem, EndpointWithStats, DomainWithStats } from '@inboundemail/sdk'
export default function Dashboard() {
const inbound = useInbound()
const [emails, setEmails] = useState<EmailItem[]>([])
const [endpoints, setEndpoints] = useState<EndpointWithStats[]>([])
const [domains, setDomains] = useState<DomainWithStats[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
loadDashboardData()
}, [])
async function loadDashboardData() {
try {
const [emailsRes, endpointsRes, domainsRes] = await Promise.all([
inbound.mail.list({ limit: 10 }),
inbound.endpoints.list(),
inbound.domains.list()
])
setEmails(emailsRes.emails)
setEndpoints(endpointsRes.data)
setDomains(domainsRes.data)
} catch (error) {
console.error('Failed to load dashboard:', error)
} finally {
setLoading(false)
}
}
if (loading) {
return <div>Loading dashboard...</div>
}
return (
<div className="p-8">
<h1 className="text-3xl font-bold mb-8">Email Dashboard</h1>
{/* Stats Overview */}
<div className="grid grid-cols-3 gap-6 mb-8">
<div className="bg-white p-6 rounded-lg shadow">
<h3 className="text-lg font-semibold">Domains</h3>
<p className="text-3xl font-bold">{domains.length}</p>
<p className="text-sm text-gray-500">
{domains.filter(d => d.status === 'verified').length} verified
</p>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<h3 className="text-lg font-semibold">Endpoints</h3>
<p className="text-3xl font-bold">{endpoints.length}</p>
<p className="text-sm text-gray-500">
{endpoints.filter(e => e.isActive).length} active
</p>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<h3 className="text-lg font-semibold">Recent Emails</h3>
<p className="text-3xl font-bold">{emails.length}</p>
<p className="text-sm text-gray-500">Last 24 hours</p>
</div>
</div>
{/* Recent Emails */}
<div className="bg-white rounded-lg shadow">
<h2 className="text-xl font-semibold p-6 border-b">Recent Emails</h2>
<div className="divide-y">
{emails.map(email => (
<div key={email.id} className="p-6 hover:bg-gray-50">
<div className="flex justify-between items-start">
<div>
<h3 className="font-semibold">{email.subject}</h3>
<p className="text-sm text-gray-500">
From: {email.from} • To: {email.recipient}
</p>
<p className="text-sm mt-2">{email.preview}</p>
</div>
<div className="text-sm text-gray-500">
{new Date(email.receivedAt).toLocaleString()}
</div>
</div>
</div>
))}
</div>
</div>
</div>
)
}