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

# Email

> Receive emails as bucket objects with a dedicated inbound address for document intake

## Overview

The Email connector lets you ingest documents by forwarding emails to a dedicated address. Each email becomes a bucket object with the body as a text blob, each attachment as a typed blob, and the original `.eml` preserved for chain of custody.

This is built for compliance-oriented workflows — legal document intake, healthcare record forwarding, secure support inboxes — where email is the transport and the documents (attachments) are the payload.

## Prerequisites

* A Mixpeek account with an active namespace
* A bucket and sync configured for the email connection

## How It Works

1. **Create an email connection** — Mixpeek assigns a unique inbound address (e.g., `conn_abc123@inbound.mixpeek.com`)
2. **Cloudflare receives the email** — MX records point to Cloudflare Email Routing, which routes to a Worker
3. **Worker POSTs raw .eml** — The Cloudflare Email Worker reads the raw RFC 2822 bytes and POSTs them to the Mixpeek webhook
4. **Mixpeek parses and stores** — MIME parsing extracts headers → metadata, body → text blob, attachments → S3-backed blobs, raw .eml → S3

```
Customer Email Client
        │
        ▼
  Cloudflare MX (inbound.mixpeek.com)
        │
        ▼
  Cloudflare Email Routing (catch-all)
        │
        ▼
  mixpeek-email-ingest Worker
        │  POST raw .eml bytes
        ▼
  api.mixpeek.com/v1/webhooks/email/{connection_id}
        │  MIME parse → S3 upload → object + blobs
        ▼
  Bucket Objects
        │  blobs in object storage, metadata in Mongo
        ▼
  mvs_bucket_<bucket_id>
     one document per object, searchable and alertable
```

The last step happens the first time anything names the bucket as a collection.
See [Bucket-backed collections](https://docs.mixpeek.com/docs/vector-store/system-collections.md#bucket-backed-collections).

## Configuration

### Connection-level fields

| Field | Required | Default | Description |
| - | - | - | - |
| `allowed_senders` | No | `[]` (all) | Sender allowlist. Exact addresses or domain wildcards (`*@company.com`). Empty = accept all. |
| `store_raw_eml` | No | `true` | Store the original `.eml` file as an additional blob for chain of custody. |

### Auto-provisioned fields (read-only)

| Field | Description |
| - | - |
| `inbound_address` | System-assigned email address for this connection (e.g., `conn_abc123@inbound.mixpeek.com`) |
| `webhook_secret` | Auto-generated HMAC-SHA256 signing secret for webhook verification |

## Setup

**1. Create an email connection**

```python Python theme={null}
from mixpeek import Mixpeek

mp = Mixpeek("your_api_key")

connection = mp.connections.create(
    name="Legal Intake Inbox",
    provider_type="email",
    provider_config={
        "credentials": {"type": "webhook_secret"},
        "allowed_senders": ["*@lawfirm.com", "paralegal@partner.com"],
        "store_raw_eml": True,
    },
)

print(f"Inbound address: {connection.provider_config['inbound_address']}")
print(f"Webhook URL: https://api.mixpeek.com/v1/webhooks/email/{connection.connection_id}")
```

```javascript JavaScript theme={null}
const { Mixpeek } = require("mixpeek");
const mp = new Mixpeek("your_api_key");

const connection = await mp.connections.create({
  name: "Legal Intake Inbox",
  provider_type: "email",
  provider_config: {
    credentials: { type: "webhook_secret" },
    allowed_senders: ["*@lawfirm.com", "paralegal@partner.com"],
    store_raw_eml: true,
  },
});

console.log(`Inbound address: ${connection.provider_config.inbound_address}`);
console.log(`Webhook URL: https://api.mixpeek.com/v1/webhooks/email/${connection.connection_id}`);
```

```bash cURL theme={null}
curl -X POST https://api.mixpeek.com/v1/organizations/connections \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Legal Intake Inbox",
    "provider_type": "email",
    "provider_config": {
      "credentials": {"type": "webhook_secret"},
      "allowed_senders": ["*@lawfirm.com", "paralegal@partner.com"],
      "store_raw_eml": true
    }
  }'
```

**2. Create a bucket sync**

Link the email connection to a bucket so incoming emails become objects:

```python Python theme={null}
sync = mp.buckets.syncs.create(
    bucket_id="your_bucket_id",
    connection_id=connection.connection_id,
    source_path="inbox",
)
```

```bash cURL theme={null}
curl -X POST https://api.mixpeek.com/v1/buckets/your_bucket_id/syncs \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "connection_id": "conn_abc123",
    "source_path": "inbox"
  }'
