Tutorials / Local development
Tutorial · any language · 10 minutesTest your email webhook handler on localhost
Your webhook handler runs on your laptop, but email arrives on the internet. The GhostParse CLI closes that gap two ways: it simulates signed webhooks offline, and it streams real email to localhost as it arrives. No tunnel, no deploy.
▶ Watch the video walkthrough on YouTube
1. Simulate a webhook, with no account
Start your app, then point the sandbox at it. It posts a realistic email.received event, signed exactly as real ones are:
npx @wildye/email-parser-cli simulate http://localhost:3000/webhooks/email
! No signing secret given, so this test one is used: whsec_5mY0B… Give your app the same secret (or pass --secret with your real one) so it accepts these webhooks. 10:42:07 200 jane@sample.invalid → support@yourcompany.example "Re: Your order #1042 has shipped" 14 ms
Pass --secret whsec_… with the secret your app uses (from Dashboard → Inbound webhook once you have an account). Every simulated event has data.sandbox: true, so your code can tell a test from real mail.
2. Every event, and the awkward cases
email-parser simulate http://localhost:3000/webhooks/email --event bounced # an email you sent bounced email-parser simulate http://localhost:3000/webhooks/email --event complained # marked as spam email-parser simulate http://localhost:3000/webhooks/email --repeat 3 # the same webhook-id three times email-parser simulate http://localhost:3000/webhooks/email --bad-signature # a forgery: must be refused
--repeatsends the same webhook id each time, the way a retry would: your handler should store it once.--bad-signaturepasses only if your endpoint answers 4xx. If it says your endpoint accepted it, you aren't verifying signatures.
3. Your own emails, through your own parser
Save any email as an .eml file (in most mail apps: Save as or Download message). With an API key, the sandbox parses it with the same parser real mail goes through, and with --parser, adds what your rules parser extracts:
export EMAIL_PARSER_API_KEY=ek_live_… email-parser simulate http://localhost:3000/webhooks/email --eml ./invoice.eml --to invoices@yourcompany.com email-parser simulate http://localhost:3000/webhooks/email --eml ./invoice.eml --parser prs_…
Nothing is delivered, stored or counted against your plan. Add --print to see the event's JSON.
4. Real email, streamed to localhost
When you're ready for the real thing, listen forwards every email your account receives to your local URL, unchanged and still signed:
email-parser listen --forward http://localhost:3000/webhooks/email
Now send an email to one of your addresses and watch it arrive. Or send our realistic sample through the whole pipeline with email-parser sample.
5. Check your handler verifies signatures
The one thing every handler must do. With our SDKs it's one line:
import { verifyWebhook } from "@wildye/email-parser";
const event = verifyWebhook(rawBody, req.headers, process.env.GHOSTPARSE_WEBHOOK_SECRET); // throws if forged
from email_parser import verify_webhook event = verify_webhook(raw_body, request.headers, os.environ["GHOSTPARSE_WEBHOOK_SECRET"]) # raises if forged
Then email-parser simulate … --bad-signature should print Your endpoint rejected the bad signature. More languages in the docs.