Email in.
Clean JSON out.
GhostParse receives email for your domain, proves who really sent it, pulls out the data you need and delivers it, signed, to your app, Slack, Sheets or Zapier. Without keeping a single message.
1,000 emails a month free · no credit card
Received: from mail.example.com ([203.0.113.9]) From: Jane Sample <jane@example.com> To: support@yourapp.com Subject: Re: Your order #1042 has shipped DKIM-Signature: v=1; a=rsa-sha256; d=example.com; Content-Type: multipart/mixed; boundary="b1" --b1 Hi, the tracking link says delivered but nothing has arrived. Order #1042, total £42.50. Tracking number TRK-88213. > On Mon, Your App <orders@yourapp.com> wrote: > Good news: your order has shipped… --b1 Content-Disposition: attachment; filename="order-1042.csv"
{
"type": "email.received",
"data": {
"from": { "address": "jane@example.com" },
"subject": "Re: Your order #1042 has shipped",
"reply_text": "Hi, the tracking link says…",
"thread_id": "thr_9f2c41d07ab3e5c8",
"authentication": { "verdict": "pass" },
"attachments": [ "order-1042.csv" ],
"extracted": {
"order_number": "1042",
"total": 42.50,
"tracking": "TRK-88213"
}
}
}
1042
42.5
TRK-88213
| received_at | from | order | total |
|---|---|---|---|
| 09:58 | sam@shop.test | 1039 | 18.00 |
| 10:17 | li@mail.test | 1041 | 64.20 |
| 10:42 | jane@example.com | 1042 | 42.50 |
New row added to “Orders › Inbox”
Plugs into what you already run
- Node.js
- Python
- PHP
- Laravel
- Ruby
- Go
- Zapier
- Make
- n8n
- Slack
- Microsoft Teams
- Google Sheets
We read it.
We pass it on.
We forget it.
Mail is parsed in memory and handed to you the moment it arrives. No inbox, no archive, no copy waiting to leak. Your delivery log keeps only the metadata you need to debug: never a subject, body or attachment.
How we handle your data →The boring parts of email, done properly.
Ask for fields, get fields.
Say what you need (an order number, a total, a tracking code) and every email arrives with it already pulled out in data.extracted.
Replies, not quote chains.
Just the new words, with the history and signature cut away.
Invoices here. Urgent there.
One thread_id per conversation.
From References, In-Reply-To, even Outlook's Thread-Index. Match replies to tickets without guessing.
thr_9f2c41d07ab3e5c8Know who really sent it.
We check SPF, DKIM and DMARC ourselves and give you one verdict you can trust.
Develop against real mail. No tunnel.
The CLI streams every email to your laptop, signature and all, so your handler runs unchanged.
$ email-parser listen --forward localhost:3000 Ready. Waiting for mail… 10:42:07 200 jane@example.com → support@yourapp.com 10:42:31 200 sam@shop.test → orders@yourapp.com▍
Your brand. Our engine.
Sub-accounts, your logo, your MX hostname and your dashboard address, all through one API key.
Ten lines to production.
Verify the signature, read the JSON, done. Standard Webhooks signing means the library you already trust works too.
import { verifyWebhook } from "@wildye/email-parser"; app.post("/hooks/email", express.raw({ type: "*/*" }), (req, res) => { const event = verifyWebhook(req.body, req.headers, process.env.WEBHOOK_SECRET); if (event.type === "email.received") { const email = event.data; tickets.reply(email.thread_id, email.reply_text); } res.sendStatus(200); });
from email_parser import verify_webhook @app.post("/hooks/email") def email_hook(): event = verify_webhook(request.get_data(), request.headers, WEBHOOK_SECRET) email = event.email tickets.reply(email.thread_id, email.reply_text) return "", 200
use Wildye\EmailParser\Webhook; $event = Webhook::fromGlobals(getenv('WEBHOOK_SECRET')); if ($event->isEmailReceived()) { $email = $event->email(); Tickets::reply($email->field('order_number'), $email->replyText); } http_response_code(200);
Receiving in three steps.
Point your MX
Add two DNS records. We show the exact values and check them live.
Choose your addresses
Allow exactly the addresses you want (support@, orders@, ticket-*) and say where each one's mail goes.
Receive clean JSON
Signed, verified and parsed, at your webhook in milliseconds. Endpoint down? We try your backup URL, then ask the sender to retry.
Built for conversations, not campaigns.
Keeping the platform and its free plan free depends on keeping it clean. Using it for email marketing breaks our Terms and gets accounts closed.
✓ Built for
- Customer replies to your app's notifications
- Support inboxes that become tickets
- Invoices, receipts and documents emailed into your app
- Alerts and reports from other systems
✕ Not allowed
- Newsletters, promotions and marketing campaigns
- Bulk or mailing-list sends, cold outreach
- Any email the recipient didn't ask for
- Spoofing, phishing or misleading senders
Free to start. Fair as you grow.
Your inbox,
as an API.
Sign up, point a domain at us, send it an email. You'll see the JSON in your dashboard in seconds.