This repository contains the full-stack implementation for the ReachInbox Associate Backend Engineer assignment. It's an AI-powered email aggregator that synchronizes an IMAP account in real-time, makes emails searchable, and provides intelligent features like automated categorization and context-aware reply suggestions.
Real-Time Email Synchronization: Connects to an IMAP account and uses IDLE mode to sync new emails instantly without polling.
Full-Text Search: All emails are indexed in Elasticsearch, allowing for fast, powerful search across subjects, bodies, and senders.
AI-Based Categorization: Each email is automatically categorized into labels like Interested, Not Interested, Meeting Booked, etc., using a generative AI model.
Automated Webhooks: When an email is categorized as "Interested," the system automatically sends notifications to both a Slack channel and a generic webhook endpoint.
Web-Based UI: A simple, single-page frontend to view, search, and filter emails, displaying their AI-generated categories.
AI-Powered Reply Suggestions (RAG): A bonus feature implementing a Retrieval-Augmented Generation (RAG) pipeline. The system retrieves relevant context from a Qdrant vector database to help the AI draft highly relevant replies.
Backend: Node.js, Express.js, TypeScript
Real-Time Sync: node-imap
Databases:
Elasticsearch: For full-text search and filtering.
Qdrant: Vector database for the RAG implementation.
AI & Parsing:
Generative AI APIs (Gemini/OpenAI/Groq) for categorization and generation.
Embedding APIs for vector creation.
mailparser for robust email content parsing.
Environment: Docker, Docker Compose
The application is built on a modular, service-oriented architecture:
IMAP Sync Service (imapService.ts): Establishes a persistent connection to the IMAP server. It performs an initial sync of historical emails and then listens for new emails in real-time.
Persistence Layer:
Elasticsearch (elasticService.ts): All parsed emails are indexed here. This service provides methods to create the index and perform complex search queries.
Qdrant (qdrantService.ts): Stores vectorized text data (the "outreach agenda") for the RAG pipeline.
AI Services:
Categorization (aiService.ts): A dedicated service that takes email content and returns a JSON-formatted category from a generative AI model.
Embeddings (embeddingService.ts): A service to convert text into vector embeddings for storage and search in Qdrant.
API & Web Layer:
Express.js (index.ts): Provides the REST API endpoints (/api/emails/search, /api/emails/suggest-reply).
Frontend (index.html): A self-contained vanilla JavaScript UI that communicates with the backend API.
Follow these steps to get the project running locally.
- Clone the Repository Bash
git clone cd 2. Create the Environment File Create a .env file in the root of the project by copying the example file.
Bash
cp .env.example .env Now, open the .env file and fill in all the required values:
IMAP_USER=your_email@gmail.com IMAP_PASSWORD=your_google_app_password IMAP_HOST=imap.gmail.com
GEMINI_API_KEY= OPENAI_API_KEY= GROQ_API_KEY=
SLACK_WEBHOOK_URL=https://hooks.slack.com/... WEBHOOK_SITE_URL=https://webhook.site/... 3. Start the Databases Make sure you have Docker running on your machine.
Bash
docker-compose up -d This will start the Elasticsearch and Qdrant containers in the background.
- Install Dependencies Bash
npm install 5. Seed the Vector Database (For RAG Feature) This is an optional step to add your personal data for the reply-suggestion feature.
Bash
npx ts-node scripts/seed.ts Running the Application Once the setup is complete, run the following command to start the backend server:
Bash
npm start The server will start, connect to the IMAP server, and begin the initial email synchronization.
Using the Frontend To use the UI, simply open the index.html file in your web browser.
API Endpoints Search Emails:
GET /api/emails/search
Query Params: account (string, required), q (string, optional)
Example: http://localhost:3000/api/emails/search?account=your_email@gmail.com&q=interview
Suggest a Reply:
POST /api/emails/suggest-reply
Body (JSON):
JSON
{ "subject": "Original email subject", "body": "Original email body text" }