Extract data from email
To extract data from email automatically, describe the fields you need in plain English and forward the emails to a ParsedMail inbox. A language model reads each body and attachment, fills the fields with typed values such as dates, money and line-item tables, and scores its confidence in every value.
Email received
Fields described as
booking reference, guest name, check-in date, check-out date, number of guests, room type, total price, special requests (list)
JSON delivered to your webhook
{ "booking_reference": "HX-30918", 0.99 "guest_name": "Tomasz Wilk", 0.98 "check_in_date": "2026-11-07", 0.97 "check_out_date": "2026-11-10", 0.97 "number_of_guests": 2, 0.95 "room_type": "Deluxe Double, sea view", 0.94 "total_price": { "amount": 486, "currency": "EUR" }, 0.98 "special_requests": [ "Late arrival around 23:00", "Baby cot" ] 0.87 }
Describe the fields, not the layout
You write what you want, for example "booking reference, guest name, check-in date, check-out date, number of guests, total price, special requests". ParsedMail turns that sentence into a typed schema you can review: field names, types and which fields are required. Adjust anything, add descriptions where a field is ambiguous ("total price including taxes"), and test the schema against a real sample email in the dashboard before switching on live mail.
There is no template per sender and no regular expression to maintain. The same schema reads a booking from a channel manager, a forwarded guest email and a reservation in a PDF. This is the core difference explained on the AI email parser page.
Field types that come back ready to use
Values are converted to their declared type before delivery, so your code does not have to clean them:
| Type | Output |
|---|---|
| string, email, phone, url | Text, normalized where it makes sense |
| number, integer | 18000, 2 |
| money | {"amount": 486.0, "currency": "EUR"} |
| date, datetime | 2026-11-07, ISO 8601 |
| boolean | true or false |
| enum | One of the options you list |
| list | Array of strings |
| table | Array of row objects with typed columns, such as line items |
A schema holds up to 60 fields. The exact JSON shape is described on parse email to JSON, and every schema exports as JSON Schema draft 2020-12.
Only what is in the email
The model is instructed to use only text present in the message and its attachments. Quoted replies, signatures and footers are ignored, so the sender's phone in a signature does not end up as the customer phone of a forwarded order. A value that is not there comes back as null. A value that is there but cannot be converted, such as "sometime next week" in a date field, also becomes null with an entry in warnings.
Confidence for every value
Each field gets a confidence score from 0 to 1 and the email gets confidence_avg. In the example above the special requests score lower than the booking reference, because they come from a free-text note. Use the scores in your own code, for example to auto-confirm bookings above 0.9, or let ParsedMail route anything under a threshold to the human review queue on Growth and Scale. A missing required field always scores 0.
Attachments and bodies in one result
Data often sits partly in the body and partly in a PDF or CSV. ParsedMail reads up to 8 attachments per email and merges what it finds into the same fields, including tables of line items. Scanned PDFs and images are read as images on paid plans. See parsing email attachments for formats and page counting.
Schemas that change safely
Requirements change: finance wants a cost center, the warehouse wants the delivery window. Edit the schema and its version number increments. Each parsed email records the schema_version it used, and you can replay stored emails against the new version. A replay of an email that was already counted is not counted again, so fixing a schema does not eat your quota.
Enums and booleans for routing decisions
Extraction is not only about copying values. An enum field turns a free-text email into a decision your automation can branch on. Define "request type, one of new order, change, cancellation, complaint" and every email comes back with exactly one of those options, never a fifth variant spelled differently. A boolean such as "refund requested" or "urgent" works the same way. Your Zapier path, n8n switch node or own code can route on these fields without any text matching.
This is where reading meaning pays off. A customer who writes "please do not send the second box after all" never uses the word cancellation, but the enum still comes back as cancellation, with a confidence score that tells you how sure the model is. The support email use case shows a full routing setup.
Three ways to send email in
- Forwarding. Each inbox has an address such as
[email protected]. Point a Gmail filter, an Outlook rule, a mail server alias or a BCC at it. Plus tags such as[email protected]reach the same inbox. - API. Post raw MIME, pasted text or structured fields to
POST /inboxes/{id}/emails, or callPOST /parsefor a synchronous result. - Own domain. On Scale, receive on an address like
[email protected]with an MX record.
Allowed senders per inbox (single addresses or whole @domain entries) keep stray mail out; anything else is logged as blocked_sender and not counted. Duplicates by Message-ID, or by the same sender, subject and body within 30 days, are marked duplicate and not charged.
Frequently asked questions
What kinds of data can be extracted from email?
Do I have to train the extraction on examples?
How many fields can one schema have?
What happens with emails that do not match the schema?
Is extracted data used to train models?
Related
See your own email as JSON
Paste one into the demo, describe the fields and look at the result. No account needed.