Protected mail proof preparation
Live acceptance is PENDING.
Read the Markdown source ↗Live acceptance is PENDING. No live DNS/send/receive operation has been run by the local assembly checks. The CLI plan and test fixtures are not delivery evidence.
Offline sample (no credentials, DNS, send or receive):
node modules/mail/doctor.mjs --domain mail.example.com --provider resend --plan --json
node modules/mail/doctor.mjs --domain mail.example.com --provider resend --planThe human output names MX, SPF, DKIM, DMARC and next actions. To print actual
record values, pass --config with the four DNS arrays copied from provider
setup. No provider-specific record values can be inferred from a sample domain.
The owner must supply a test sending domain, verified sender, Resend sending
key, configured receiving mailbox and readback credential; throwaway Cloudflare
resources/credentials where required, and the evidence-store token. SendGrid
verified sender/Inbound Parse details remain prerequisites for that separate
path. An existing Base live-proof Environment and SENDGRID_API_KEY alone are
not send-and-receive proof. Resend is the default sender for this proof.
Use a private throwaway Resend receiving mailbox on the owner-approved test domain. Enable its actual receiving MX and retain access to the received-email API. The receive key must read that mailbox's received email list and detail; a sending-only key is insufficient. This uses actual SMTP delivery into a provider receiving mailbox. It does not certify an application's signed inbound webhook integration, attachments, unsubscribe delivery or every sending adapter. No application/Worker deployment is involved in this runner; the protected Actions run is its execution identity.
Store nonsecret config in an approved file with this shape (replace the example addresses and fill every DNS group with records from actual setup before proof):
{
"domain": "mail.example.com",
"provider": "resend",
"dnsRecords": {"mx": [], "spf": [], "dkim": [], "dmarc": []},
"send": {"from": "doctor@mail.example.com", "to": "doctor@receive.example.com"},
"receive": {"provider": "resend"},
"timeoutMs": 60000,
"pollIntervalMs": 2000
}The example is a config shape, not a working fixture or evidence. Each DNS entry
is { "type": "TXT", "name": "full.record.name", "value": "exact setup value" };
MX adds integer priority. The API guide in ../src/doctor/README.md describes
record types and the resolver's precise coverage.
After explicit approval, the direct live CLI invocation is:
node modules/mail/doctor.mjs --live --config /path/to/approved-mail-config.json --jsonIt reads MAIL_DOCTOR_SEND_API_KEY and MAIL_DOCTOR_RECEIVE_API_KEY from the
process environment only; never put values on the command line or in JSON.
The supplied config never chooses a receiving URL or executable. CLI exits 0
for a valid offline plan, 0 for all six live items passing, 1 for incomplete live
checks, and 2 for configuration/runtime failure. An uncertain submission must be
reconciled before another run because each invocation sends a new probe.
The Base workflow integrator owns wiring into protected live-proof.yml.
This module installs no shared workflow; integrate the reviewed runner into the
qualified workflow line before any live run.
Required invocation contract:
The owner supplies and approves the test inputs. Configure secrets only in
live-proofwith its integration-line/release-tag branch policy. Do not make secrets available to task branches or untrusted PR code.The workflow checks out the intended exact 40-hex SHA, confirms its reachability from the permitted integration line or release tag, and reviews this code for secret exfiltration before merge. It exposes sending/readback secrets as the two
MAIL_DOCTOR_*_API_KEYvariables only to the proof step. Cloudflare send mode also needs nonsecretsend.accountIdin the config. No provider login on the Mac and no DNS writes are needed or authorized by this runner.Make the approved nonsecret config available as
$RUNNER_TEMP/mail-config.json. In a clean checkout at$GITHUB_SHA, execute exactly:Shellnode modules/mail/live-proof/run.mjs "$RUNNER_TEMP/mail-config.json" "$RUNNER_TEMP/mail-receipt.json"The entry verifies Actions metadata and clean tracked source against
GITHUB_SHA. It reserves a new mode-0600 receipt before remote effects and refuses an existing path before sending. An interrupted run leaves a pending starting receipt, never successful proof. The calling workflow enforces actual Environment protection and source reachability; environment variables alone do not establish either. Upload only the receipt using the protected evidence-store mechanism and scopedEVIDENCE_WRITE_TOKEN; never upload config, env, raw mail or logs with secrets. Destination:mail/live/<sha>/<run-id>-<attempt>/mail-receipt.json. The runner performs no GitHub/evidence-store API operations itself.Retain workflow run ID, attempt, UTC times, exact SHA and immutable store path. A fresh gate reads the receipt and actual protected run. Only a receipt with all six checks passing, independent
source:resend_received_email_apiand a real mailbox UUID satisfies this probe. A fixture receipt cannot satisfy it.
mail-live-proof-v1 receipt fields: state:pass|pending, sourceSha, command,
runUrl, runAttempt, startedAt, phase:starting|completed, and (after
completion) completedAt and structured doctor result.
The send and receive evidence share a random correlationId; receive includes
actual inboxMessageId, receipt timestamp and SHA-256 of body, recipient and
RFC Message-ID. Send includes a hash of its provider receipt ID (or null when
absent). Config errors produce no delivery receipt; incomplete checks produce a
pending receipt and exit 1. Send HTTP acceptance alone never sets receive pass.
Unit verification: node --test modules/mail/tests/doctor/*.test.mjs.
Workerd assembly and the live run remain the integrator/fresh gate's distinct
checks. No plan, secret-presence check, loopback receiver or injected provider
response substitutes for the protected live receipt.