.txt file; the Python SDK does that for you when you pass text=.
The graph
{
"name": "Email lead extractor",
"nodes": [
{ "id": "parse_1", "type": "parse" },
{
"id": "extract_1",
"type": "extract",
"extraction_schema": {
"fields": [
{ "name": "sender_name", "description": "Full name of the person who sent the email", "data_type": "string" },
{ "name": "sender_email", "description": "Email address of the sender", "data_type": "string" },
{ "name": "company_name", "description": "Company or organization the sender represents", "data_type": "string" },
{
"name": "inquiry_type",
"description": "The primary category of this inquiry",
"data_type": "enum",
"enum_options": [
{ "name": "pricing", "description": "Pricing or cost inquiry" },
{ "name": "demo_request", "description": "Request for a product demo" },
{ "name": "support", "description": "Technical support or help request" },
{ "name": "partnership", "description": "Partnership or integration inquiry" },
{ "name": "other", "description": "Other inquiry type" }
]
},
{
"name": "urgency",
"description": "How urgent this request appears based on language and deadlines mentioned",
"data_type": "enum",
"enum_options": [
{ "name": "low", "description": "No urgency signals" },
{ "name": "medium", "description": "Moderate urgency or soft deadline" },
{ "name": "high", "description": "Explicit deadline or urgent language" }
]
},
{
"name": "topics",
"description": "Products or areas of interest mentioned in the email",
"data_type": "multi_select",
"enum_options": [
{ "name": "enterprise", "description": "Enterprise plan or features" },
{ "name": "integration", "description": "Integration or API capabilities" },
{ "name": "pricing", "description": "Pricing or billing" },
{ "name": "security", "description": "Security or compliance" }
]
},
{ "name": "summary", "description": "A one-sentence summary of what the sender is asking for", "data_type": "string" }
]
}
}
],
"edges": [{ "source": "parse_1", "target": "extract_1" }]
}
import os
from anyformat.sdk import Client
from anyformat.workflow import Schema
client = Client(api_key=os.environ["ANYFORMAT_API_KEY"])
workflow = (
client.workflow("Email lead extractor")
.parse()
.extract([
Schema.string("sender_name", "Full name of the person who sent the email"),
Schema.string("sender_email", "Email address of the sender"),
Schema.string("company_name", "Company or organization the sender represents"),
Schema.enum("inquiry_type", "The primary category of this inquiry", options=[
Schema.option("pricing", "Pricing or cost inquiry"),
Schema.option("demo_request", "Request for a product demo"),
Schema.option("support", "Technical support or help request"),
Schema.option("partnership", "Partnership or integration inquiry"),
Schema.option("other", "Other inquiry type"),
]),
Schema.enum("urgency", "How urgent this request appears based on language and deadlines mentioned", options=[
Schema.option("low", "No urgency signals"),
Schema.option("medium", "Moderate urgency or soft deadline"),
Schema.option("high", "Explicit deadline or urgent language"),
]),
Schema.multi_select("topics", "Products or areas of interest mentioned in the email", options=[
Schema.option("enterprise", "Enterprise plan or features"),
Schema.option("integration", "Integration or API capabilities"),
Schema.option("pricing", "Pricing or billing"),
Schema.option("security", "Security or compliance"),
]),
Schema.string("summary", "A one-sentence summary of what the sender is asking for"),
])
.create()
)
import { Anyformat, Schema } from "@anyformat/sdk";
const af = new Anyformat({ apiKey: process.env.ANYFORMAT_API_KEY! });
const workflow = await af
.workflow("Email lead extractor")
.parse()
.extract([
Schema.string("sender_name", "Full name of the person who sent the email"),
Schema.string("sender_email", "Email address of the sender"),
Schema.string("company_name", "Company or organization the sender represents"),
Schema.enum("inquiry_type", "The primary category of this inquiry", [
Schema.option("pricing", "Pricing or cost inquiry"),
Schema.option("demo_request", "Request for a product demo"),
Schema.option("support", "Technical support or help request"),
Schema.option("partnership", "Partnership or integration inquiry"),
Schema.option("other", "Other inquiry type"),
]),
Schema.enum("urgency", "How urgent this request appears based on language and deadlines mentioned", [
Schema.option("low", "No urgency signals"),
Schema.option("medium", "Moderate urgency or soft deadline"),
Schema.option("high", "Explicit deadline or urgent language"),
]),
Schema.multiSelect("topics", "Products or areas of interest mentioned in the email", [
Schema.option("enterprise", "Enterprise plan or features"),
Schema.option("integration", "Integration or API capabilities"),
Schema.option("pricing", "Pricing or billing"),
Schema.option("security", "Security or compliance"),
]),
Schema.string("summary", "A one-sentence summary of what the sender is asking for"),
])
.create();
Run and read
Send the email body as a text file. Any.txt works; a saved .eml works too and keeps the headers.
# The body of the email, saved as a file
curl -X POST "https://api.anyformat.ai/v3/workflows/$WORKFLOW_ID/upload/run/" \
-H "Authorization: Bearer $ANYFORMAT_API_KEY" \
-F 'files=@lead-email.txt;type=text/plain'
# -> 202 {"run_id": "...", "status": "queued"}
# Read the run. Repeat until "status" is "processed".
curl "https://api.anyformat.ai/v3/runs/$RUN_ID/" \
-H "Authorization: Bearer $ANYFORMAT_API_KEY"
email_text = """From: Maria Lopez <maria.lopez@acmecorp.example>
Subject: Enterprise pricing for Q2 rollout
Hi, I am the VP of Engineering at Acme Corp. We process about 40,000 supplier
invoices a month ... Our board meets on June 12 and I need a quote and a
security overview before then. ..."""
# text= uploads the string as a .txt file for you
result = workflow.run(text=email_text).wait()
lead = {name: field.value for name, field in result.fields.items()}
if lead["urgency"] == "high":
print(f"HIGH PRIORITY: {lead['sender_name']} from {lead['company_name']}")
import type { ExtractedField } from "@anyformat/sdk";
const emailText = `From: Maria Lopez <maria.lopez@acmecorp.example>
Subject: Enterprise pricing for Q2 rollout
Hi, I am the VP of Engineering at Acme Corp. ...`;
const file = new File([emailText], "lead-email.txt", { type: "text/plain" });
const run = await workflow.run(file);
const result = await run.wait();
// field() can return a scalar or rows; every field here is a scalar
const field = (name: string) => result.field(name) as ExtractedField<string> | undefined;
if (field("urgency")?.value === "high") {
console.log(`HIGH PRIORITY: ${field("sender_name")?.value} from ${field("company_name")?.value}`);
}
What comes back
The run above, trimmed. It took 10 seconds. Every field also carriesverification_status and value_override; only the first shows them here.
{
"id": "06a8d903-aa8e-7da7-8000-1f5d790c85f7",
"status": "processed",
"results": {
"document_packet_id": "06a8d903-a825-759d-8000-1ebf38d10ce5",
"verification_url": "https://app.anyformat.ai/workflows/.../files/...",
"parse": { "markdown": "<a id=\"md_p1_b0\"></a>\n\nFrom: Maria Lopez <maria.lopez@acmecorp.example> ...", "blocks": [] },
"classifications": [],
"splits": [],
"extractions": [
{
"split_name": null,
"partition": null,
"fields": {
"sender_name": { "value": "Maria Lopez", "confidence": 99.0, "verification_status": "not_verified", "value_override": null,
"evidence": [{ "text": "From: Maria Lopez <maria.lopez@acmecorp.example>", "page_number": 1 }] },
"sender_email": { "value": "maria.lopez@acmecorp.example", "confidence": 99.0, "evidence": [ "..." ] },
"company_name": { "value": "Acme Corp", "confidence": 99.0, "evidence": [{ "text": "I am the VP of Engineering at Acme Corp.", "page_number": 1 }] },
"inquiry_type": { "value": "pricing", "confidence": 98.0, "evidence": [{ "text": "1. What does the enterprise plan cost at our volume?", "page_number": 1 }] },
"urgency": { "value": "high", "confidence": 99.0, "evidence": [{ "text": "Our board meets on June 12 and I need a quote and a security overview before then.", "page_number": 1 }] },
"topics": { "value": "enterprise, pricing, security, integration", "confidence": 98.0, "evidence": [ "..." ] },
"summary": { "value": "Maria Lopez is requesting an enterprise-volume quote, security overview including SSO and SOC 2 report, and ERP API integration information before June 12.", "confidence": 4.0, "evidence": [ "..." ] }
}
}
],
"edits": []
}
}
Tips
- A
multi_selectvalue comes back as one comma-separated string:"enterprise, pricing, security, integration". Split on", "to get the list. - Expect a low confidence on a generated
summary. The sentence is not quoted from the email, so it scores low even when it is right. Gate on the extracted fields, not on the summary. - Write
enum_optionsdescriptions that separate the close cases.pricinganddemo_requestare easy to confuse without them. - A
.txtupload has no layout, soparse.blocksis empty andparse_confidenceisnull. That is expected for text input. - To process a mailbox, create the workflow once and call upload/run per email. The submission limit is 60 requests per minute.
Next steps
Extract node
Field types, modes and smart lookup
Upload and run
Multipart fields, conflicts and idempotency
Classify node
Route each email type to its own Extract node
Field types
Every data type a field can take

