JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 54
  • Score
    100M100P100Q82970F
  • License Apache-2.0

Email-native multi-party coordination kernel: turns a promise made over email into proof. DKIM/DMARC-verified replies, a tamper-evident git ledger, workflow sequencing, and email triggers. Extracted from gitdone.

Package Exports

  • mailproof
  • mailproof/package.json

Readme

    ╭─────────────────────────────────╮
    │  ╔╦╗╔═╗╦╦  ╔═╗╦═╗╔═╗╔═╗╔═╗      │
    │  ║║║╠═╣║║  ╠═╝╠╦╝║ ║║ ║╠╣       │
    │  ╩ ╩╩ ╩╩╩═╝╩  ╩╚═╚═╝╚═╝╩        │
    │   reply ──→ verify ──→ commit   │
    │      ↑                  │       │
    │      └──────────────────┘       │
    ╰──╮──────────────────────────────╯
       ╰── proof, from the inbox

CI status npm version version (auto from package.json) license: Apache 2.0

Turn an email reply into proof. Multi-party sign-offs and document notarization over plain email — verifiable by anyone, offline, forever.

You get a record that a specific person agreed to a specific thing — and it holds up without you. No app to install, no account to create: people reply from their normal inbox. Each reply is cryptographically tied to its sender by the email they already trust (DKIM), and the whole history is a git repository anyone can verify with stock tooling — even if your service is long gone. It's the opposite of a signing SaaS: nothing to log into, no vendor to trust, no proof that evaporates when a company pivots or shuts down.

What you can do with it

  • Get a contract signed — one counterparty, one verified reply, bound to the exact document. A declaration (a contract, a pink slip): the signed file never leaves your server, only its fingerprint + the proof.
  • Run a petition or collect attestations — N distinct, provably-real people sign one thing, counted to a threshold. Open to anyone via a single address, or an explicit allow-list.
  • Drive an approval chain — release gates, vendor sign-offs, onboarding — in order, where every step is proven by the person who actually did it, and clearing one step emails the next automatically.
  • Notarize that something existed when you say it did — optionally stamp every record against Bitcoin via OpenTimestamps, so the proof of when needs no trust in you or any server.

Under all four: every reply — even a rejected one — is committed to a tamper-evident ledger, graded for trust (DKIM/DMARC/SPF/ARC), with a counted flag for whether it advanced. The audit trail is complete; trust gates the decision, never the record.

Quick start

npm i mailproof   # 2 runtime deps (mailauth, mailparser); Node ≥ 22.5

1. Give your AI assistant the integration guide

Read mailproof.context.md from node_modules/mailproof/mailproof.context.md

This single file is the complete wiring contract — every create() option, the API + ingest() result shape, the plus-tag address space, the composeNotification hook + 12 occasion kinds, the trust model, and the gotchas. It's structured for LLM consumption: your agent reads it once and knows how to wire the library correctly.

2. Describe what you want

I need to collect three sign-offs by email, in order, and end up with an
offline-verifiable proof each person really replied. Use mailproof. The
integration guide is in mailproof.context.md.

Not sure what you need? Paste this into any AI assistant:

I want to build an email-coordination or digital-notary flow with mailproof.
Read the integration guide at node_modules/mailproof/mailproof.context.md,
then ask me up to 5 questions about what I need. Based on my answers, tell me
which mode to use (workflow vs crypto sign-off) and show me the wiring code.

What's inside

One create() binds four decoupled pillars over a single data dir; take the bound methods, or the lower-level named exports to compose your own pipeline.

