Skip to content
Tier 2 Schema

Parse GitHub Notification Emails

Turn GitHub notification emails into typed JSON — repository, thread type, issue or PR number, actor, action, notification reason, and the canonical URL. Schema-first, API-native.

GitHub sends a notification email for nearly every event you subscribe to — a new issue, a pull request review request, a comment that @-mentions you. The signal you actually want (which repo, which PR, who acted, and why you were notified) is spread across the Subject, the X-GitHub-Reason header, and the message footer. MailFrame extracts those fields into a typed, schema-validated JSON object you can route to a queue, a chat bot, or your own triage dashboard.

It works on the notification emails GitHub sends for issues, pull requests, discussions, mentions, and review requests — the plain-text and HTML parts of the raw message you receive at notifications@github.com.

Fields MailFrame extracts

FieldTypeExampleNotes
repositorystringoctocat/Hello-Worldowner/repo, taken from the subject and List-ID header
thread_typeenumpull_requestOne of issue, pull_request, discussion, commit, release
thread_numberinteger482Issue, PR, or discussion number parsed from the subject
thread_titlestringAdd retry backoff to webhook senderSubject line with the Re:, repo, and #number stripped
actorstringalex-riveraLogin or display name of the user who triggered the event, from the From header and footer
actionenumcommentedOne of opened, closed, merged, commented, reopened, assigned, review_requested
reasonenummentionWhy you were notified, from X-GitHub-Reason: mention, team_mention, review_requested, assign, author, comment, subscribed, ci_activity
urlstringhttps://github.com/octocat/Hello-World/pull/482#issuecomment-1234567890Canonical link from the “view it on GitHub” footer
body_previewstring@jordan can you take a look at the backoff logic here?First line of the comment or event body
datestring2026-05-21Notification date normalized to ISO 8601

Sample input

A typical GitHub notification email — here, a comment on a pull request that mentions you — looks like this:

From: Alex Rivera <notifications@github.com>
Subject: Re: [octocat/Hello-World] Add retry backoff to webhook sender (#482)
Date: Thu, 21 May 2026 09:14:00 -0700
To: octocat/Hello-World <Hello-World@noreply.github.com>
Cc: Jordan <jordan@example.com>, Mention <mention@noreply.github.com>
Message-ID: <octocat/Hello-World/pull/482/c1234567890@github.com>
X-GitHub-Reason: mention
List-ID: octocat/Hello-World <Hello-World.octocat.github.com>

@jordan can you take a look at the backoff logic here? The retry loop
doubles the delay but never caps it, so a flaky endpoint could stall the
whole worker.


Reply to this email directly, or view it on GitHub:
https://github.com/octocat/Hello-World/pull/482#issuecomment-1234567890

You are receiving this because you were mentioned.

Structured JSON output

{
  "repository": "octocat/Hello-World",
  "thread_type": "pull_request",
  "thread_number": 482,
  "thread_title": "Add retry backoff to webhook sender",
  "actor": "alex-rivera",
  "action": "commented",
  "reason": "mention",
  "url": "https://github.com/octocat/Hello-World/pull/482#issuecomment-1234567890",
  "body_preview": "@jordan can you take a look at the backoff logic here?",
  "date": "2026-05-21"
}

JSON Schema definition

Every field is validated against the schema before MailFrame returns it. You can copy this as a starting point and tighten it for your own use case:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "github_notification",
  "type": "object",
  "required": ["repository", "thread_type", "actor", "reason"],
  "properties": {
    "repository": { "type": "string", "pattern": "^[^/]+/[^/]+$" },
    "thread_type": { "type": "string", "enum": ["issue", "pull_request", "discussion", "commit", "release"] },
    "thread_number": { "type": "integer", "minimum": 1 },
    "thread_title": { "type": "string" },
    "actor": { "type": "string" },
    "action": { "type": "string", "enum": ["opened", "closed", "merged", "commented", "reopened", "assigned", "review_requested"] },
    "reason": { "type": "string", "enum": ["mention", "team_mention", "review_requested", "assign", "author", "comment", "subscribed", "ci_activity"] },
    "url": { "type": "string", "format": "uri" },
    "body_preview": { "type": "string" },
    "date": { "type": "string", "format": "date" }
  }
}

Parse via the API

POST the raw email (MIME or plain text) to /v1/parse with the schema you want to extract against:

curl https://api.mailframe.ai/v1/parse \
  -H "Authorization: Bearer $MAILFRAME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "schema": "github_notification",
    "input": { "type": "email", "raw": "<base64-encoded MIME>" }
  }'

The call is synchronous: /v1/parse validates the extraction against your schema and returns the typed JSON in the HTTP response, so you can act on it inline — route it to a queue, a chat bot, or your own triage dashboard.

Prefer not to relay the email yourself? Inbox forwarding — pointing a Gmail or Outlook filter for notifications@github.com at a unique inbox address MailFrame assigns you — is on the roadmap. Until it ships, POST the raw email to /v1/parse as shown above.

On the roadmap

Today every parse happens synchronously over the API call above. Asynchronous webhook delivery — having MailFrame POST a signed envelope to your endpoint when a parse completes, instead of you reading it from the HTTP response — is planned, alongside inbox forwarding. Both are roadmap items, not shipped features.

Other schemas

Ship this schema in production

Define your fields once, then POST raw email to /v1/parse. MailFrame returns typed JSON in the HTTP response. (Unique inbox forwarding and signed webhook delivery are on the roadmap.)

Request early access