Skip to content
xfdzcoderPublic
forked from kawing11a/mailhub

About

Self-hosted, multi-tenant email management platform unifying IMAP/SMTP, Gmail OAuth, and Microsoft Outlook OAuth into a modern Next.js 16 dashboard with BullMQ background sync, Meilisearch full-text search, PWA support, and Web Push notifications.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

424 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MailHub Icon

MailHub

A multi-tenant email management platform built with Next.js 16. Connect IMAP/SMTP, Gmail OAuth, or Microsoft/Outlook OAuth accounts, sync emails via background workers, and manage everything from a unified dashboard with full-text search, drag-and-drop labels, activity logs, spam risk detection, granular member access control, Progressive Web App (PWA) support, and Web Push notifications.

Sponsor MailHub Buy Me a Coffee

Screenshots & Demo

MailHub running locally with synthetic inbox data and compact email actions
Real MailHub email viewer showing a long subject and synthetic development message

Captured from the local development app using fictional demo data. No live mail accounts are connected.


Dashboard Overview Multi-Account Email Stream Mobile Responsive View
Dashboard Overview Multi-Account Email Stream Mobile Responsive View

Why MailHub?

Managing multiple email accounts across local clients is a disjointed, sluggish experience. MailHub redesigns this workflow from the ground up:

  • 📬 Aggregated Stream (Unified Context): No more clicking through 10 different mailboxes. MailHub unifies all your IMAP and OAuth accounts into a single, unified email feed.
  • ⚙️ Server-Side Decoupling: Heavy syncing tasks are fully handled by backend BullMQ workers on your server. Your frontend Next.js 16 dashboard remains ultra-lightweight and buttery smooth, no matter how many accounts you add.
  • ⚡ Instant Global Search: Powered by Meilisearch. Search through hundreds of thousands of emails across all connected accounts simultaneously with millisecond-level results.
  • 🌐 Setup Once, Access Anywhere: Being a Self-hosted PWA, you only configure your email accounts once on your server. Any desktop or mobile device can then instantly access the fully synced dashboard without tedious re-configurations.

Tech Stack

Layer Technology
Framework Next.js 16 (App Router)
Language TypeScript 5
PWA / Client Service Worker, Web App Manifest, usePWAInstall hook, @dnd-kit (Drag & Drop)
Database PostgreSQL 16 + Prisma ORM 7 (@prisma/adapter-pg)
Search Meilisearch
Queue / Cache Redis 7 + BullMQ
Auth JWT (jose) + bcryptjs
Email Protocols IMAP (imapflow) · SMTP (nodemailer) · Gmail OAuth 2.0 API · Microsoft Outlook OAuth 2.0 API
UI React 19, Tailwind CSS 4, Lucide Icons, TipTap editor, Local geist fonts
State Zustand + TanStack React Query
Notifications Web Push (web-push + VAPID)
Testing Jest + ts-jest
Containerization Docker multi-stage build + Docker Compose

Key Features

  • 📧 Multi-Account & Multi-Tenant: Connect multiple IMAP/SMTP, Gmail OAuth, or Microsoft Outlook OAuth mailboxes across isolated organization workspaces.
  • 👥 Granular Access Control: Organization administrators can manage and grant per-member access permissions to specific email accounts.
  • 🤖 AI Email Assistance: Summarize labels, explain messages, draft or rewrite replies, extract action items, analyze tone, translate content, and deliver summaries through Telegram, WeCom, or generic webhooks.
  • ⚙️ Email Automation Rules: Apply ordered rules globally or by account/account label, with conditional or match-all execution for labels, read/star/risk state, webhooks, and forwarding.
  • ⚡ Realtime Email Sync: High-throughput background sync powered by BullMQ workers with automatic SPAM detection and Meilisearch indexation.
  • 📤 Multi-Provider Email Sender: Send emails using native SMTP, Google Gmail API, or Microsoft Graph/Outlook API with automatic token refreshing.
  • 📬 Aggregated All Emails View: View and filter emails across all connected accounts simultaneously in a unified stream, complete with customizable reading pane layouts (Right, Bottom, or Off).
  • 🗑️ Trash & Restore Flow: Full support for moving emails to Trash, restoring messages back to inbox/folders, and emptying trash per account.
  • 🔍 Instant Full-Text Search: Search headers, body content, and senders seamlessly across all connected accounts powered by Meilisearch.
  • 🏷️ Drag & Drop Label Management: Organize emails using customizable organization labels and interactive drag-and-drop actions.
  • 📱 Progressive Web App (PWA): Installable desktop/mobile experience with offline Service Worker caching, automated background update polling, system installation detection, and dynamic UI install buttons.
  • 📝 Rich Text Composer & Fullscreen Mode: Full-featured TipTap rich text editor with image resizing, attachments, signature auto-insertion, and seamless fullscreen composition.
  • 🔔 Real-Time SSE & Push Notifications: Instant inbox updates via Server-Sent Events (SSE) and native Web Push notifications.

