OpenMailConnect
Official# OpenMailConnect
[](https://github.com/DINQ-labs/openmailconnect/actions/workflows/tests.yml)
[](LICENSE)
An independent open-source MCP server for your own mailbox.
- **Gmail:** direct Google OAuth, automatic token refresh, send/reply, read/search,
threads and drafts.
- **SMTP:** authenticated TLS (465) or STARTTLS (587), sending only.
- No DINQ account, payment system, hosted analytics or third-party OAuth broker.
- Mailbox credentials are entered in a browser, not passed to the agent.
## Install
Python 3.11+ and `uv` are required.
```bash
git clone https://github.com/DINQ-labs/openmailconnect.git
cd openmailconnect
uv sync
cp .env.example .env
uv run openmailconnect
```
The default is MCP stdio, plus a local binding server at `127.0.0.1:8787`.
Configure your MCP client with an absolute checkout path:
```json
{"mcpServers":{"openmailconnect":{"command":"uv","args":["--directory","/absolute/path/openmailconnect","run","openmailconnect"]}}}
```
Client formats differ; adapt this command to the client's configuration.
Do not start multiple instances sharing the same binding port. Use a different
`--port`, data directory and origin for separate owner instances.
## Gmail setup (your Google OAuth application)
Create a Google Cloud OAuth **Web application** client, enable the Gmail API,
and register the exact redirect URI:
```
http://127.0.0.1:8787/oauth/callback
```
Set `GMAIL_CLIENT_ID` and `GMAIL_CLIENT_SECRET` in your local `.env` file. For a
Google OAuth app in testing mode, add your Google account as a test user. Public
Google apps may require verification for Gmail scopes; the project does not
bypass Google's consent or verification requirements.
Ask the agent to call `mail_connect(provider="gmail")`, open the returned link,
authorize your account, then call `mail_accounts`. The Google client secret and
mailbox tokens do not belong in chat. Tokens refresh automatically while the
refresh grant remains valid.
## SMTP setup
Call `mail_connect(provider="smtp")`. Open the returned link and enter your email,
SMTP hostname, port and app-specific password/authorization code. The server
verifies TLS and authentication without sending a test message. Private-network
SMTP addresses and ports other than 465/587 are rejected by default.
SMTP does not provide mailbox reading, search or draft APIs. Use Gmail for those.
## Tools
| Tool | Purpose |
|---|---|
| mail_accounts | List connected mailboxes, without credentials |
| mail_connect | Browser link to connect Gmail or SMTP |
| mail_send | Send or reply, with To/Cc/Bcc, plain text and optional HTML |
| mail_search | Gmail query, paging and message IDs |
| mail_read | Gmail message and MIME parts |
| mail_thread | Gmail conversation |
| mail_create_draft | Create a Gmail draft without sending |
| mail_drafts | List Gmail drafts |
For replies, supply the original Gmail message ID as `reply_to` and explicitly
provide recipients, subject and body. Sending requires the user's authorization.
Use a stable `request_id` for each logical send and reuse it for retries. A request
ID with different content is rejected. States are `submitted`, `partial`, `failed`,
`pending`, and `unknown`. Submitted means the provider accepted the message, not
that it was delivered or opened. Do not re-send an uncertain request under a new
ID; check the mailbox. This prevents automatic duplicate sends but cannot provide
exactly-once delivery across an external mail server and local storage.
## HTTP / Docker
```bash
# Set OPENMAILCONNECT_TOKEN to a long random secret in .env first.
uv run openmailconnect --transport http --host 0.0.0.0
# or
docker compose up --build -d
```
MCP endpoint: `/mcp`; clients send `Authorization: Bearer <token>`.
Set `OPENMAILCONNECT_ORIGIN` to the HTTPS public origin behind your reverse proxy,
and register `<origin>/oauth/callback` in Google Cloud. Browser binding links are
single-use and expire after ten minutes. The service is single-owner: clients of
one instance share its mailboxes. It is not a hosted multi-user account system.
The SQLite database and encrypted mailbox credentials live under
`OPENMAILCONNECT_DATA_DIR` (default `~/.local/share/openmailconnect`). Keep the
`credentials.key` file with backups; losing it makes stored tokens unreadable.
Protect both files with filesystem permissions. Deleting an account's Google
grant in Google security settings revokes access; SMTP app passwords can be
revoked at the provider. No email body is stored in the send receipt database.
## Develop
```bash
uv run pytest -q
uv build
```
Tests use synthetic mail providers and do not send real email. The provider code
is informed by DINQ Connector's direct Gmail/SMTP implementations. The tool design
references https://github.com/zavora-ai/mcp-email; no source was copied from it.
License: Apache-2.0.
## Contributing and support
Maintained by DINQ Labs as a standalone project. See [CONTRIBUTING.md](CONTRIBUTING.md)
for local checks and pull requests, and [SECURITY.md](SECURITY.md) for the security
model. Report reproducible bugs through [GitHub Issues](https://github.com/DINQ-labs/openmailconnect/issues).
This initial release is intended for self-hosted, single-owner use.
TDQS
Scored across 8 tools
Each tool targets a distinct resource/action: connection, accounts, sending, draft creation/listing, search, read, and thread retrieval. There is no meaningful overlap between tools, and the descriptions make the boundaries clear.
All tools share the mail_ prefix and use consistent snake_case. Action tools use verbs like create_draft, send, search, and read, while resource-listing tools use plural nouns like drafts and accounts, creating a predictable pattern.
With 8 tools, the server is well-scoped for an email integration use case. Each tool earns its place and there is no redundancy or excessive granularity.
Core workflows are covered: connect, list accounts, send, read, search, thread, and draft creation/listing. Minor gaps exist around draft lifecycle management, such as updating, deleting, or explicitly sending a draft, but these are not fatal to the primary use case.