Metadata-Version: 2.4
Name: mixmail
Version: 1.1.3
Summary: Installable MixMail CLI for Gmail backed by a local OpenAI-compatible LLM
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: google-auth>=2.23.0
Requires-Dist: google-auth-oauthlib>=1.1.0
Requires-Dist: google-auth-httplib2>=0.1.1
Requires-Dist: google-api-python-client>=2.100.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: rich>=13.7.0

# 📧 MixMail

MixMail is an autonomous AI agent that connects to your Gmail inbox and lets you query emails using natural language. Powered by a local **OpenAI-compatible LLM server** and the **Gmail API**.

## Architecture

```
User ──▶ mixmail CLI ──▶ Agent ──▶ LLM (Local OpenAI-compatible server) ──▶ Tool Call ──▶ Gmail API
                                ▲                                │
                                └──── LLM Summary ◀── Results ◀──┘
```

## Project Structure

```
MixMail/
├── pyproject.toml              # Package metadata + CLI command
├── main.py                     # Backward-compatible launcher
├── requirements.txt            # Python dependencies
├── .env                        # API keys (create from .env.example)
├── .env.example                # Template
├── client_secret_*.json        # Google OAuth client secret
├── token.json                  # Auto-generated after first auth
├── README.md
└── email_assistant/
    ├── __init__.py
   ├── __main__.py             # Allows: python -m email_assistant
   ├── cli.py                  # CLI implementation
    ├── config.py               # Settings & env var loading
    ├── gmail_client.py         # Gmail API client (OAuth, search, read)
    ├── tools.py                # Agent tool definitions & schemas
    ├── summarizer.py           # LLM-powered email summarisation
    └── agent.py                # ReAct tool-calling agent loop
```

## Setup

### 1. Create Google OAuth credentials (Desktop App)

1. Open [Google Cloud Console](https://console.cloud.google.com/).
2. Create or select a project.
3. Enable **Gmail API**:
   - Go to **APIs & Services → Library**.
   - Search for **Gmail API** and click **Enable**.
4. Configure **OAuth consent screen**:
   - Choose **External** (or Internal for Workspace).
   - Fill required fields and save.
   - In testing mode, add your Gmail address under **Test users**.
5. Create OAuth client credentials:
   - Go to **APIs & Services → Credentials**.
   - Click **Create Credentials → OAuth client ID**.
   - Application type: **Desktop app**.
   - Download the JSON file.

Important notes:
- Use the Google account that owns the mailbox you want MixMail to access.
- On first MixMail run, sign in with that same account in the browser consent flow.
- MixMail uses Gmail read scope by default. If you later enable send scope in Google Cloud and want sending, delete `token.json` and authenticate again.

### 2. Start your local LLM server

MixMail expects an **OpenAI-compatible Chat Completions endpoint**.

Example with a local server:

```bash
curl http://localhost:1200/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen2.5-coder-1.5b-instruct",
    "messages": [
      { "role": "system", "content": "Always answer in rhymes." },
      { "role": "user", "content": "What day is it today?" }
    ],
    "temperature": 0.7,
    "max_tokens": -1,
    "stream": false
}'
```

If that curl works, the MixMail base URL is usually `http://localhost:1200/v1`.

### 3. Install MixMail

From this repository:

```bash
pip install .
```

or from wheel:

```bash
pip install dist/mixmail-1.1.1-py3-none-any.whl
```

### 4. Configure MixMail inside the CLI (recommended)

Run:

```bash
mixmail
```

Then use the built-in setup commands:

```text
/llm_url
/mail_creds
/setup
```

- `/llm_url` saves your local LLM base URL (for example `http://localhost:1200/v1`).
- `/mail_creds` accepts pasted OAuth JSON or a file path import.
- `/setup` shows where MixMail is storing config files.

### 5. First Gmail authorization

After credentials are set, ask any query (for example `show unread emails`).
MixMail opens your browser for Google sign-in/consent and then stores the token automatically.

Default installed-cli locations:
- Config home: `$HOME/.mixmail`
- OAuth client secret: `$HOME/.mixmail/client_secret.json`
- OAuth token: `$HOME/.mixmail/token.json`

## Usage Examples

```
You ❯ find emails from recruiters last week

Agent:
Found 3 emails.

1. Amazon Recruiting
   Subject: ML Engineer role — Seattle
   Summary: Recruiter reaching out regarding an open ML position.

2. Deloitte Talent
   Subject: Interview scheduling
   Summary: Asking for availability for a technical interview.

3. Startup Founder
   Subject: AI Engineer opportunity
   Summary: Early-stage startup looking for founding engineer.
```

```
You ❯ show unread emails with attachments
You ❯ summarize the thread about visa sponsorship
You ❯ list job interview emails from this month
You ❯ send an email to alex@example.com with subject "Interview follow-up" saying thanks for the call and that I'm available Friday afternoon
```

### Commands

| Command | Action |
|---------|--------|
| `help`  | Show usage tips |
| `reset` | Clear conversation history |
| `/llm_url` | Set local LLM server URL (OpenAI-compatible) |
| `/mail_creds` | Paste or import Google OAuth credentials |
| `/setup` | Show the active MixMail config locations |
| `quit`  | Exit the assistant |

For first-time setup in the installed CLI, you can now configure everything inside the app:

```text
mixmail
/llm_url
/mail_creds
```

`/mail_creds` accepts either:

- A pasted Google OAuth desktop-app JSON document.
- A file path like `C:/Users/Alice/Downloads/client_secret.json`.
- A file import command like `file:C:/Users/Alice/Downloads/client_secret.json`.

## Features

- **Natural language search** — translates plain English into Gmail search syntax
- **Email retrieval** — fetches sender, subject, date, snippet, attachments
- **Full message reading** — retrieves complete email bodies on demand
- **Email sending** — sends plain-text Gmail messages from the authenticated account
- **Thread summarisation** — summarizes entire email conversations
- **Attachment detection** — lists filenames of attached documents
- **Email categorisation** — classifies emails (recruiters, finance, personal, promotions)
- **Pagination** — handles large result sets gracefully
- **Auto token refresh** — OAuth tokens are refreshed automatically

## Troubleshooting

| Issue | Fix |
|-------|-----|
| Local LLM server is unreachable | Start the server on `http://localhost:1200` or update `LLM_BASE_URL` |
| `credentials file not found` | Ensure your OAuth JSON is in the project root |
| Browser doesn't open for auth | Run from a terminal with browser access |
| `invalid_scope` from Gmail | Delete `token.json` and re-run to force fresh OAuth with current scopes |
| Email sending fails | Your token may be read-only; re-authenticate after enabling Gmail send scope in Google Cloud OAuth consent |
| `403 Forbidden` on Gmail API | Enable Gmail API in Cloud Console; add yourself as a test user |
| Token expired | Delete `token.json` and re-run |

## Packaging For Clients

If you want a client to install and run this like a standard CLI:

```bash
pip install git+https://github.com/your-org/MixMail.git
mixmail
```

Each client machine still needs its own runtime config:

- A reachable local or hosted OpenAI-compatible LLM endpoint in `$HOME/.mixmail/.env`.
- A Google OAuth client secret JSON file.
- First-run browser login to grant Gmail access.

Important: if the CLI runs on the client machine, the API key and Gmail OAuth flow also happen on that client machine. If you do not want to expose your API key or distribute Google credentials, the correct architecture is a hosted backend rather than a local CLI.

For local handoff, you can also build a wheel and share that instead of the source tree:

```bash
python -m pip install build
python -m build
pip install dist/mixmail-1.1.1-py3-none-any.whl
mixmail
```
