Email parser quickstart
To get your first parsed email, create an inbox, describe the fields you need in plain English, then forward an email to the inbox address or POST it to the API. ParsedMail returns a JSON object with your keys, typed values and a confidence score per field, by webhook or from the REST API.
Create an account and confirm your address
Sign up with an email address and a password, then enter the code we send to that address. Confirming the address unlocks a one-time sandbox of 10 emails with one inbox. The sandbox reads attachments of one page and no scans, and keeps raw emails for 7 days. It is not a plan and it does not renew. Webhook delivery starts with a paid plan, so in the sandbox you read results in the dashboard or with the API.
Everything below works the same on Starter, Growth and Scale. The plan limits are listed in errors and limits.
Create an inbox and a schema
In the dashboard open Inboxes and create one per workflow, for example "Orders". Each inbox gets its own address made of the name and a short random suffix:
[email protected]Then open Schemas, create a schema and describe the fields in one sentence:
order number, customer name, customer email, products with quantity and price, total, delivery dateParsedMail turns the sentence into typed fields that you can adjust before saving:
order_number string
customer_name string
customer_email email
products table (name string, quantity integer, price money)
total money
delivery_date dateAttach the schema to the inbox. The same steps work through the API with POST /v1/schemas and POST /v1/inboxes. Field types, tables and versioning are covered in defining schemas.
Send your first email
The quickest test is to forward any order confirmation from your mailbox to the inbox address. For a steady flow, set up a Gmail filter, an Outlook rule or a mail server alias as described in inboxes and forwarding.
If the email already sits in your own system, POST it to the inbox with an API key that has the parse scope:
curl https://parsedmail.com/api/v1/inboxes/inb_8k2m4q7d1x/emails \
-H "Authorization: Bearer $PARSEDMAIL_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"from": "[email protected]",
"subject": "Order #NW-48213 confirmed",
"text": "Order number: NW-48213\nCustomer: Dana Ortiz\n2 x Burr grinder K6 @ $189.00\nTotal: $378.00\nEstimated delivery: October 21, 2026"
}'The API answers right away with 202 Accepted and the email id. Parsing runs in the background and usually takes a few seconds:
{"id": "eml_f0qfttfnggyv5cn4a3ka", "object": "email", "status": "received"}Raw MIME files, pasted text and base64 attachments are covered in sending emails.
Read the parsed result
The email appears in the dashboard log with the original next to the JSON. With the API, fetch it by id:
curl https://parsedmail.com/api/v1/emails/eml_f0qfttfnggyv5cn4a3ka \
-H "Authorization: Bearer $PARSEDMAIL_KEY" \
-H "Accept: application/json"{
"id": "eml_f0qfttfnggyv5cn4a3ka",
"object": "email",
"inbox": "inb_8k2m4q7d1x",
"inbox_address": "[email protected]",
"schema": "sch_vnf3updh2qin",
"schema_version": 1,
"status": "parsed",
"received_at": "2026-10-15T09:12:04+00:00",
"from": {"email": "[email protected]", "name": null},
"to": "[email protected]",
"subject": "Order #NW-48213 confirmed",
"message_id": null,
"duplicate_of": null,
"attachments": [],
"data": {
"order_number": "NW-48213",
"customer_name": "Dana Ortiz",
"customer_email": null,
"products": [
{"name": "Burr grinder K6", "quantity": 2, "price": {"amount": 189, "currency": "USD"}}
],
"total": {"amount": 378, "currency": "USD"},
"delivery_date": "2026-10-21"
},
"confidence": {"order_number": 0.99, "customer_name": 0.95, "customer_email": 0.5, "products": 0.96, "total": 0.98, "delivery_date": 0.94},
"confidence_avg": 0.964,
"needs_review": false,
"reviewed": false,
"classification": null,
"warnings": [],
"sandbox": false
}A value that is not in the email is null (an empty array for lists and tables), never a guess. When the status is still received or processing, wait a moment and fetch again, or let the webhook tell you.
Add a webhook
On a paid plan open Webhooks, add an https URL and copy the signing secret that starts with whsec_. Every parsed email is POSTed to that URL as JSON with a ParsedMail-Signature header. A minimal receiver in Node:
import crypto from "node:crypto";
import express from "express";
const app = express();
app.post("/webhooks/parsedmail", express.raw({ type: "application/json" }), (req, res) => {
const parts = Object.fromEntries(
(req.get("ParsedMail-Signature") || "").split(",").map((p) => p.trim().split("="))
);
const expected = crypto
.createHmac("sha256", process.env.PARSEDMAIL_WEBHOOK_SECRET)
.update(`${parts.t}.${req.body}`)
.digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) <= 300;
if (!fresh || expected !== parts.v1) return res.sendStatus(400);
const event = JSON.parse(req.body);
console.log(event.type, event.data.id, event.data.data);
res.sendStatus(200);
});
app.listen(3000);Press Send test event to check the endpoint. Use a constant time comparison in production; complete examples for Node, Python, PHP and Go and the retry schedule are in webhooks.
Create an API key
Open API keys, give the key a name and pick its scopes. The key belongs to the workspace you are in when you create it and is shown once, so store it in your secret manager right away.
| Scope | Allows |
|---|---|
read | List and fetch inboxes, schemas and emails |
parse | Submit emails, replay emails, call POST /v1/parse |
write | Create inboxes, create and update schemas, delete emails |
New keys get read and parse by default. Check the key with the usage endpoint, which every key may call:
curl https://parsedmail.com/api/v1/usage \
-H "Authorization: Bearer $PARSEDMAIL_KEY" \
-H "Accept: application/json"{"plan": "starter", "emails_used": 12, "emails_limit": 1000, "pages_used": 4, "pages_limit": 300, "period_start": "2026-10-03", "period_end": "2026-11-03"}The Accept: application/json header in these examples is optional; the API always answers in JSON. Every endpoint is described in the API reference.
Frequently asked questions
Do I need to write code to use ParsedMail?
How long does parsing take?
Can I test without forwarding real email?
/v1/inboxes/{id}/emails. Each test run counts as one email.
What happens when my inbox has no schema yet?
failed and the message "This inbox has no schema yet". Attach a schema and replay it from the log or with POST /v1/emails/{id}/replay.