Piece What it does
create({ dataDir, domain, … }) Composition root — binds verify + sequence + git ledger + triggers over one dir
ingest(raw, envelope) The inbound pipeline: prefilter → DKIM/DMARC verify → route → commit (accept-with-flag) → advance state → trigger the next email
Trust classify classifyTrust grades each reply verified / forwarded / authorized / unverified from DKIM + DMARC + SPF + ARC
Events (workflow) Ordered / parallel / custom steps among named participants; completion = all steps done
Crypto sign-off Declaration (1 signer) or attestation (threshold of distinct signers), open or allow-listed, with an optional requiredDocHash
Notary hashDocument / verifyDocument — bind a hashed document to a verified signature; plaintext addresses + bytes are never stored
Git ledger A per-event git repo; listCommits is the tamper-evident chain — every reply committed, counted records whether it advanced state
Offline verify verify() / reverify() re-check a commit against the archived DKIM key — holds even with live DNS down
OTS anchoring Optional otsBinupgradeProofs() folds a Bitcoin OpenTimestamps anchor into each commit's proof
Triggers 12 neutral occasion kinds (activation, advance, completion, overdue, bounce, verify_report, …) over one composeNotification hook
Lifecycle activateEvent · editEvent · completeEvent · reopenEvent · sweep() (overdue nudge + auto-archive)

Modes: two generic ones — an events workflow and a crypto sign-off (declaration / attestation). Branding, web UI, auth, and the heavy attestation tail (revoke, multi-doc manifests, alternate dedup) are consumer policy, not kernel.

Transport: bundled self-hosted Postfix/sendmail, with opendkim signing outbound at the MTA — not a pluggable third-party mail provider.

Deps: 2 runtime — mailauth (DKIM/DMARC/ARC) + mailparser (MIME), both required because verifying/parsing untrusted mail is security-critical. The git ledger shells out to the git binary (no simple-git); ots is an optional external binary. Pure ESM + JSDoc, no consumer build step; ships generated strictNullChecks-checked .d.ts.

This table is the map, not the manual — per-option wiring and API detail live in the Integration Guide and docs/.


Recipes

The 80% path is short; full wiring — every option, the ingest() result, the trust model — is in the Integration Guide.

An ordered approval chain, proven — each step confirmed by the person who did it, the chain emailing the next automatically:

import { create } from 'mailproof';

const core = create({ dataDir: './data', domain: 'app.example', sendmailBin: '/usr/sbin/sendmail' });

await core.createEvent({
  id: 'onboarding42', type: 'workflow', flow: 'sequential', initiator: 'boss@app.example',
  steps: [
    { id: 'legal',   participant: 'alice@corp.example' },
    { id: 'finance', participant: 'bob@corp.example' },
  ],
});
await core.activateEvent('onboarding42');        // emails the first step

// Postfix pipes each reply in; mailproof verifies, commits, advances, emails the next:
const res = await core.ingest(rawEmail, { sender, recipient, clientIp, clientHelo });
// res.counted → did it advance?   res.eventComplete → all done?

A two-party contract, signed and provable offline — bound to the exact document, nothing sensitive stored:

import fs from 'node:fs/promises';

const doc = await fs.readFile('./contract.pdf');
await core.createEvent({
  id: 'contract42', type: 'crypto', initiator: 'you@app.example',
  signers: ['counterparty@firm.example'],
  threshold: 1,                              // one verified signer = a declaration
  requiredDocHash: core.hashDocument(doc),   // the reply must attach exactly this file
});
await core.activateEvent('contract42');
// They reply with the file → DKIM-verified + hash-matched → committed + complete.
// Only the sha256 + DKIM proof are stored; the document never leaves your server.

Same crypto shape scales to a petition (open: true, threshold: 100 — anyone verified counts), and anyone can re-check a proof later, offline, with core.verify(id, bytes) against the archived DKIM key.


Grounded, not just claimed

  • Verification is tested against real-world mail, not just fixtures — it reaches verified end to end on a genuine production DKIM-signed message over live DNS, a committed regression keeps it that way, and deprecated rsa-sha1 is refused (RFC 8301).
  • Validated against a real consumer's entire feature set — every capability of a mature, corner-case-heavy email-coordination app was rebuilt on the public surface. All of it fits; the heavy parts (document manifests, two-step close, proof export, forwarding) ride the existing hooks as thin policy, not kernel changes.
  • 317 tests, 2 runtime deps, a JSDoc-sourced TypeScript surface. Stable under SemVer — breaking changes only in a future major.

Docs

Start at docs/README.md: the PRD (what mailproof is, who adopts it, the NO-GO table), DESIGN (the extraction boundary + planned API), SPEC (wire formats), and the decisions log. For wiring an adopter, the Integration Guide is the single source.

License

Apache License, Version 2.0 — see LICENSE. © hamr0