Architecture

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│ Next.js App  │────▶│  PostgreSQL  │◀────│   Workers    │
│ (PWA + API)  │     │  (Prisma)    │     │  (BullMQ)    │
└──────┬───────┘     └──────────────┘     └──────┬───────┘
       │                                         │
       │             ┌──────────────┐            │
       ├────────────▶│  Meilisearch │◀───────────┤
       │             │  (Search)    │            │
       │             └──────────────┘            │
       │             ┌──────────────┐            │
       └────────────▶│    Redis     │◀───────────┘
                     │  (Queue/SSE) │
                     └──────────────┘
  • Next.js App — serves the dashboard UI, handles PWA service worker lifecycle, and exposes REST API routes.
  • Workers — background processes that sync email via IMAP/Gmail/Outlook, managed by BullMQ. Horizontally scalable with partition keys (WORKER_PARTITION).
  • Redis — backs the BullMQ job queue and server-sent events for realtime updates.
  • Meilisearch — powers instant full-text search across all synced emails.
  • PostgreSQL — primary data store for users, organizations, email accounts, permissions, emails, labels, favorites, and activity logs.

Data Model

Core entities managed via Prisma:

  • User — authentication identity (email + password hash)
  • Organization — multi-tenant workspace (slug-based)
  • OrganizationMember — user ↔ org membership with role permissions
  • EmailAccount — connected mailbox (IMAP/SMTP creds or OAuth tokens, encrypted at rest)
  • MemberEmailAccountAccess — granular per-member access permissions for specific email accounts
  • Email / EmailBody / Attachment — synced messages, bodies, and file metadata
  • Label / AccountLabel / EmailLabel — workspace and account-level labels applied to messages
  • EmailActivityLog — detailed audit log of email operations
  • PushSubscription — Web Push endpoints per organization user
  • FavoriteEmail — starred/favorited emails tracking per user account

Getting Started

Prerequisites

  • Node.js ≥ 20
  • Docker & Docker Compose (for PostgreSQL, Redis, Meilisearch)

1. Clone & Install

git clone https://github.com/kawing11a/mailhub.git
cd mailhub
npm install

2. Environment Variables

cp .env.example .env

Edit .env with your values. Required variables:

For a local synthetic demo, copy .env.example to .env.local instead and point its service URLs at your own loopback services. Leave the root .env absent; when .env exists, the app and Prisma use that real configuration and the demo seed refuses to run.

Variable Description
DATABASE_URL PostgreSQL connection string
REDIS_URL Redis connection string
MEILI_HOST Meilisearch URL
MEILI_MASTER_KEY Meilisearch admin key
JWT_SECRET Secret for signing JWT tokens
ENCRYPTION_KEY 64-char hex key for encrypting stored credentials
NEXT_PUBLIC_APP_URL Base application URL (e.g. https://localhost:3000)
GOOGLE_CLIENT_ID OAuth 2.0 Client ID for Google Workspace / Gmail
GOOGLE_CLIENT_SECRET OAuth 2.0 Client Secret for Google Workspace / Gmail
AZURE_CLIENT_ID OAuth 2.0 Application (Client) ID for Microsoft Outlook
AZURE_CLIENT_SECRET OAuth 2.0 Client Secret for Microsoft Outlook
AZURE_TENANT_ID Azure Tenant ID (e.g., common or specific Directory ID)

Optional worker and database controls use conservative defaults from .env.example:

Variable Default Description
DB_POOL_MAX 5 Maximum PostgreSQL connections per Node.js process
DB_CONNECTION_TIMEOUT_MS 10000 Maximum time to wait for a PostgreSQL connection
SYNC_WORKER_CONCURRENCY 1 Concurrent sync jobs per worker process
EMAIL_PERSIST_CONCURRENCY 3 Concurrent email persistence operations per account
IMAP_STARTUP_CONCURRENCY 10 IMAP listener connections opened in parallel at worker startup
GMAIL_POLL_INTERVAL_MS 60000 Gmail polling interval
GMAIL_REQUEST_INTERVAL_MS 1000 Minimum local spacing between Gmail API requests for one identity
IMAP_REQUEST_INTERVAL_MS 250 Minimum local spacing between Outlook/IMAP requests for one account
IMAP_RECONCILE_INTERVAL_MS 300000 IMAP recovery reconciliation interval
OUTBOUND_HOST_ALLOWLIST empty Exact host=cidr allowlist for reserved/non-public IMAP/SMTP destinations

Instance administrator provisioning

System Preferences affects every organization. Access requires both an exact user ID in the server-only INSTANCE_ADMIN_USER_IDS deployment allowlist and current administrator membership in the active organization. Organization administration alone does not grant instance access.

  1. Create or identify the intended user and explicitly assign organization administrator membership through the existing organization administration process.
  2. Obtain the user's immutable User.id from the database (users.id) or the authenticated /api/auth/me response (user.id). Use IDs, not email addresses, organization IDs, or wildcard patterns.
  3. Set the web application's runtime environment, for example INSTANCE_ADMIN_USER_IDS=user-id-one,user-id-two. Entries are comma-separated, trimmed, and matched exactly. Keep this variable server-only.
  4. Restart/recreate every web process with the same configuration. For Docker, supply it through the web container's environment or --env-file.

An absent, empty, or whitespace-only allowlist denies all instance settings reads and writes. To revoke access, remove the ID and restart the web processes; removing or downgrading the user's active organization membership also blocks access, even with an existing session.

On upgrade, existing organization administrators lose System Preferences access until explicitly provisioned. Existing global values, organization AI preferences, and personal semantic-search preferences continue to apply under their existing permissions. The instance-administrator policy itself grants no roles automatically. Version 0.4.0 removes the personal AI toggle. The initial create-admin command creates an organization administrator only; it does not provision instance access.

3. Start Services

# Start PostgreSQL, Redis, and Meilisearch
npm run services:up

4. Database Setup

npx prisma generate
npx prisma migrate deploy

To create an initial admin account for a clean deployment:

npm run create-admin
# Or pass parameters inline:
npm run create-admin admin@example.com "Admin User" "Password123!" "My Organization"

To seed synthetic demo data into a local development database (optional):

npm run db:seed

The demo seed is repeatable and only targets a loopback database from .env.local. It refuses to run in production, against a non-local database, or while a root .env file exists. For demo development, start only the local dependencies with docker compose up -d postgres redis meilisearch; do not start the bundled web and worker containers.

Demo login: admin@demo.mailhub.test / DemoPass123!. The seeded mail accounts are inactive and have no server credentials, so they cannot connect to external mail servers.

5. Run the App

# Development server (with experimental HTTPS for PWA & OAuth)
npm run dev

Open https://localhost:3000.

6. Run a Worker (optional)

Workers sync email accounts in the background:

npm run worker

Worker partitions and sync limits

An email account keeps the workerPartition stored with the account. Its initial-sync job is routed to that partition's queue, so existing accounts assigned to worker-1 remain handled by a worker deployed with WORKER_PARTITION=worker-1. Adding workers does not automatically rebalance existing accounts; keep every partition that owns accounts deployed until you deliberately reassign those accounts.

For a ten-worker deployment, start conservatively with SYNC_WORKER_CONCURRENCY=1 and EMAIL_PERSIST_CONCURRENCY=3. DB_POOL_MAX is per Node.js process, so budget it across every worker and the web process rather than per email account. The defaults in .env.example limit the database pool to five connections per process and use a ten-second pool checkout timeout.

Outbound host allowlist

By default, MailHub rejects IMAP/SMTP hosts that resolve to non-public addresses (SSRF protection). For self-hosted deployments that intentionally connect to a LAN mail server, or through a transparent proxy that returns fake-IP DNS answers, one opt-in setting is available:

# Exact hostname -> reserved CIDR. Repeat the host for multiple address ranges.
OUTBOUND_HOST_ALLOWLIST=mail.example.com=192.168.1.10/32,imap.example.com=198.18.0.0/15

Rules:

  • Exact hostname match only; wildcards and IP literals are not supported.
  • Every resolved address must be inside one of the configured CIDRs.
  • CIDRs must be inside a reserved/non-public range; 0.0.0.0/0 and other public ranges are ignored.
  • Malformed entries are ignored; the host remains blocked.
  • Only set the ranges your deployment actually uses; avoid broad link-local or metadata ranges.
  • This exception applies to IMAP/SMTP host resolution only, not OAuth/HTTP requests.

7. Run Tests

To execute unit and API endpoint tests:

npm test

API Routes

Method Route Description
POST /api/auth/register Register new user + organization
POST /api/auth/login Authenticate and receive JWT
POST /api/auth/logout Clear authentication session
GET /api/auth/me Fetch active user profile
POST /api/auth/password Update user account password
GET /api/accounts List connected email accounts
POST /api/accounts Add an email account (IMAP/SMTP or OAuth)
DELETE /api/accounts/[id] Remove connected email account
POST /api/accounts/[id]/test Test IMAP/SMTP connection settings
POST /api/accounts/[id]/read-all Mark all emails in account as read
POST /api/accounts/[id]/reindex Trigger Meilisearch reindexing for account
GET /api/accounts/[id]/stats Fetch synchronization and message stats
GET /api/accounts/[id]/emails Fetch emails for account folder
POST /api/accounts/[id]/emails/send Send email via SMTP, Gmail, or Microsoft OAuth API
GET/PATCH/DEL /api/accounts/[id]/emails/[emailId] Fetch details, update status/starred, or trash/delete email
POST /api/accounts/[id]/emails/[emailId]/restore Restore email from trash to original folder
GET /api/accounts/[id]/emails/[emailId]/attachments/[attachmentId] Download email attachment
POST /api/accounts/[id]/emails/empty-trash Purge all emails in trash for account
GET/POST /api/accounts/[id]/drafts Manage email drafts
POST /api/accounts/[id]/drafts/sync Sync local email draft to server
GET /api/accounts/oauth/google/init Initiate Google OAuth 2.0 authorization
GET /api/accounts/oauth/google/callback Google OAuth 2.0 callback redirect
GET /api/accounts/oauth/microsoft/init Initiate Microsoft Outlook OAuth 2.0 authorization
GET /api/accounts/oauth/microsoft/callback Microsoft Outlook OAuth 2.0 callback redirect
GET /api/emails/new Aggregated stream of recent emails across all accounts
GET /api/emails/search Full-text search across emails (Meilisearch)
GET /api/emails/thread/[threadId] Fetch email thread by thread ID
POST /api/emails/labels Apply or remove labels from emails
GET/POST /api/labels List or create organization labels
PATCH/DELETE /api/labels/[id] Update or delete organization label
GET/POST /api/labels/[id]/emails Manage emails assigned to label
GET/POST /api/labels/[id]/accounts Manage accounts assigned to label
GET/POST/DEL /api/favourites Manage user favorite emails
POST /api/favourites/reorder Reorder user favorite items
GET /api/org Organization details
GET /api/org/members Organization members list
PATCH/DELETE /api/org/members/[userId] Update member role or remove member
GET/POST /api/org/members/[userId]/accounts Manage member access control for accounts
GET /api/activity Fetch activity audit log
GET /api/dashboard Dashboard summary stats
GET /api/realtime/stream SSE stream for live updates
GET /api/version Service Worker app version check
GET /api/pwa Check PWA system status
POST /api/notifications/subscribe Register Web Push subscription
POST /api/notifications/test Send test Web Push notification

Dashboard Pages

Route Page
/login Sign in page
/register Sign up page
/inbox Account-specific email inbox with search, context menus & thread viewer
/all-emails Aggregated multi-account email feed with reading pane customization (Right, Bottom, Off)
/new-emails Live incoming email feed (redirects to /all-emails)
/overview Analytics dashboard & overview statistics
/labels Label & category management
/settings Account, team access, and organization settings
/activity System audit and activity logs
/testing Integration test sandbox

Progressive Web App (PWA) Features

  • System Installation Check: Utilizes navigator.getInstalledRelatedApps() and display mode media queries (standalone, window-controls-overlay) to detect if MailHub is installed on the user's OS.
  • Smart Install UI: Displays an Install MailHub App button in the sidebar for browser tabs; automatically hides when accessed inside the installed PWA app or system.
  • Icon Generation: Generated app icon suite available via node scripts/generate-pwa-icons.mjs.

Docker

Quick Start with Docker Hub Image

Pull and run the official pre-built MailHub Docker image directly from Docker Hub:

# Pull this release from Docker Hub (`latest` points to the same image)
docker pull kawing11a/mailhub:0.4.0

# Run MailHub web container (using your .env file)
docker run -d \
  --name mailhub-web \
  -p 3000:3000 \
  --env-file .env \
  kawing11a/mailhub:0.4.0

# Run background worker container
docker run -d \
  --name mailhub-worker \
  --env-file .env \
  kawing11a/mailhub:0.4.0 \
  npm run worker

Running with Docker Compose

Build and run the complete stack (MailHub web, workers, PostgreSQL, Redis, Meilisearch):

docker compose up -d --build

The Dockerfile uses a multi-stage build (deps → build → runner) producing a lean production image. Workers run as separate containers using the same image with npm run worker as the entrypoint.

When upgrading an existing deployment, run npx prisma migrate deploy before starting the 0.4.0 web and worker containers.

Project Structure

src/
├── app/
│   ├── (auth)/          # Login & register pages
│   ├── (dashboard)/     # Authenticated dashboard pages
│   │   ├── activity/    # Activity log
│   │   ├── all-emails/  # Aggregated multi-account email feed
│   │   ├── inbox/       # Account email inbox & thread viewer
│   │   ├── labels/      # Label management
│   │   ├── new-emails/  # Redirect to all-emails feed
│   │   ├── overview/    # Dashboard stats
│   │   ├── settings/    # Settings & team account access control
│   │   └── testing/     # Testing sandbox
│   ├── api/             # REST API routes
│   │   ├── accounts/    # Email account CRUD, OAuth, testing, stats, drafts, and member access
│   │   ├── activity/    # Activity audit log
│   │   ├── auth/        # Auth endpoints (login, logout, me, password, register)
│   │   ├── dashboard/   # Summary statistics
│   │   ├── emails/      # Email search, threads, new email stream, and labels
│   │   ├── favourites/  # Favorites management & reordering
│   │   ├── labels/      # Organization and account label management
│   │   ├── notifications/# Push subscriptions & test notifications
│   │   ├── org/         # Organization & team member access management
│   │   ├── pwa/         # PWA status check
│   │   ├── realtime/    # Server-Sent Events stream
│   │   └── version/     # PWA / App version check
│   ├── layout.tsx       # Root layout with local Geist font loading
│   └── manifest.ts      # Web App Manifest for PWA
├── components/
│   ├── email/           # Email list, thread viewer, compose modal, context menu
│   ├── labels/          # Label assignment picker & list components
│   ├── providers/       # OAuth provider integration components
│   ├── pwa/             # PWA Install button & instruction modal
│   ├── search/          # Meilisearch query bar
│   ├── settings/        # Settings, account access modal, accounts list, edit account modal
│   └── sidebar/         # Dynamic navigation sidebar with PWA install integration
├── hooks/               # Custom React hooks (usePWAInstall, PWA updates, SSE, queries)
├── lib/
│   ├── accounts/        # Account management logic & OAuth tokens
│   ├── auth/            # JWT + session utilities
│   ├── db/              # Prisma client
│   ├── gmail/           # Gmail OAuth & API integration
│   ├── imap/            # IMAP connection manager & sync logic
│   ├── queue/           # BullMQ job definitions
│   ├── search/          # Meilisearch client
│   ├── smtp/            # Multi-provider email sender client (SMTP, Gmail API, Microsoft API)
│   ├── crypto.ts        # AES credential encryption
│   ├── redis.ts         # Redis client singleton
│   └── validation/      # Zod validation schemas
├── stores/              # Zustand state stores (UI, sync, accounts)
└── worker.ts            # BullMQ worker entry point
scripts/                 # Database seed & PWA icon generation scripts
prisma/
├── schema.prisma        # Database schema
└── migrations/          # Migration history

Sponsoring & Financial Support

If MailHub helps you or your organization manage email workflows effectively, please consider supporting ongoing development and maintenance!

Sponsor MailHub Buy Me a Coffee

Contributing

Contributions are always welcome! Whether you are reporting bugs, improving documentation, or submitting pull requests, please read our Contributing Guide and review our Code of Conduct before getting started.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Security Policy

For security disclosures, supported versions, and vulnerability reporting procedures, please read our Security Policy.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Model endpoint operators: see model outbound origin policy for approval configuration, local-service compatibility, credential isolation and rollout checks.

About

Self-hosted, multi-tenant email management platform unifying IMAP/SMTP, Gmail OAuth, and Microsoft Outlook OAuth into a modern Next.js 16 dashboard with BullMQ background sync, Meilisearch full-text search, PWA support, and Web Push notifications.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages