Skip to main content
You already run an IMAP mailbox (Proton, Fastmail, Gmail with app password, etc.) and want its attachments to land in suchi. Two transports work today:
  1. This recipe — mail-intake. A small Go daemon that polls IMAP, extracts attachments matching a MIME allowlist, and drops them into a consume directory with a per-attachment JSON sidecar. suchi’s fs-watch picks up both. Clean cred separation: the mail service never sees suchi; suchi never sees the mailbox.
  2. Direct IMAP polling via INGEST_IMAP_URL — no external tools; see config.
Pick one. This page covers option 1.

Prerequisites

  • Proton Mail Bridge (or any IMAP endpoint) reachable from the mail-intake container.
  • A shared volume both mail-intake and suchi can write / read. Recommended: a bind mount off /mnt/homelab/mail-intake/consume.

docker-compose

docker-compose.yml

mail-intake config.yaml

Sidecar compatibility

mail-intake emits flat-shape JSON:
suchi’s sidecar spec normally requires "suchi_sidecar": 1, but core/ingest/sidecar transparently accepts the flat-shape JSON — no producer patch needed. "Name <address>" correspondent strings are peeled to just the display name; created accepts RFC-3339 or YYYY-MM-DD. If you’re writing your own producer, you can EITHER emit the flat-shape JSON (portable) OR the versioned suchi-native form (access to jd_category, custom_fields, multi-role correspondents, etc. — see sidecar spec).

What you’ll see

For each attachment mail-intake extracts, suchi’s fs-watch:
  1. Sees the file drop into /ingest/.
  2. Reads the sidecar (filename.json).
  3. Creates a document row owned by INGEST_FS_OWNER_EMAIL.
  4. Enqueues post-ingest — qpdf → OCR → ZUGFeRD → rules → render.
  5. Applies sidecar-derived title, created, correspondent (as sender), tags.
What this path DOESN’T give you: the raw .eml as its own suchi doc. If you want the email body indexed alongside the attachments (so a full-text search hits “hi, please see attached” in the body), either:
  • Configure mail-intake to also drop the raw message alongside its attachments (upstream feature request, or write a small wrapper), OR
  • Use suchi’s direct IMAP polling (INGEST_IMAP_URL). That path ingests the .eml first, then fans out its attachments as child docs via email_parent_id.

Testing locally

The fastest way to kick the tires without touching your real mailbox:
Each attachment lands within a few seconds of appearing in /consume/.