Mail Console is a local-first mailbox workspace for managing large Outlook / Hotmail account libraries, receiving verification codes or recent messages, refreshing OAuth tokens, and exposing the same operations through an API key protected developer interface.
It is intentionally simple to deploy: a standard-library Python backend, native HTML/CSS/JavaScript, and plain text/JSON data files. No database, Node build step, or frontend framework is required.
If Mail Console saves you time or helps your workflow, please consider giving the project a star. It helps more people discover the project and keeps development moving.
| Dashboard | Account Library |
|---|---|
![]() |
![]() |
![]() |
![]() |
Privacy-safe screenshot mode:
http://127.0.0.1:8899/?privacy=1
http://127.0.0.1:8899/?privacy=1&lang=en
privacy=1 masks mailbox addresses, group names, and account counts in the UI. It is intended for screenshots, demos, and documentation. It does not modify data/accounts.txt, categories, tokens, or any local account assets.
- Dashboard-first UI designed for hundreds or thousands of mailbox accounts.
- Nested folder-like categories with drag-and-drop account and group movement.
- Dense but readable account rows, expandable history, and per-account receive state.
- Receive verification codes or recent messages from a single account or selected accounts.
- Outlook REST first, IMAP fallback, with Inbox/Junk/Archive/Deleted/Clutter coverage where available.
- Page-local receive history with duplicate suppression by mailbox arrival time and content.
- Import
.txtfiles or pasted account text, deduplicated by real email address. - Export normalized account lines as
email----mailbox_password----client_id----refresh_token. - Manual and scheduled Outlook refresh token maintenance with local backups.
- Config-driven login, password hashing, session cookies, local themes, and resource overview.
- Developer API with an independent enable switch and API key.
- Quick Start
- Screenshots
- AI Agent Deployment
- Configuration
- Account File Format
- Import And Export
- Receiving Codes And Messages
- Developer API
- Token Refresh
- Deployment
- Security Notes
- Troubleshooting
- Project Layout
Requirements:
- Python 3.10+
- Windows PowerShell for the bundled control script, or any shell that can run
python app.py
Windows double-click start:
start_mail_console.vbs
Windows double-click stop:
stop_mail_console.vbs
Command line start:
python app.pyOpen the console:
http://127.0.0.1:8899
Default local login when no config.json exists:
admin / admin
For any shared machine, server, or public network, create config.json and change the password before exposing the service.
Paste this into an AI coding agent and let it deploy from the README:
Please read this README and deploy Mail Console safely on this machine:
https://raw.githubusercontent.com/Enffun-EL/Mail-Console/main/README.md
Real mailbox accounts, passwords, OAuth client IDs, refresh tokens, API keys, session secrets, and generated config files are private assets. Keep them in ignored local files, not in issues, pull requests, logs, screenshots, or README examples.
config.json is the recommended configuration entry point. Environment variables and command line arguments are best used as deployment overrides.
Create a local config file:
copy config.example.json config.jsonOn macOS/Linux:
cp config.example.json config.jsonConfiguration precedence:
command line arguments > environment variables > config.json > built-in defaults
Example:
{
"server": {
"host": "127.0.0.1",
"port": 8899
},
"auth": {
"enabled": true,
"username": "admin",
"password": "change-this-password",
"passwordHash": "",
"secret": "replace-with-a-long-random-string",
"cookieSecure": false,
"sessionSeconds": 86400
},
"paths": {
"accounts": "data/accounts.txt",
"categories": "data/categories.json",
"archive": "data/token-refresh-archive",
"tokenSchedule": "data/token-refresh-schedule.json"
},
"fetch": {
"waitSeconds": 120,
"intervalSeconds": 5,
"maxConcurrent": 8
},
"api": {
"enabled": false,
"key": ""
}
}Important options:
| Section | Option | Description |
|---|---|---|
server |
host, port |
HTTP bind address and port. Changing these requires restart. |
auth |
enabled |
Enable or disable browser login. Disable only on trusted local networks. |
auth |
username, password |
Basic local login credentials. |
auth |
passwordHash |
Takes priority over password when set. Generate with python scripts/make_password_hash.py. |
auth |
secret |
Session signing secret. Use a long random value in production. |
auth |
cookieSecure |
Set to true when the app is served through HTTPS. |
fetch |
waitSeconds, intervalSeconds, maxConcurrent |
Default receive timeout, polling interval, and concurrency. |
api |
enabled, key |
Developer API switch and key. Prefer managing these from the UI. |
Supported environment overrides include PANEL_HOST, PANEL_PORT, PANEL_USER, PANEL_PASSWORD, PANEL_PASSWORD_HASH, PANEL_AUTH_ENABLED, MAIL_CONSOLE_API_ENABLED, and MAIL_CONSOLE_API_KEY. See .env.example for more.
Default account file:
data/accounts.txt
Supported account lines:
email----mailbox_password
email----mailbox_password----outlook_client_id----outlook_refresh_token
openai_email----openai_password----mailbox_password----outlook_client_id----outlook_refresh_token
Category headers are supported:
[Project A]
demo@example.com----password----client_id----refresh_token
Project B----demo2@example.com----password----client_id----refresh_token
Nested categories use /:
Registered/CPA/PLUS
- Import from the UI with a
.txtfile or pasted account text. - Append import keeps existing accounts and skips duplicate email addresses.
- Replace import backs up the current account file and writes a deduplicated file.
- Export always writes
email----mailbox_password----client_id----refresh_token.
Mail Console has two receive modes:
code: extracts six-digit verification codes from relevant messages.message: returns the latest visible email subject, sender, arrival time, and preview/body.
Receive behavior:
- Outlook REST is used first when OAuth credentials are present.
- IMAP is used as fallback when REST times out or is unavailable.
- The UI keeps receive history only in the current browser page session.
- Each account keeps up to 30 receive records in memory.
- Duplicate results are suppressed by mode, mailbox arrival time, and received content.
- If content is the same but mailbox arrival time differs, it is treated as a new email.
If a sender reports that a message was sent but Mail Console does not show it, verify that the mailbox provider actually exposes it through Outlook REST/IMAP. In practice, mail can be delayed, blocked, greylisted, or routed differently per recipient.
Open the user menu in the top-right corner and choose API.
API controls:
- Use the slider to enable or disable API access.
- Generate a key to create and save a new API key. The previous key becomes invalid immediately.
- Use the eye icon to reveal the key temporarily.
- Use
Copy Keyto copy it. - The API documentation panel uses the current browser origin, so local, cloud, IP, domain, and HTTPS deployments show the correct base URL automatically.
Authentication headers:
Authorization: Bearer YOUR_API_KEYor:
X-API-Key: YOUR_API_KEYFetch one mailbox:
curl -X POST "http://127.0.0.1:8899/api/v1/fetch" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"email\":\"demo@outlook.com\",\"mode\":\"message\",\"wait\":120,\"recentMinutes\":60}"Fetch verification code instead:
{
"email": "demo@outlook.com",
"mode": "code",
"wait": 120,
"recentMinutes": 10
}Batch fetch:
curl -X POST "http://127.0.0.1:8899/api/v1/fetch_batch" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"emails\":[\"a@outlook.com\",\"b@outlook.com\"],\"mode\":\"message\",\"parallel\":4}"Common API endpoints:
| Method | Path | Purpose |
|---|---|---|
GET |
/api/accounts |
List accounts, categories, counts, and max concurrency. |
POST |
/api/v1/fetch |
Fetch one mailbox using API-key auth. |
POST |
/api/v1/fetch_batch |
Fetch multiple mailboxes using API-key auth. |
POST |
/api/category |
Move accounts to a category. |
POST |
/api/create_category |
Create a category. |
POST |
/api/rename_category |
Rename or move a category path. |
POST |
/api/delete_category |
Delete a category and move its accounts back to uncategorized. |
GET |
/api/export |
Export normalized account lines. |
GET / POST |
/api/token_schedule |
Read or save token refresh schedule. |
POST |
/api/refresh_tokens |
Refresh selected or all OAuth tokens. |
GET |
/api/workspace_stats |
Read process memory, local data size, and disk free space. |
Treat the API key like a password. When API is enabled, the key can call protected operations in this app.
- Refresh selected OAuth accounts manually.
- Refresh all OAuth accounts manually.
- Schedule refreshes by interval: every
Nminutes, hours, or days. - Day-based schedules can use a clock time, such as every 30 days at 03:00.
- Schedule state is stored in
data/token-refresh-schedule.jsonby default. - Backups and reports are written under
data/token-refresh-archive.
Local-only default:
{
"server": {
"host": "127.0.0.1",
"port": 8899
}
}LAN or server deployment:
{
"server": {
"host": "0.0.0.0",
"port": 8899
},
"auth": {
"enabled": true,
"username": "admin",
"password": "replace-this"
}
}Recommendations for servers:
- Change the default password before binding to a public interface.
- Prefer
auth.passwordHashinstead of a plain password in shared environments. - Put the app behind HTTPS before setting
auth.cookieSecure=true. - Use a firewall or reverse proxy access rules for public deployments.
- Store
config.jsonanddata/outside public web roots.
PowerShell controller:
powershell -ExecutionPolicy Bypass -File "console_control.ps1" -Action start
powershell -ExecutionPolicy Bypass -File "console_control.ps1" -Action status
powershell -ExecutionPolicy Bypass -File "console_control.ps1" -Action stopThe controller reads config.json and PANEL_PORT to open the correct URL.
Command line overrides:
python app.py --host 127.0.0.1 --port 8899 --config config.json
python app.py --accounts data/accounts.txt --categories data/categories.json
python app.py --api-enabled true --api-key YOUR_API_KEY- Do not commit
config.json,data/accounts.txt, or real token archives. - Do not use
admin / adminoutside local testing. - Refresh tokens are not rendered in normal account rows.
- Receive history is page-local and disappears after refresh/clear.
- The UI
Clear recordsaction clears page logs, received messages, and codes. It does not delete mailbox server messages. - API keys are powerful. Disable API when it is not needed.
Message was sent but not received:
- Check the account in the UI and increase
recentMinutesorwait. - The sender may show multiple recipients, but Outlook may expose the message for only some mailboxes.
- Check Inbox, Junk, Archive, Deleted, and Clutter in the mailbox provider.
- OAuth/REST can see different data from webmail during delivery delays.
- Use the API/UI failure message. It includes the latest visible Outlook message when no recent message is found.
Login does not work:
- Verify
auth.username,auth.password, orauth.passwordHash. - Restart after changing host/port and refresh after changing frontend files.
- If using HTTPS, only set
auth.cookieSecure=truebehind HTTPS.
Token refresh failed:
- Confirm the account line has
client_idandrefresh_token. - Check
data/token-refresh-archivefor backup and report files. - Some Microsoft refresh tokens expire or are revoked and must be replaced.
app.py Thin launcher, keeps `python app.py` working
src/mail_console/__init__.py Package metadata and version marker
src/mail_console/__main__.py Package entrypoint when `src` is on `PYTHONPATH`
src/mail_console/server.py HTTP routes, request handling, fetch jobs, schedules
src/mail_console/accounts.py Account loading, import/export, groups, token writeback
src/mail_console/outlook.py Outlook OAuth and HTTP JSON helpers
src/mail_console/mail_parser.py MIME parsing, text cleanup, verification-code extraction
src/mail_console/mail_messages.py REST message normalization and duplicate-detection keys
src/mail_console/security.py Password hashes, session signing, secrets
src/mail_console/workspace.py Local resource stats and cleanup helpers
src/mail_console/models.py Dataclasses and shared model types
src/mail_console/constants.py App constants, limits, regexes, Outlook endpoints
src/mail_console/paths.py Project, data, static, config, archive paths
src/mail_console/utils.py Small shared parsing and formatting helpers
static/index.html Main console UI
static/login.html Login page
assets/ README screenshots
config.example.json Configuration template
.env.example Optional environment overrides
scripts/make_password_hash.py Password hash helper
console_control.ps1 Start / stop / status controller
start_mail_console.vbs Windows double-click start
stop_mail_console.vbs Windows double-click stop
accounts.example.txt Example account file
data/accounts.txt Local real account file, ignored by Git
data/categories.json Local category state, ignored by Git
data/token-refresh-schedule.json Scheduled token refresh state, ignored by Git
data/token-refresh-archive Refresh-token backups and reports, ignored by Git



