Skip to content

Latest commit

 

History

50 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

inboxone

A self-hosted webmail aggregator: one modern inbox view for all your existing mail accounts (generic IMAP/SMTP providers plus Outlook.com via OAuth2), running entirely in a single Docker container. inboxone does not upload your mail to a hosted third-party service. It stores account configuration, encrypted credentials and tokens, sync state, and message metadata in its local SQLite database; full bodies and attachments are fetched on demand and are not persisted.

Features

  • Aggregate multiple IMAP/SMTP accounts and Outlook.com into one chronological inbox.
  • Color-coded account indicator on every message so you always know which mailbox it came from.
  • Search cached subject, sender, and recipient metadata across the unified inbox, with an unread-only filter.
  • Reply to or forward messages from any configured account, from a single aggregated view.
  • Per-account folder selection — sync just INBOX, or additional folders/labels too.
  • A single app-wide password gate protects the whole UI.
  • Modern three-pane UI (filter rail / message list / reading pane), not an old-school webmail look.

Architecture (brief)

  • Backend: Python (FastAPI), SQLAlchemy async + SQLite, APScheduler for background IMAP polling, IMAPClient for IMAP, aiosmtplib for basic-auth SMTP sending, msal for Microsoft OAuth2 device-code sign-in, Microsoft Graph for sending mail from Outlook accounts.
  • Frontend: React + TypeScript + Vite + TailwindCSS + TanStack Query + Zustand.
  • Data model: account configuration, encrypted credentials and tokens, sync state, and message metadata (subject, sender, recipients, date, flags, folder, size, etc.) are stored in a local SQLite database. Bodies and attachments are never persisted — they're fetched live from the mail server when requested.
  • Runs as a single Docker container: the API and the background sync scheduler share one Python process (no separate worker process needed).

Requirements

  • Docker and Docker Compose.

Security note: inboxone is a single-user application intended for private or local-network use. Do not expose it directly to the public internet. For remote access, use a trusted VPN or a reverse proxy with independent authentication.

Quick start

  1. Copy the example environment file and fill in real values:
    cp .env.example .env
  2. Generate the required secrets:
    python3 -c "import secrets; print(secrets.token_urlsafe(32))"   # SECRET_KEY
    python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"   # ENCRYPTION_KEY
    (If you don't have Python locally, run these one-liners inside the built container instead: docker compose run --rm inboxone python3 -c "...".)
  3. Set APP_PASSWORD in .env to a password of your choosing (this only seeds the initial password - see "Forgot your password?" below for how to reset it later).
  4. Pull and start (uses the published image from ghcr.io):
    docker compose up -d
  5. Open http://localhost:8000, log in with APP_PASSWORD, and add your accounts under Settings.

Adding accounts

Generic IMAP/SMTP (most providers)

Use your provider's IMAP/SMTP host, port, and your normal username/password (or an app-specific password, see below). Settings → Add account → "Generic IMAP/SMTP".

Gmail

Gmail requires an App Password rather than your normal account password once 2-Step Verification is enabled (Google no longer allows plain account passwords for IMAP/SMTP). Create one at myaccount.google.com/apppasswords and use it as the IMAP/SMTP password. Host: imap.gmail.com (port 993), smtp.gmail.com (port 587).

Outlook.com

Outlook.com accounts use OAuth2 via a device-code sign-in flow. Go to Settings → Add account, choose Outlook, enter a name, and select Connect. Enter the displayed code at microsoft.com/devicelogin, then sign in with your Microsoft account. inboxone uses built-in OAuth client configuration, so you do not need to register an Azure application.

Environment variables

Variable Description
APP_PASSWORD Password required to access the web UI.
SECRET_KEY Random secret used to sign the session cookie.
ENCRYPTION_KEY Fernet key used to encrypt stored IMAP/SMTP passwords and OAuth tokens at rest. Do not rotate after accounts exist without a migration - existing encrypted values would become unreadable.
DATABASE_URL SQLite connection string (defaults to the /data bind mount).
SYNC_DEFAULT_INTERVAL_SECONDS Default IMAP polling interval per account (minimum 30s).

Forgot your password?

APP_PASSWORD in .env only sets the initial password the first time the container starts - after that, the password lives in the database and editing .env no longer has any effect. If you forget it, reset it directly from inside the running container:

docker exec -it inboxone python -m app.cli reset-password

This prompts for a new password and updates it immediately, without needing to know the old one - no need to touch .env or restart anything.

Data & privacy model

  • inboxone does not upload your mail to a hosted third-party service. Its database and application data remain on the server where you run the container.
  • The local SQLite database stores the app password hash, account configuration, encrypted credentials and OAuth tokens, sync state, and message metadata (subject, sender/recipients, date, flags, folder, and size).
  • Message bodies and attachments are fetched from the provider when you open or download them and are not persisted to disk by inboxone.
  • IMAP/SMTP passwords and Microsoft OAuth tokens are encrypted at rest with ENCRYPTION_KEY and decrypted in memory when needed for a connection.
  • Deleting a message moves it to the account's Trash or Deleted Items folder on the provider; inboxone does not permanently erase it.

Building from source

The published image (ghcr.io/dermute/inboxone:latest) is what docker-compose.yml uses by default. To build and run from your own checkout instead, uncomment the build: block in docker-compose.yml (and comment out image:), then:

docker compose up -d --build

Development (without Docker)

# backend (from the repository root)
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e "./backend[dev]"
cd backend
alembic upgrade head
uvicorn app.main:app --reload

# frontend (separate terminal)
cd frontend
npm install
npm run dev

The Vite dev server proxies /api requests to http://localhost:8000.

Known limitations / roadmap

  • No IMAP IDLE or push updates yet — the backend polls each account on an interval (default 60s) and the frontend polls the API every 15s. New mail typically appears within a minute.
  • No Gmail OAuth - Gmail accounts are configured as generic IMAP/SMTP using an App Password.
  • Single user, single SQLite database - not designed for multiple concurrent users.
  • Message list "snippet" preview is not populated yet, since generating it would require fetching bodies during sync (which this app intentionally avoids to keep mail off local storage).

AI attribution

This project was developed with AI assistance.

License

MIT — see LICENSE.

About

Self-hosted, single-user mail aggregator (IMAP/SMTP + Outlook OAuth2) in one Docker container. AI-generated, personal use only - see README.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages