ReachInbox Email Aggregator - Development Plan
Breaks a full-stack email aggregator into 6 sequential phases with mandatory, core, and stretch tiers for an interview project.
What this file does
Breaks a full-stack email aggregator into 6 sequential phases with mandatory, core, and stretch tiers for an interview project.
When to use it
- Building an AI-driven email onebox with real-time IMAP sync
- Implementing RAG-based reply suggestions on email data
- Structuring a multi-phase coding assignment for a job interview
- Setting up Elasticsearch and Qdrant for email search and vector storage
Assumes this stack
ReachInbox Email Aggregator - Development Plan
Project Overview
Build an AI-driven email onebox aggregator with real-time IMAP synchronization, intelligent categorization, and RAG-powered reply suggestions using TypeScript and Node.js.
Phase 0: Project Setup
1. Initialize Project
npm init -y
npm install typescript @types/node ts-node --save-dev
npx tsc --init
2. Install Core Dependencies
# IMAP Client
npm install node-imap mailparser
# Database & Search
npm install @elastic/elasticsearch @qdrant/js-client-rest
# Server & Utilities
npm install express dotenv cors
npm install @types/express @types/node-imap --save-dev
# AI Integration
# Use native fetch for Gemini API
3. Docker Services Setup
Create docker-compose.yml:
- Elasticsearch (port 9200) - Email search and storage
- Qdrant (ports 6333, 6334) - Vector database for RAG
4. Project Structure
src/
├── services/
│ ├── imap/ # Email synchronization
│ ├── elasticsearch/ # Search & indexing
│ ├── gemini/ # AI categorization & embeddings
│ └── vector-db/ # RAG implementation
├── controllers/ # API handlers
├── routes/ # Express routes
├── types/ # TypeScript interfaces
└── utils/ # Helper functions
5. Environment Configuration
Create .env.example:
# IMAP Accounts (minimum 2)
IMAP_EMAIL_1=
IMAP_PASSWORD_1=
IMAP_EMAIL_2=
IMAP_PASSWORD_2=
# Elasticsearch
ELASTICSEARCH_HOST=localhost:9200
# AI
GEMINI_API_KEY=
# Integrations
SLACK_WEBHOOK_URL=
WEBHOOK_SITE_URL=
# Vector DB
QDRANT_HOST=localhost
QDRANT_PORT=6333
Phase 1: Real-Time Email Synchronization ⭐ MANDATORY
Core Requirements
- Persistent IMAP connections using IDLE mode
- No polling or cron jobs
- Sync last 30 days of emails
- Support minimum 2 email accounts
Implementation Steps
1.1 IMAP Service Setup
Create src/services/imap/ImapClient.ts:
- Initialize connection per email account
- Authenticate using credentials from environment
1.2 Initial History Fetch
- Fetch all major folders (INBOX, Sent, Drafts)
- Use IMAP SEARCH:
SINCE <30 days ago> - Fetch ENVELOPE and BODYSTRUCTURE
- Parse email metadata (from, to, subject, date)
- Extract plain text body
1.3 Real-Time IDLE Listener
- Transition to IDLE mode after initial sync
- Listen for events:
mail- New email arrivalexpunge- Email deletion
- Fetch new emails immediately on event
- Pass to indexing pipeline
1.4 Connection Watchdog
- Ping connection every 29 minutes
- Re-send IDLE command to maintain session
- Handle disconnections with auto-reconnect
- Implement exponential backoff on failures
1.5 Data Structure
interface EmailDocument {
id: string;
accountId: string;
folder: string;
subject: string;
body: string;
from: string;
to: string[];
date: Date;
aiCategory: string;
indexedAt: Date;
}
Phase 2: Elasticsearch Storage & Search ⭐ CORE
Implementation Steps
2.1 Elasticsearch Client Setup
Create src/services/elasticsearch/ElasticsearchClient.ts:
- Connect to
http://localhost:9200 - Create
emailsindex with proper mapping
2.2 Index Mapping
{
subject: { type: 'text' },
body: { type: 'text' },
accountId: { type: 'keyword' },
folder: { type: 'keyword' },
date: { type: 'date' },
aiCategory: { type: 'keyword' },
from: { type: 'keyword' },
to: { type: 'keyword' }
}
2.3 Indexing Pipeline
- Receive email from IMAP service
- Strip HTML, convert to plain text
- Index immediately to Elasticsearch
- Return indexed document ID
2.4 Search Implementation
Create search endpoint: GET /api/emails/search
Query parameters:
q- Search term (subject/body)account- Filter by accountIdfolder- Filter by foldercategory- Filter by AI category
Query structure:
{
query: {
bool: {
must: [
{ multi_match: { query: searchTerm, fields: ["subject", "body"] } }
],
filter: [
{ term: { accountId: account } },
{ term: { folder: folder } }
]
}
}
}
Phase 3: AI Email Categorization ⭐ CORE
Categories
- Interested
- Meeting Booked
- Not Interested
- Spam
- Out of Office
Implementation Steps
3.1 Gemini Integration
Create src/services/gemini/GeminiClient.ts:
- Use Gemini API endpoint
- Configure API key from environment
3.2 System Prompt Definition
Analyze the email and categorize it into ONE of these categories:
- Interested: Lead shows interest
- Meeting Booked: Meeting scheduled
- Not Interested: Negative response
- Spam: Unwanted promotional emails
- Out of Office: Auto-reply responses
Return JSON with category field only.
3.3 JSON Schema Configuration
{
type: "OBJECT",
properties: {
category: {
type: "STRING",
enum: ["Interested", "Meeting Booked", "Not Interested", "Spam", "Out of Office"]
}
},
required: ["category"]
}
3.4 Categorization Flow
- Email indexed in Elasticsearch
- Send subject + body to Gemini API
- Receive category response
- Update Elasticsearch document with
aiCategory - Trigger webhook if category is "Interested"
3.5 Error Handling
- Implement retry logic with exponential backoff
- Handle rate limits gracefully
- Default to "Uncategorized" on failure
- Log all categorization attempts
Phase 4: Slack & Webhook Integration ⭐ CORE
Implementation Steps
4.1 Webhook Service
Create src/services/webhooks/WebhookClient.ts
4.2 Trigger Condition
Activate when aiCategory === "Interested"
4.3 Slack Notification
async function sendSlackNotification(email: EmailDocument) {
const payload = {
text: `🎯 Interested Lead Detected!`,
blocks: [
{
type: "section",
fields: [
{ type: "mrkdwn", text: `*From:* ${email.from}` },
{ type: "mrkdwn", text: `*Subject:* ${email.subject}` },
{ type: "mrkdwn", text: `*Account:* ${email.accountId}` }
]
}
]
};
await fetch(SLACK_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
}
4.4 Generic Webhook
async function triggerGenericWebhook(email: EmailDocument) {
await fetch(WEBHOOK_SITE_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event: 'InterestedLead',
timestamp: new Date().toISOString(),
email: {
id: email.id,
from: email.from,
subject: email.subject,
accountId: email.accountId,
category: email.aiCategory
}
})
});
}
Phase 5: Frontend Interface 🌟 UNLOCKS FRONTEND
Prerequisites
Complete Phases 1-4 with Postman validation
Backend API Endpoints
5.1 Required Endpoints
GET /api/accounts // List configured email accounts
GET /api/emails // Paginated email list
GET /api/emails/search // Search with filters
GET /api/emails/:id // Single email details
Frontend Implementation
5.2 Technology Choice
- Simple HTML/CSS/JS, or
- React with TypeScript
5.3 Core Components
Email List
- Display emails in table/card format
- Show: subject, from, date, AI category
- Pagination support
Filter Panel
- Account dropdown (from
/api/accounts) - Folder dropdown (INBOX, Sent, etc.)
- Category filter (AI categories)
Search Bar
- Full-text search input
- Calls
/api/emails/searchendpoint
AI Category Tags
- Visual badges for each category
- Color-coded (e.g., green for Interested)
5.4 Integration Flow
- Fetch accounts on page load
- Display email list with filters
- Update list on filter/search change
- Show AI category prominently
- Click email to view details
Phase 6: RAG Suggested Replies 🏆 INTERVIEW FAST-TRACK
Prerequisites
Complete Phase 5 with working UI
Implementation Steps
6.1 Vector Database Setup
Initialize Qdrant collection:
{
collection_name: "product_knowledge",
vectors: {
size: 768, // Gemini embedding dimension
distance: "Cosine"
}
}
6.2 Knowledge Base Preparation
Create training data file with:
- Product information
- Outreach agenda
- Meeting booking links
- Common responses
Split into chunks (200-300 words each)
6.3 Embedding Generation
async function generateEmbedding(text: string) {
const response = await fetch(
`https://generativelanguage.googleapis.com/v1/models/embedding-001:embedContent`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: "models/embedding-001",
content: { parts: [{ text }] }
})
}
);
return response.json();
}
6.4 Index Knowledge Base
For each chunk:
- Generate embedding
- Store in Qdrant with metadata
- Include original text as payload
6.5 RAG Pipeline
Endpoint: POST /api/emails/:id/suggest-reply
Flow:
- Receive email ID
- Fetch email content from Elasticsearch
- Generate embedding for email text
- Query Qdrant for top 3 similar chunks
- Assemble prompt:
System: Act as professional assistant Context: [Retrieved chunks] Email: [Original email] Instruction: Draft reply based ONLY on context - Send to Gemini API
- Return suggested reply
6.6 Frontend Integration
- Add "Suggest Reply" button on email detail view
- Display loading state during generation
- Show suggested reply in text area
- Allow editing before sending
Testing Strategy
Phase 1-4: Postman Testing
- Test IMAP sync with real accounts
- Verify Elasticsearch indexing
- Check AI categorization accuracy
- Validate webhook triggers
Phase 5: UI Testing
- Test all filters and search
- Verify email display
- Check responsive design
- Validate API integration
Phase 6: RAG Testing
- Test reply relevance
- Verify context grounding
- Check response quality
- Validate edge cases
Deployment Checklist
Code Quality
- TypeScript strict mode enabled
- Proper error handling throughout
- Environment variables for all configs
- No hardcoded credentials
- Logging implemented (winston/pino)
- Code modular and organized
Documentation
- README with setup instructions
- Architecture diagram included
- API documentation
- Environment variable examples
- Known limitations documented
Repository
- Private GitHub repository created
- Access granted to reviewers
- .gitignore configured
- Clean commit history
- No sensitive data committed
Demo Video
- Screen recording prepared
- Real-time sync demonstrated
- All features showcased
- Clear audio narration
- Under 5 minutes duration
Success Criteria
Minimum Viable Implementation
✅ Phase 1: IMAP IDLE working (no polling) ✅ Phase 2: Elasticsearch search functional ✅ Phase 3: AI categorization accurate ✅ Phase 4: Webhook notifications working
Strong Candidate
✅ All above phases complete ✅ Phase 5: Functional UI integrated
Exceptional Candidate
✅ All above phases complete ✅ Phase 6: RAG replies implemented 🏆 Direct final interview invitation
Key Technical Decisions
IMAP Implementation
- Use
node-imaplibrary - Maintain persistent connections
- Implement connection watchdog
- Handle network interruptions gracefully
Search Strategy
- Elasticsearch for full-text search
- Keyword fields for exact filtering
- Combine
mustandfilterclauses - Optimize query performance
AI Integration
- Gemini API for categorization
- JSON mode for structured output
- System prompts for consistency
- Error handling with retries
RAG Architecture
- Qdrant for vector storage
- Chunk size: 200-300 words
- Top K retrieval: 3 chunks
- Context-grounded generation
Notes
- Focus on quality over quantity
- Complete phases sequentially
- Test thoroughly before moving forward
- Document all architectural decisions
- Implement proper error handling from start
- Use TypeScript types throughout
- No plagiarism - original implementation required
What's inside
6 phases, 5 code blocks, 3 TypeScript interfaces, 1 docker-compose reference, 1 deployment checklist
Change this for your project
- Replace
ALANAK777/ReachInBox-Assignmentwith your own repository name - Replace
GEMINI_API_KEYenvironment variable with your actual API key provider - Replace
SLACK_WEBHOOK_URLandWEBHOOK_SITE_URLwith your own webhook endpoints
Where it goes
Keep it in your repository where the agent or team that needs it will read it.
Worth borrowing
- Phase gating: each phase requires the previous one to be complete, preventing scope creep
- Mandatory vs stretch tiers let you demonstrate a minimum viable product while showing ambition
- Connection watchdog with 29-minute ping and exponential backoff for persistent IMAP IDLE
Related Documents
Building SupportX AI Assist: A Multi-Agent IT Support System
Describes building a multi-agent IT support system with AutoGen, Azure AI Search, and Gemini embeddings for instant issue resolution and automatic escalation.
Intelligent Document Query Platform — GitHub-ready Low-Level Design (LLD)
Provides a copy-ready low-level design for a serverless document query platform with vector search and LLM integration.
Graph Matching with Topological Features
Teaches enhanced graph matching by combining spatial distances with node2vec and commute times embeddings, then applying the Hungarian algorithm.
Pulse — Life Cofounder | Build Log
Documents a full-stack monorepo that ingests LinkedIn and GitHub data, generates embeddings in-browser, and provides a RAG chat with an AI cofounder.