An executive-style AI assistant that reads your email, identifies why people are contacting you, and generates actionable task cards β not just messages. This isn't another inbox. It's a decision-routing system, built with a personal assistant metaphor.
Most email tools treat messages as the primary unit. This assistant doesn't.
Instead, it treats your inbox as:
- A stream of requests for your attention
- That need to be classified, delegated, or replied to
- In a workflow-driven interface (not a chronological list)
Think: 1950s secretary triaging your morning mail.
Layer | Tech |
---|---|
Frontend | Next.js + Tailwind CSS |
Backend | FastAPI + Beanie (MongoDB ODM) |
Database | MongoDB Atlas |
Auth | (TBD β Clerk or custom) |
AI | OpenAI or mock assistant logic |
email-assistant/
βββ backend/
β βββ app/ # FastAPI app, routes, models
β βββ tests/ # Pytest-based backend tests
β βββ .env.example # Sample environment config for FastAPI
βββ frontend/
β βββ app/ # Next.js app router
β βββ components/ # TaskCard, BottomNav, etc.
β βββ .env.example # Sample environment config for Next.js
βββ README.md
βββ .gitignore
cd backend
poetry install
poetry run uvicorn app.main:app --reload
cd frontend
npm install
npm run dev
- API endpoints for email-task management:
POST /api/v1/email
to ingest messages and create persisted tasksGET /api/v1/tasks
&PATCH /api/v1/tasks/{id}
to retrieve and update tasks
- AI/Rule-based services for:
- Context classification (scheduling, sales, support, etc.)
- One-line summary generation
- Quick action suggestion for reply, archive, schedule, etc.
- Responsive TaskCard UI:
- Displays sender, subject, summary and action buttons
- Supports in-card interactions (Done, Snooze, Archive) without a full page reload
- Bottom navigation bar with active tab highlighting for main app sections
- Mobile-first, touch-friendly design and persistent MongoDB storage
When a user forwards an email (e.g., from Gmail or Outlook), the original sender and subject are often embedded in the body of the forwarded message, rather than preserved in the email headers. The assistant automatically parses the body of incoming emails to extract this information.
- The backend scans the email body for common patterns like:
From: Jane Doe <jane@example.com>
Subject: Original Subject Line
- If these are found, the assistant uses them as the sender and subject for the created task, instead of the forwarding user's info.
- If multiple
From:
orSubject:
fields are present, the first instance is used. - If no forwarded headers are found, the system falls back to the forwarding user's metadata.
- Malformed or partial headers are handled gracefully, defaulting to the forwarding user's info if needed.
Example:
From: Jane Doe <jane@example.com>
Subject: Q2 Budget Review
Body: Please see attached for the Q2 budget review.
This will result in a task with sender Jane Doe <jane@example.com>
and subject Q2 Budget Review
, even if the email was forwarded by someone else.
See backend/app/utils/email_utils.py
and backend/app/services/email_task_mapper.py
for implementation details.
Create environment files to configure AI classification and the API base URL:
- Examples exist in .env.example files
Backend (in backend/.env
or project root .env
):
OPENAI_API_KEY=your_api_key_here
OPENAI_API_MODEL=gpt-3.5-turbo
USE_AI_CONTEXT=true
USE_AI_SUMMARY=true
USE_AI_ACTIONS=true
MONGODB_URI=<your_mongodb_uri>
MONGODB_DB=<your_database_name>
# Mailbox configuration
MAILBOX_DOMAIN=mailslurp.biz
MAILBOX_API_KEY=your_mailslurp_api_key
# IMAP configuration (for temporary email fetching)
IMAP_HOST=mailslurpimap.click
IMAP_PORT=8993
IMAP_USERNAME=your_imap_username
IMAP_PASSWORD=your_imap_password
Frontend (in frontend/.env.local
):
NEXT_PUBLIC_API_BASE=http://localhost:8000
# (Optional) Clerk or Auth key if using identity
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your-publishable-key
CLERK_SECRET_KEY=your-secret-key
# Flags or feature toggles
NEXT_PUBLIC_DEBUG=true
The assistant suggests relevant actions for each email task based on its content and context. This can be powered by either:
-
AI-based suggestions (when
USE_AI_ACTIONS=true
):- Uses OpenAI to analyze email content and context
- Generates contextually relevant actions (e.g., "Schedule Meeting" for calendar requests)
- Falls back to rule-based if AI is unavailable
-
Rule-based suggestions (default):
- Uses predefined strategies based on email context
- Provides common actions like Reply, Forward, Archive
- Ensures at least 2-3 relevant actions per task
Each task will always have 2-3 suggested actions, regardless of the suggestion method used.
# Backend tests
cd backend
poetry run pytest
# Frontend tests
cd frontend
npm run test
- Incoming email webhooks are protected by an API key and IP whitelist.
- The
WebhookSecurity
model (Beanie) stores the current API key, allowed IPs, and activation status. - All webhook access attempts are logged with timestamp, IP, and status (success/failure) for auditability.
- Security validation is enforced on the
/api/v1/email/incoming
endpoint:- Requests must include a valid
x-api-key
header. - Requests must originate from an allowed IP address.
- Invalid or missing credentials result in 400/403 errors.
- Requests must include a valid
- Environment variables:
WEBHOOK_SECURITY_ENABLED
(default: true) β Toggle webhook security (for development/testing).WEBHOOK_DEFAULT_ALLOWED_IPS
β Comma-separated list of IPs allowed by default (set in.env.example
).
- Admin Panel:
- Admins can view and update the API key and allowed IPs via the
/admin/webhook
UI. - API key can be rotated and copied securely from the admin panel.
- Admins can view and update the API key and allowed IPs via the
Request Example:
POST /api/v1/email/incoming HTTP/1.1
Host: yourdomain.com
x-api-key: <your_api_key>
Content-Type: application/json
{
"sender": "forwarder@provider.com",
"subject": "Fwd: Important client request",
"body": "..."
}
- Only requests with a valid API key and from an allowed IP will be processed.
- Invalid requests receive clear error messages and are logged for review.
- All webhook access attempts (success and failure) are logged in
backend/app/utils/logging.py
. - Log entries include:
- Timestamp
- Event type (e.g.,
webhook_access
,api_key_validation
) - IP address
- Status (success/failure)
- Optional details (never includes sensitive data)
- Logs are suitable for security audits and can be integrated with external monitoring tools.
- Example log entry:
2024-05-01 12:34:56,789 - INFO - event=webhook_access status=failure ip=8.8.8.8 details=Invalid API key
The duplicate detection system ensures that emails with similar or identical content are not processed multiple times. This is achieved through a combination of exact matching and fuzzy matching techniques.
-
Exact Matching:
- Emails are first checked for exact matches using their
message_id
or a hash of their sender, subject, and body. - If an exact match is found, the email is flagged as a duplicate.
- Emails are first checked for exact matches using their
-
Fuzzy Matching:
- If no exact match is found, the system uses a similarity algorithm to compare the subject and body of the email with recent emails.
- The similarity is calculated using the
SequenceMatcher
from Python'sdifflib
module. - A configurable threshold (default: 0.9) determines whether two emails are considered duplicates based on their similarity score.
-
Performance Optimization:
- Recent emails are limited to a manageable number (e.g., 100) to ensure performance remains acceptable even with large email volumes.
- Database indexes are used to optimize exact match lookups.
-
Threshold:
- The similarity threshold can be configured via the
DUPLICATE_THRESHOLD
environment variable. - Example:
DUPLICATE_THRESHOLD=0.85
in the.env
file.
- The similarity threshold can be configured via the
-
Environment Variable:
DUPLICATE_THRESHOLD=0.9
-
Similar but Non-Identical Emails:
- The system ensures that emails with minor variations (e.g., typos or slight rephrasing) are flagged as duplicates if they exceed the similarity threshold.
-
Large Email Volumes:
- The system is designed to handle large volumes of emails efficiently by limiting the scope of fuzzy matching and leveraging database optimizations.
For more details, see the implementation in backend/app/services/duplicate_detection.py
.
The AI Email Assistant provides each user with a unique mailbox address that can be used to forward emails for processing. This feature simplifies email processing by eliminating the need to manually forward emails to a generic address.
-
Unique Address Generation:
- Each user is automatically assigned a unique mailbox address (e.g.,
user123@mailslurp.biz
). - The address is generated based on a combination of user ID and a random component to ensure uniqueness.
- The address is stored in the
UserSettings
model in the database.
- Each user is automatically assigned a unique mailbox address (e.g.,
-
Email Forwarding:
- Users can set up automatic forwarding from their primary email accounts to their unique mailbox address.
- Instructions for setting up forwarding in Gmail, Outlook, and Apple Mail are provided in the Settings page.
-
Email Processing:
- Emails sent to the unique mailbox address are automatically associated with the correct user.
- The system processes these emails and creates tasks based on their content.
- This ensures that emails are correctly attributed to the user who owns the mailbox.
The mailbox provisioning system requires the following environment variables:
# Mailbox configuration
MAILBOX_DOMAIN=mailslurp.biz
MAILBOX_API_KEY=your_mailslurp_api_key
# IMAP configuration (for temporary email fetching)
IMAP_HOST=mailslurpimap.click
IMAP_PORT=8993
IMAP_USERNAME=your_imap_username
IMAP_PASSWORD=your_imap_password
For more implementation details, see backend/app/services/mailbox_provisioning.py
.
The configured inbox has a webhook event NEW_MAIL which will send all new email over to the /email/incoming
webhook. (TODO)
In the meantime, in order to manually poll from the inbox via IMAP, manually call the API endpoint
/api/v1/email/get/{email-address}
This API will automatically poll the inbox of the given email address with IMAP to pull emails. This functionality will remain after the webhook is implemented, but will be deprecated in favor of the webhook approach.
The AI Email Assistant includes a spam filtering system to ensure that irrelevant or spammy emails do not clutter your task list. Here's how it works:
-
Keyword-Based Detection:
- The system uses a predefined list of spam keywords (e.g., "free money," "urgent offer") to identify spam emails.
- Emails containing these keywords in their subject or body are flagged as spam.
-
Task Skipping:
- Emails flagged as spam are not converted into tasks. Instead, they are stored in the database with a
is_spam
flag set totrue
.
- Emails flagged as spam are not converted into tasks. Instead, they are stored in the database with a
-
User Preferences:
- Spam filtering can be toggled on or off via the Email Settings page in the UI.
- Navigate to the Spam Alert Card in the UI.
- Review the list of emails flagged as spam.
- Click the Not Spam button next to an email to mark it as not spam.
- The email will be removed from the spam list and will be eligible for task creation.
-
Fetch Spam Emails:
GET /api/v1/emails/spam
- Returns a list of all emails flagged as spam.
-
Mark Email as Not Spam:
PATCH /api/v1/emails/{email_id}/not-spam
- Marks a specific email as not spam and removes the spam flag.
- An email with the subject "Win a prize" is received.
- The system detects spam keywords and flags the email as spam.
- The email appears in the Spam Alert Card in the UI.
- The user reviews the email and clicks "Not Spam."
- The email is unflagged and processed for task creation.