```

**3. Send a test email**

Send an email with an attachment to the inbound address and verify the object appears in your bucket.

## Object Structure

Each email becomes **one bucket object** with multiple blobs:

| Blob Property | Type | Content |
| - | - | - |
| `email_body` | `text` | Email body (plain text preferred, HTML fallback) |
| `attachment_0`, `attachment_1`, ... | varies | Each attachment, typed by MIME (image, pdf, video, etc.) |
| `raw_eml` | `text` | Original `.eml` file stored in S3 (if `store_raw_eml` is enabled) |

### Email metadata fields

These are set as **root-level fields** on the object and can be mapped to your bucket schema:

| Field | Type | Description |
| - | - | - |
| `email_from` | string | Sender address |
| `email_to` | list\[string] | Recipient addresses |
| `email_cc` | list\[string] | CC addresses |
| `email_subject` | string | Subject line |
| `email_date` | string (ISO 8601) | Date the email was sent |
| `email_message_id` | string | RFC 2822 Message-ID (used for deduplication) |
| `email_in_reply_to` | string | Parent message ID (for threading) |
| `email_references` | list\[string] | Thread reference IDs |
| `email_attachment_count` | integer | Number of attachments |

## Schema Mapping

Map email fields to your collection schema to make them searchable:

```json theme={null}
{
  "schema": {
    "fields": [
      {"name": "email_from", "type": "text"},
      {"name": "email_subject", "type": "text"},
      {"name": "email_date", "type": "text"},
      {"name": "email_attachment_count", "type": "text"}
    ]
  }
}
```

Use `attribute_filter` in your retriever to query by sender, date, or subject:

```json theme={null}
{
  "stage_name": "attribute_filter",
  "stage_type": "filter",
  "config": {
    "stage_id": "attribute_filter",
    "parameters": {
      "conditions": {
        "AND": [
          {"field": "email_from", "operator": "contains", "value": "@lawfirm.com"},
          {"field": "email_date", "operator": "gte", "value": "2026-01-01"}
        ]
      }
    }
  }
}
```

## Security

| Feature | Description |
| - | - |
| **Sender allowlist** | Only accept emails from specified addresses or domains |
| **Webhook signature** | HMAC-SHA256 verification of inbound payloads |
| **Deduplication** | Duplicate emails (same Message-ID) are skipped |
| **Chain of custody** | Raw `.eml` uploaded to S3 with SHA-256 hash for forensic integrity |
| **Credential encryption** | Webhook secret encrypted at rest (Fernet / CSFLE) |
| **Audit logging** | All connection events written to the audit log (400-day retention) |

> [!WARNING]
>
> Email headers and bodies may contain PII (names, email addresses, phone numbers). Consider enabling PII redaction in your collection pipeline or restricting access to the namespace containing email data.

## Compliance Notes

| Requirement | How Mixpeek addresses it |
| - | - |
| **HIPAA — encryption in transit** | Cloudflare enforces TLS on MX; webhook endpoint requires HTTPS (TLS 1.2+) |
| **HIPAA — encryption at rest** | Credentials encrypted via CSFLE; all blobs (body, attachments, raw .eml) stored in encrypted S3 |
| **HIPAA — audit trail** | All access written to the audit log |
| **eDiscovery — immutability** | Raw `.eml` in S3 with SHA-256 hash, stored alongside parsed content |
| **eDiscovery — chain of custody** | Source tracking: `source_provider=email`, `source_object_id=email://{message_id}` |
| **SOC 2 — access control** | Per-namespace RBAC (ADMIN, MEMBER, VIEWER) with granular operations |

> [!NOTE]
>
> Mixpeek does not currently hold a HIPAA BAA. If you need a BAA for PHI handling, contact us at [sales@mixpeek.com](mailto:sales@mixpeek.com) to discuss your requirements.

## Troubleshooting

| Issue | Solution |
| - | - |
| **403 — sender not in allowlist** | Add the sender's address or domain to `allowed_senders` |
| **404 — connection not found** | Verify the `connection_id` in the webhook URL matches an active email connection |
| **400 — no active bucket sync** | Create a bucket sync linked to this email connection |
| **Duplicate emails skipped** | Expected behavior — emails with the same Message-ID are deduplicated |
| **Attachments not appearing** | Check that the email service is sending the full raw RFC 2822 message, not a stripped-down version |

## Related

* [Buckets](https://docs.mixpeek.com/docs/ingestion/buckets.md) — Bucket schemas and objects
* [Create Sync Configuration](https://docs.mixpeek.com/docs/api-reference/bucket-syncs/create-sync-configuration.md) — Link connections to buckets
* [Attribute Filter](https://docs.mixpeek.com/docs/retrieval/stages/attribute-filter.md) — Filter by email metadata


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