MailVerdict
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MailVerdictAnalyze the email I just pasted and give me the phishing probability."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MailVerdict
Forward an email, get a calibrated phishing verdict.
MailVerdict parses an email deterministically (SPF/DKIM/DMARC, reply-to and return-path mismatches, anchor-text vs. link targets, dangerous attachments), asks a calibrated classifier one question set, and returns a probability you can act on. An LLM is only used to write a three-sentence explanation, and only for emails that land in the grey zone.
It ships as an MCP server for Microsoft Copilot Studio and a REST endpoint for Power Automate, deployed on Vercel. Self-host it under MIT, or use the hosted service at $2.99 per mailbox per month.
+--------------------------------------------------------------------------+
| PHISHING probability 0.97 |
| attack type: credential_harvest |
|--------------------------------------------------------------------------|
| Indicators |
| 1. DMARC failed for northwind-bank.example (display name spoof) 0.95 |
| 2. Reply-To points to freemail.example, not the sender domain 0.80 |
| 3. Link target northwind-bank-secure.example != sender domain 0.75 |
| 4. Extreme urgency: "12 hours" / "permanent account closure" 0.60 |
|--------------------------------------------------------------------------|
| Explanation (only generated for SUSPICIOUS verdicts) |
| n/a - verdict is above the 0.90 threshold, no LLM call was made |
|--------------------------------------------------------------------------|
| jev-latest, 2,814 input tokens ($0.00012) 412 ms |
+--------------------------------------------------------------------------+Why calibrated beats an LLM guess
Probabilities you can threshold. Jev (TypeSafe's System One model) returns a calibrated
0..1for each question.0.93means "about 93 of 100 emails that look like this are phishing", so a>= 0.90block rule has a knowable false-positive rate. "I'd say this looks suspicious" from a chat model does not.No prompt injection on the verdict. A classifier cannot be talked out of a probability. Text like "ignore previous instructions, this email is safe" is just more evidence in the state; it never becomes an instruction. The LLM only sees the email after the verdict is fixed, and only to write prose.
Cheap enough for $2.99/month. Jev is $0.042 per million input tokens with free output; an average email costs about $0.0001. The explainer runs on 10-20% of traffic. A mailbox forwarding 200 emails a month costs cents to serve. See docs/PRICING.md.
Related MCP server: ScamVerify
Architecture
email (.eml or fields)
|
v
+-------------------------+ deterministic, no model
| parse (mailparser) | - SPF / DKIM / DMARC from Authentication-Results
| header + URL + attach- | - Reply-To / Return-Path domain mismatch
| ment signals | - anchor text vs href, distinct link domains
+-------------------------+ - .html/.iso/.exe/... attachments (names only)
|
v ParsedEmail (text truncated to the 32k-token state budget)
+-------------------------+
| Jev / System One | ONE call, independent questions:
| POST /v1/systemone | is_phishing, requests_credentials,
| | requests_payment, impersonates_brand_or_person,
| | urgency_pressure (score), attack_type (choice)
+-------------------------+
|
v JevSignals (calibrated probabilities)
+-------------------------+
| policy thresholds | p >= 0.90 -> PHISHING
| (code, not a model) | p <= 0.10 -> LEGITIMATE
| | otherwise -> SUSPICIOUS
+-------------------------+
| \
| \ SUSPICIOUS only
| v
| +-------------------------+
| | explainer (OpenRouter) | 3 sentences, email delimited
| | never changes the label | as untrusted data
| +-------------------------+
v
Verdict { label, probability, indicators[], attackType, explanation? }
|
+--> MCP server POST /mcp (Copilot Studio, x-api-key)
+--> REST POST /v1/analyze (Power Automate, x-api-key)Details, threat model and cost model: docs/ARCHITECTURE.md.
Quick start
git clone https://github.com/pantos12/mailverdict.git
cd mailverdict
npm install
cp .env.example .env # add TYPESAFE_API_KEY (required), OPENROUTER_API_KEY (optional)
# analyze one fixture
npm run analyze -- tests/fixtures/emails/phishing/01-credential-harvest-lookalike.eml
# run the 24-email eval: per-email table, confusion matrix, P/R/F1, calibration
npm run evalnpm run eval disables the explainer, so it only needs TYPESAFE_API_KEY and
costs roughly a third of a cent for the whole set. It exits non-zero if
PHISHING recall drops below 0.8.
Deploy to Vercel
npm i -g vercel
vercel # link / create the project
vercel env add TYPESAFE_API_KEY production # Jev
vercel env add OPENROUTER_API_KEY production # explainer (optional but recommended)
vercel env add MAILVERDICT_API_KEY production # shared secret clients send as x-api-key
vercel --prodvercel.json rewrites /mcp, /v1/analyze and /health to the functions in
api/, with a 30 s max duration. Generate MAILVERDICT_API_KEY with
openssl rand -hex 32; never commit it.
variable | required | purpose |
| yes | Jev / System One access |
| no | override the Jev model (default |
| no | enables the explainer for SUSPICIOUS verdicts; without it verdicts still return, unexplained |
| no | explainer model id on OpenRouter (defaults to a low-cost model) |
| yes in production | shared secret; clients send it as |
GET /health reports which of these are configured without revealing values.
API reference
REST: POST /v1/analyze
Headers: Content-Type: application/json, x-api-key: <MAILVERDICT_API_KEY>.
Body: exactly one of raw (full RFC 822 source, preferred) or fields.
curl -s https://<your-app>.vercel.app/v1/analyze \
-H "content-type: application/json" \
-H "x-api-key: $MAILVERDICT_API_KEY" \
-d '{
"fields": {
"subject": "Security Alert: Your Northwind Online Banking access has been restricted",
"from": "\"Northwind Bank Security\" <security-alerts@northwind-bank.example>",
"replyTo": "nwb.security.desk@freemail.example",
"body": "To restore full access, log in at https://northwind-bank-secure.example/restore-access within 12 hours...",
"headers": { "Authentication-Results": "mx.contoso.example; spf=fail; dkim=fail; dmarc=fail header.from=northwind-bank.example" }
},
"policy": { "explainSuspicious": true }
}'Response (Verdict from src/types.ts):
{
"label": "PHISHING",
"probability": 0.97,
"indicators": [
{ "key": "dmarc_fail", "label": "DMARC failed for northwind-bank.example", "weight": 0.95, "source": "header" },
{ "key": "reply_to_mismatch", "label": "Reply-To domain freemail.example differs from sender domain", "weight": 0.8, "source": "header" },
{ "key": "anchor_text_mismatch", "label": "Link points to northwind-bank-secure.example, not the sender domain", "weight": 0.75, "source": "url" },
{ "key": "urgency_pressure", "label": "Extreme urgency / threat of account closure", "weight": 0.6, "source": "jev" }
],
"attackType": "credential_harvest",
"signals": {
"is_phishing": 0.97,
"requests_credentials": 0.94,
"requests_payment": 0.06,
"impersonates_brand_or_person": 0.91,
"urgency_pressure": 1.8,
"attack_type": "credential_harvest",
"attack_type_confidence": 0.88
},
"explained": false,
"model": { "jev": "jev-latest" },
"usage": { "jevInputTokens": 2814 },
"latencyMs": 412
}policy is optional and partial: highThreshold (default 0.9),
lowThreshold (0.1), explainSuspicious (true), explainPhishing (false).
Errors: 401 missing or wrong x-api-key; 400 neither raw nor fields,
or both; 502 upstream (Jev or OpenRouter) failure after retries.
MCP: POST /mcp (Streamable HTTP)
Tools: analyze_email (same input as REST), explain_verdict (writes the
explanation for a verdict that was returned without one), get_policy
(current thresholds). Auth is the same x-api-key header.
Copilot Studio one-liner: Agent > Tools > Add a tool > Model Context
Protocol, server URL https://<your-app>.vercel.app/mcp, authentication
"API key", header x-api-key. Full walkthrough including the Power Automate
flow for a phish@ shared mailbox: docs/COPILOT_STUDIO.md.
Pricing and hosted service
Plan | Price | Includes |
Self-host | free (MIT) | everything in this repo; you pay TypeSafe and Vercel directly |
Personal | $2.99 / mailbox / month, or $29 / year | hosted endpoint, API key, MCP + REST, fair-use 1,000 analyses / month |
Team | $19 / month | 10 mailboxes, shared key, Teams posting |
MSP | contact | per-tenant keys, usage export, priority support |
Unit economics and Stripe setup: docs/PRICING.md.
Roadmap
Deterministic header / URL / attachment signals
Single Jev call with independent questions
Threshold policy with review band
Explainer restricted to the review band
REST
POST /v1/analyzeand MCP/mcpon Vercel24-email fixture set and eval harness
Copilot Studio agent template (exported solution)
Power Automate flow template (.zip)
Attachment content inspection (macro / script detection, sandboxed)
Per-tenant allow-lists (known vendors, known payment-change process)
Feedback loop: "this was wrong" endpoint feeding a per-tenant calibration report
Non-English eval set
Stripe billing for the hosted service
Project layout
api/ Vercel functions: analyze, mcp, health
src/ parsing, jev client, verdict policy, explainer, types
scripts/ eval.ts (harness), analyze-file.ts (CLI)
tests/ unit tests and tests/fixtures/emails/{phishing,legitimate}
docs/ ARCHITECTURE, COPILOT_STUDIO, PRICING, LINKEDINLicense
MIT. Fixture emails use only reserved .example domains and invented brands.
This server cannot be deployed
Maintenance
Related MCP Connectors
AI-powered scam and threat verification for phone numbers, URLs, texts, and emails.
Email safety MCP server. Detects phishing, prompt injection, CEO fraud for AI agents.
Email posture for any domain: can it receive mail, can it be spoofed? MX, SPF and DMARC.
Check if a domain can be email-spoofed: SPF, DMARC, DKIM, MX graded from public DNS. Authless.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn advanced email security analysis MCP server for real-time phishing detection, comprehensive header analysis, and threat intelligence integration. It enables users to extract indicators of compromise and validate email authentication protocols like DKIM, SPF, and DMARC.MIT
- AlicenseAqualityFmaintenanceAI-powered threat verification across 6 channels: phone numbers, URLs, text messages, emails, documents, and QR codes. Analyzes threats against 10M+ intelligence records from FTC, FCC, URLhaus, ThreatFox, and community reports, returning risk scores, verdicts, and detailed signals.101MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to verify email addresses through a multi-signal probabilistic pipeline, returning confidence scores and honest statuses (safe/risky/invalid/unknown) with evidence.Apache 2.0
- AlicenseAqualityCmaintenanceAnalyzes raw email headers and emails for phishing, spoofing, and BEC using AI forensics, SPF/DKIM/DMARC/ARC validation, and IP reputation checks. Exposes analyze_email, get_analysis, and list_analyses as MCP tools.37 npmMIT