> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mirage.strukto.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Email

> Mount an IMAP mailbox as a Mirage filesystem and send messages through SMTP from Python workspaces.

The Email VFS exposes any IMAP mailbox as a virtual filesystem
mounted at some prefix such as `/email/`. Sending is handled via SMTP.

## Config

```python theme={null}
import os

from mirage import MountMode, Workspace
from mirage.vfs.email import EmailConfig, EmailVFS

config = EmailConfig(
    imap_host=os.environ["IMAP_HOST"],
    smtp_host=os.environ["SMTP_HOST"],
    username=os.environ["EMAIL_USERNAME"],
    password=os.environ["EMAIL_PASSWORD"],
)
vfs = EmailVFS(config=config)
ws = Workspace({"/email": vfs}, mode=MountMode.READ)
```

### Config Reference

| Field | Type | Default | Description |
| - | - | - | - |
| `imap_host` | `str` | | IMAP server hostname |
| `imap_port` | `int` | `993` | IMAP port |
| `smtp_host` | `str` | | SMTP server hostname |
| `smtp_port` | `int` | `587` | SMTP port |
| `username` | `str` | | Email address / login |
| `password` | `str` | | Password or app password |
| `use_ssl` | `bool` | `True` | Use SSL for IMAP |

### Common VFS Settings

| VFS | IMAP Host | SMTP Host | Notes |
| - | - | - | - |
| Outlook/365 | `outlook.office365.com` | `smtp.office365.com` | App password or OAuth2 |
| Yahoo | `imap.mail.yahoo.com` | `smtp.mail.yahoo.com` | App password required |
| Fastmail | `imap.fastmail.com` | `smtp.fastmail.com` | App password |
| iCloud | `imap.mail.me.com` | `smtp.mail.me.com` | App password |
| ProtonMail | `127.0.0.1` (Bridge) | `127.0.0.1` (Bridge) | Requires ProtonMail Bridge |
| Self-hosted | Your server hostname | Your server hostname | Whatever you configured |

## Filesystem Layout

```text theme={null}
/email/
  <folder>/
    <yyyy-mm-dd>/
      <sanitized-subject>__<uid>.email.json
      <sanitized-subject>__<uid>/   # only if message has attachments
        <attachment-filename>
```

Example:

```text theme={null}
/email/
  INBOX/
    2026-04-14/
      Meeting_Notes__12345.email.json
      Meeting_Notes__12345/
        report.pdf
        screenshot.png
      Simple_Email__12346.email.json
    2026-04-13/
      Hello__12347.email.json
  Sent/
    2026-04-14/
      Reply__12348.email.json
  Drafts/
  Archive/
```

Folder directories appear at the root, using IMAP folder names
(e.g., `INBOX`, `Sent`, `Drafts`).

### Date Directories

Inside each folder, messages are grouped into date subdirectories
formatted as `YYYY-MM-DD`. The date is derived from the message's
`Date` header.

### Message Files

Each message is stored as a `.email.json` file. The filename shape is:

```text theme={null}
<sanitized-subject>__<uid>.email.json
```

### Attachments

Messages that have attachments get a companion subdirectory with
the same base name (without `.email.json`):

```text theme={null}
Meeting_Notes__12345.email.json    # message JSON
Meeting_Notes__12345/              # attachment directory
  report.pdf
  screenshot.png
```

## Cache

The Email VFS uses `IndexCacheStore` (same as Gmail, Slack,
Discord, and other mounts). Index entries store folder names,
message UIDs, and message metadata.

## Example

```python theme={null}
import asyncio
import os

from dotenv import load_dotenv

from mirage import MountMode, Workspace
from mirage.vfs.email import EmailConfig, EmailVFS

load_dotenv(".env.development")

config = EmailConfig(
    imap_host=os.environ["IMAP_HOST"],
    smtp_host=os.environ["SMTP_HOST"],
    username=os.environ["EMAIL_USERNAME"],
    password=os.environ["EMAIL_PASSWORD"],
)
vfs = EmailVFS(config=config)


async def main():
    ws = Workspace({"/email": vfs}, mode=MountMode.READ)

    # List folders
    r = await ws.shell("ls /email/")
    print(await r.stdout_str())

    # List date directories in INBOX
    r = await ws.shell("ls /email/INBOX/")
    print(await r.stdout_str())

    # List messages for a specific date
    r = await ws.shell("ls /email/INBOX/2026-04-14/")
    print(await r.stdout_str())

    # Read a message
    r = await ws.shell(
        "cat /email/INBOX/2026-04-14/Meeting_Notes__12345.email.json")
    print(await r.stdout_str())

    # Extract subject with jq
    r = await ws.shell(
        'jq ".subject"'
        " /email/INBOX/2026-04-14/Meeting_Notes__12345.email.json")
    print(await r.stdout_str())

    # List attachments
    r = await ws.shell("ls /email/INBOX/2026-04-14/Meeting_Notes__12345/")
    print(await r.stdout_str())

    # Search across all messages
    r = await ws.shell('rg "quarterly" /email/INBOX/')
    print(await r.stdout_str())

    # Tree view
    r = await ws.shell("tree -L 2 /email/INBOX/")
    print(await r.stdout_str())

    # Triage unread messages
    r = await ws.shell("himalaya envelope list --folder INBOX --unseen --max 5")
    print(await r.stdout_str())

    # Send an email
    r = await ws.shell(
        'himalaya message send --to "user@example.com"'
        ' --subject "Hello from MIRAGE"'
        ' --body "This email was sent via the MIRAGE email VFS."')
    print(await r.stdout_str())


if __name__ == "__main__":
    asyncio.run(main())
```

## Finding UIDs

VFS-specific commands require message UIDs. These can be
extracted from the filesystem:

```bash theme={null}
# UID is embedded in filename after "__"
ls /email/INBOX/2026-04-14/
# -> Meeting_Notes__12345.email.json   <- uid = 12345

# Read a message then reply
himalaya message read --uid 12345 --folder INBOX
himalaya message reply --uid 12345 --folder INBOX --body "Thanks for the notes"
```

## Shell Commands

Standard commands available on the mounted email tree:

| Command | Notes |
| - | - |
| `ls` | List folders, dates, messages, attachments |
| `cat` | Read message JSON or attachment content |
| `head` / `tail` | First/last N lines |
| `grep` / `rg` | Pattern search (file or directory level) |
| `jq` | Query message JSON fields |
| `wc` | Line/word/byte counts |
| `stat` | File metadata (name, size, type) |
| `find` | Recursive search with `-name`, `-maxdepth` |
| `tree` | Directory tree view |
| `basename` | Extract filename from path |
| `dirname` | Extract directory from path |
| `realpath` | Resolve path to absolute form |
| `nl` | Number lines of output |

Acting on mail (list, read, send, reply, forward) goes through the
[himalaya CLI](/python/cli/himalaya) when installed.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.