Email Import Node
Overview
Section titled “Overview”Email Import gives each canvas node its own inbound email address. You send plaintext or attachments to that address, and Fontana starts the workflow as its owner, no manual click required.
- Real inbound mail - Fontana receives SMTP on the install host (platform Haraka on TCP 25) for addresses on
@<tenant>.<env>.<baseDomain>, not a polled mailbox - One address per node - the local part is server-generated and opaque; it is never derived from your workflow id or username
- Owner-triggered runs - the run fires with your workflow’s owner identity, the same identity a scheduled cron run uses
- Inbox mode - each new email triggers one run that contains your entire inbox as a datagrid: one row per email, newest first, up to
maxEmailsrows (default 100) - Structured dataset rows - each row has typed columns (
from,sent,subject,body,to,cc,messageId) plus anattachmentsarray - Parsed attachments - Docling-supported files contribute markdown; CSV/TSV/PSV contribute tabular rows; other types soft-fail with
parseErrorwithout blocking the run
Pause and resume inbound triggers
Section titled “Pause and resume inbound triggers”On the canvas node (full card and compact / graph simplified view) a pause / play control toggles whether new mail starts runs. Pause sets the node disabled (common.execution.enabled: false); inbound SMTP then fail-closes for that node with no run. Resume turns triggers back on. You can still open the node and replay past messages manually while paused.
Getting your address
Section titled “Getting your address”Save the workflow, then open the Email Import tab on the node. Fontana provisions the address the first time you open the tab and shows it once ready:
<opaque-local-part>@<your-tenant>.<your-environment>.<baseDomain>Example: wf-….@demo.flow-dev.fontana-ai.com. You always see the address your deployment actually has, never a client-guessed value. If your deployment has not enabled inbound email, the tab tells you so instead of showing a broken address.
What happens when mail arrives
Section titled “What happens when mail arrives”- The sender’s MTA delivers to MX for your tenant mail hostname; the install host accepts SMTP on TCP 25 (STARTTLS) into the platform Haraka adapter.
- The adapter asks that tenant’s Convex control plane which workflow and node the opaque local-part maps to (
EMAIL_INGEST_KEY, metadata only). - MIME body, structured metadata (
email-meta.json), and attachment bytes are written straight into the tenant workflow-engine upload directory (same store as File Input), using a dedicated upload key. Convex does not store or transit the MIME bytes. - Convex ingest collects file references for all previous emails received on this node, merges in the new email’s references, and sorts everything newest-first up to
maxEmails(default 100). If a run is already queued but not yet started, its file references are replaced with the updated inbox. If the engine is processing a previous run, a new run is queued to start after it finishes. - The engine preload step groups file references by email, reads each email’s body and metadata, and writes one structured row per email to the node’s
outputport before any node in the workflow runs. - Each attachment is parsed on that run (Docling markdown, tabular rows, or soft-fail
parseError) and nested underattachments[]. - A run starts using the workflow owner’s identity for connectors and secrets, exactly as a scheduled cron run would.
Structured output rows
Section titled “Structured output rows”The output port is a multi-row datagrid with one row per email in your inbox, newest first:
| Column | Type | Notes |
|---|---|---|
from |
string | MIME From |
sent |
string | UTC sent stamp (same shape historically used on the canonical Sent: line) |
subject |
string | MIME Subject |
body |
string | Plaintext body only (no header block) |
to |
string[] | MIME To addresses (empty when absent) |
cc |
string[] | MIME Cc addresses (empty when absent) |
messageId |
string | Normalized Message-ID (empty when absent) |
attachments |
object[] | Per-file metadata and parse results |
Each attachments[] element includes name, extension, size, contentType, storedName, parseEngine (docling | tabular | none), and optional markdown, rows, or parseError. BCC is not exposed on output.
Row order is newest-first. The number of rows is capped by maxEmails (default 100). When a new email arrives, the entire inbox snapshot is re-materialized as the output dataset for that run.
This shape is Email Import only. File Input Paste mode still uses a single body column with an Outlook-style header block when you paste mail into Paste.
Downstream extract
Section titled “Downstream extract”Read native columns (from, sent, subject, to, cc, messageId, attachments) directly from Email Import. Wire a Template node only when you need fields embedded inside the plaintext body (for example Client / Order / Qty lines), then a Schema node for typed shapes. The email-structured-data-extract skill still builds Paste → Template → Schema for File Input Paste corpora; for inbound Email Import it prefers native header columns and Jinja for body-field extraction only.
Explore ships an Inbound Email Showcase community template with Email Import → Template (body fields) → Schema → Operation SWITCH siphons (rush vs standard by Qty) → separate Save File exports.
Inbox panel
Section titled “Inbox panel”On the Email Import tab, below the provisioned address, the Inbox panel lists every email this node has received (subject, sender, date). Click any row to expand it and read the body text. The body is fetched directly from the workflow-engine file store when you open the row; Convex is not in that path.
New runs start automatically when mail arrives. You do not need to replay or refresh; use the canvas Run button for a manual run.
Inbound email files are not listed on File Input Engine Files; the Inbox panel on this node is the only UI for these messages.
Inbox cap
Section titled “Inbox cap”The maxEmails setting in the Settings tab caps how many recent messages are packed into each run as rows (default 100). When your inbox exceeds the cap the oldest emails are dropped from the run; the Inbox panel still shows every received message. The other Settings fields (markAsRead, includeAttachments, autoReconnect) are stored on the node but not yet read by ingest.
What Email Import does not do
Section titled “What Email Import does not do”- It does not poll an IMAP mailbox or accept mailbox credentials
- It does not map the sender’s address to a Fontana user; the run always fires as the workflow owner
- It does not accept mail from third-party inbound webhook providers
- It does not see BCC’d or envelope-only recipients: your provisioned address is matched against the message’s
ToandCcheaders only. Mail addressed to your provisioned address solely through BCC does not trigger a run.
Enabling inbound email for a deployment
Section titled “Enabling inbound email for a deployment”Inbound email is an operator-enabled deployment feature. You enable the platform Haraka chart via the host fontana.yaml email.inbound block (domain, optional requireTls), point MX for each <tenant>.<domain> at the install host, and run fontana apply. Apply seeds per-tenant Convex ingest and engine upload credentials into the platform registry and publishes host TCP 25 to the platform inbound-smtp Service. STARTTLS reuses the Caddy ACME certificates already issued for those Flow tenant hosts; you do not supply separate mail PEMs. Apply fails closed if host TCP 25 cannot be published, or if requireTls is true and those Caddy certs are missing. See the Fontana CLI reference, docs/SECRET_HANDLING.md for the inbound email keys, and RUNBOOK_K8S.md for enable steps.
Related
Section titled “Related”- File Input - Paste mode still uses the Outlook-style
bodyheader block; Docling on document attachments - Template - extracts fields from plaintext
bodywhen native columns are not enough - Workflow schema - Full schema reference