Version 1.0 — Draft Specification
The Trust-First Email Protocol (TFEP) is a backward-compatible extension to the existing SMTP email infrastructure. It addresses the fundamental trust gaps of SMTP — sender identity spoofing, spam, phishing, and the lack of verifiable authorization for different categories of mail — without requiring the replacement of existing infrastructure.
TFEP operates as a dual-stack overlay: TFEP-capable gateways speak both TFEP and SMTP, translating between the two and preserving trust proofs across protocol boundaries.
- Cryptographically verifiable sender identity
- Protocol-level spam prevention through declared message intent + cryptographic permits
- Phishing prevention through undeniable sender DID verification
- Native end-to-end encryption (optional, graceful fallback)
- Full backward compatibility with SMTP; no flag-day migration
- Replacing SMTP for all traffic immediately
- Centralized identity registry or blockchain dependency
- Content filtering (TFEP prevents identity fraud, not content-based deception)
Every TFEP sender is identified by a DID (Decentralized Identifier) anchored to a domain:
did:web:example.com
The DID document is published at:
https://example.com/.well-known/did.json
The DID document MUST contain at minimum:
- One
Ed25519VerificationKey2020verification method (for message signing) - One
X25519KeyAgreementKey2020key agreement method (for encryption)
Domains publish TFEP capability via a DNS TXT record:
_tfep.example.com TXT "v=TFEP1; did=did:web:example.com; policy=bridge; pow=0; caps=v1,enc,pow"
| Field | Required | Description |
|---|---|---|
v |
Yes | Protocol version (TFEP1) |
did |
Yes | The domain's DID |
policy |
No | bridge (default) or strict |
pow |
No | Required proof-of-work difficulty (0 = disabled) |
caps |
No | Comma-separated feature tags: v1, enc, pow |
When rotating keys, the old key MUST be marked "revoked": true in the DID document OR removed. New keys SHOULD include a notBefore timestamp. Gateways MUST NOT verify signatures using revoked keys.
TFEP messages are transported as standard MIME multipart emails with additional parts.
Content-Type: multipart/mixed
├── text/plain Human-readable fallback (required)
├── application/tfep+json TFEP envelope (required)
└── application/tfep-proof Base64-encoded Ed25519 signature (required)
The X-TFEP-Proof header MUST also be set to the base64url-encoded signature for quick gateway validation without full MIME parsing.
{
"version": "1",
"message_id": "<uuid-v4-or-v7>",
"thread_id": "<uuid-v4-or-v7>",
"message_type": "<see §4>",
"sender_did": "did:web:sender.example",
"recipient_did": "did:web:recipient.example",
"recipients": [],
"timestamp": "2025-01-01T12:00:00Z",
"subject": "Hello",
"body_hash": "<hex SHA-256 of plaintext body>",
"permit_token": "<JWT or omitted>",
"pow_proof": "<hashcash string or omitted>",
"encrypted": false,
"encryption_ephemeral_key": "<base64url X25519 pubkey or omitted>",
"bounced_message_id": "<omitted unless type=bounce>",
"bounce_reason": "<omitted unless type=bounce>",
"bounce_code": 0,
"recipient_caps": ["v1", "enc"]
}The envelope is canonically serialized to JSON (with pow_proof zeroed out) and the Ed25519 signature is computed over its SHA-256 hash.
Senders MUST declare a message_type. Gateways enforce authorization rules based on this declaration.
| Type | Description | Authorization Required |
|---|---|---|
personal |
Human-to-human message | Permit OR verified contact |
transactional |
Business → customer (receipts, notifications) | Relationship token |
marketing |
Newsletter, promotional | Opt-in permit issued by recipient |
automated |
System alert, notification | Same as transactional |
receipt |
Delivery acknowledgment | None (sent by gateway) |
bounce |
NDR / permanent failure | None (sent by gateway) |
Marketing enforcement: A marketing message without a valid opt-in permit MUST be rejected with SMTP code 554 at the gateway level. This is a protocol-level rejection, not a spam filter decision.
Inbound messages are assigned a trust tier by the receiving gateway:
| Tier | Condition |
|---|---|
verified |
Valid TFEP DNS record + valid DID document + valid Ed25519 signature |
identified |
DKIM/SPF/DMARC pass but no TFEP |
unknown |
No verifiable authentication |
blocked |
Local or federated blocklist match |
Tier determines default inbox routing. Recipients may configure custom routing rules.
A send permit is a short-lived Ed25519-signed JWT issued by a recipient granting a specific sender inbox access.
{
"iss": "did:web:recipient.example",
"sub": "did:web:sender.example",
"aud": ["tfep:permit:v1"],
"iat": 1700000000,
"exp": 1731536000,
"iss_did": "did:web:recipient.example",
"grantee_did": "did:web:sender.example"
}Signed with the issuer's Ed25519 private key.
Senders may request a permit via the recipient's well-known endpoint:
POST https://recipient.example/.well-known/tfep/permit-request
Content-Type: application/json
{"sender_did": "did:web:sender.example", "message_type": "transactional"}
Response: 201 with {"permit_token": "..."} (auto-approved) or 202 with {"request_id": "..."} (pending review).
Recipients may withdraw a permit:
POST https://recipient.example/.well-known/tfep/unsubscribe
Content-Type: application/json
{"permit_token": "...", "sender_did": "did:web:newsletter.example"}
When both sender and recipient have published X25519 keys in their DID documents, TFEP messages SHOULD be encrypted.
- Sender generates an ephemeral X25519 keypair
- ECDH shared secret =
X25519(sender_ephemeral_private, recipient_X25519_public) - Body is encrypted with NaCl secretbox using the shared secret
envelope.encrypted = trueenvelope.encryption_ephemeral_key= base64url of the ephemeral public key- Encrypted body replaces plaintext body in the MIME structure
The text/plain fallback part MUST contain a human-readable notice that the message is encrypted.
For messages to multiple recipients:
- Generate a random 32-byte content key (AES-256)
- Encrypt body with content key
- For each recipient: ECDH-wrap the content key with their X25519 public key
- Each recipient's wrapped key is stored in
envelope.recipients[].wrapped_content_key
Recipient domains may require a computational proof-of-work from senders without a valid permit.
The PoW format is Hashcash-style over:
v=1;bits=<n>;resource=<senderDID>+<recipientDID>;ts=<unix>;nonce=<n>
Valid PoW: SHA-256(token) has at least n leading zero bits.
Senders with valid permits are exempt from PoW requirements.
Receiving gateways MUST enforce:
- Signature validation: Invalid or missing signature → SMTP
550reject - Display-name mismatch: If the RFC 5322
Fromdisplay name contains a known brand string that does not match the verifiedsender_diddomain → downgrade tounknowntier + attachX-TFEP-Spoof-Warning: display-name-mismatchheader - Transactional relationship check:
transactionalmessages without a relationship token → downgrade tounknowntier - Marketing permit enforcement:
marketingwithout valid permit → SMTP554reject - Replay prevention: Messages with
timestampolder thanmax_message_age(default 5 minutes) → SMTP550reject
When a TFEP sender delivers to an SMTP-only recipient, the sending gateway issues a reputation token (signed JWT) as a receipt. When the SMTP recipient later adopts TFEP, they may present historical tokens to bootstrap their trust score.
Tokens decay over time using an exponential decay function with a configurable half-life.
Gateways MAY query a community-maintained DNS reputation zone:
_tfep-rep.<senderDomain>.<resolver> TXT "score=0.8;reports=42"
score: float [0.0, 1.0]. Values < 0.3 indicate community-flagged bad actor.reports: integer report count.
Federated reputation is a secondary signal. Local trust decisions (permits, tiers) take precedence.
The _tfep DNS record includes a caps= field advertising supported features. Senders SHOULD check recipient caps before sending.
| Cap Tag | Meaning |
|---|---|
v1 |
TFEP version 1 supported |
enc |
X25519 encryption supported |
pow |
Proof-of-work supported |
If the sender uses a feature not in the recipient's caps, it SHOULD gracefully omit that feature.
TFEP gateways SHOULD expose an authenticated REST API for administrative access. See the implementation for the full OpenAPI-compatible endpoint list.
Authentication: Authorization: Bearer <api_key> header.
- Key compromise: Rotate keys immediately using
tfep-gateway rotate-key. The old key should be marked"revoked": truein the DID document. - DNS spoofing: Enable DNSSEC validation (
identity.require_dnssec: true) in high-security environments. TheADbit in DNS responses is checked. - Replay attacks: Gateways enforce a
max_message_agewindow (default 5 minutes) and aclock_skewtolerance (default 1 minute). - Rate limiting: Token bucket limits per IP (connections/minute) and per sender DID (messages/hour) are enforced.
- Key storage: Private keys SHOULD be stored passphrase-encrypted. The keystore uses AES-256-GCM with PBKDF2-SHA256 (100,000 iterations).
TFEP is designed for incremental adoption following the STARTTLS precedent:
| Phase | Description |
|---|---|
| 0: Opt-in | Early adopters install TFEP gateways; SMTP users receive normal email with embedded proof |
| 1: Hybrid | Major providers add TFEP support; DNS capability records proliferate |
| 2: Reputation | Cross-protocol reputation tokens become standard; pure-SMTP spam increasingly quarantined |
| 3: Default | New accounts default to TFEP; SMTP is a legacy compatibility mode |
The TFEP Domain Registry is an optional extension that provides a human-readable namespace for TFEP identities. Registry operators serve the .tpt top-level domain (or any configured TLD) as an authoritative DNS zone.
DIDs (did:web:example.com) are cryptographically verifiable but not human-memorable. The registry maps short names (alice) to DIDs, enabling email addresses like alice@alice.tpt that are both recognizable and cryptographically rooted.
- Format:
^[a-z0-9][a-z0-9-]{0,62}$— lowercase alphanumeric + hyphens, starting with a letter or digit. - Registration: One-time, no renewals. First-come, first-served.
- TLD: Configured per deployment; the reference TLD is
.tpt.
The DNS bridge runs alongside the gateway and serves synthetic DNS records for registered names:
| Query | Response |
|---|---|
TXT alice.tpt |
v=TFEP1; did=<did>; policy=bridge; caps=v1,enc |
TXT _tfep.alice.tpt |
Same as above (capability lookup format) |
A alice.tpt |
Configured gateway_ip (IPv4) |
AAAA alice.tpt |
Configured gateway_ipv6 (IPv6) |
SOA tpt. |
Zone SOA record |
NS tpt. |
Configured nameserver hostname |
| Unregistered name | NXDOMAIN + SOA in authority |
| Non-registry query | Forwarded to upstream resolver (default 1.1.1.1:53) |
The bridge also supports DNS-over-TLS (DoT) on a configurable port (default :853), using the gateway's TLS certificate.
Client Registry API DNS Bridge
| | |
|-- POST /register ---→ | |
| { name, did, | |
| owner_pubkey, |-- INSERT registry_domains
| fee_tx } | |
|←-- 201 { record } --- | |
| | |
|-- Deploy DID doc -------------------------→ (HTTPS at did:web endpoint)
| | |
|-- Query TXT alice.tpt --------------------→ |
|←-- v=TFEP1; did=... --------------------- |
Transfers are cryptographically verified. The current owner signs:
transfer:<name>:<new_did>:<new_owner_pubkey>:<unix_timestamp>
with their Ed25519 private key. The registry verifies the signature against the stored owner_pubkey before updating the record and appending a registry_transfers audit entry.
A name is marked dormant: true if no valid DID document is found at https://<name>.<tld>/.well-known/did.json after registry.dormant_days days (default 90). Dormant names remain registered and are not available for re-registration.
Owners may attach arbitrary JSON metadata to their name (bio, URL, avatar, etc.) by signing:
metadata:<name>:<sha256-hex-of-metadata-json>
Metadata is stored in the registry and returned in resolution responses. It is public and unverified by the protocol — treat it as self-asserted.
Gateways with the registry enabled serve human-readable HTML profile pages at /p/<name>, showing the name's DID, pubkey, registration date, metadata, and transfer history. These pages are suitable for linking in email footers or social profiles.
- Name squatting: The registry is first-come, first-served. Deployments MAY add fee validation or manual review to deter squatting.
- Key loss: There is no key recovery mechanism. Lost owner keys mean the name cannot be transferred. Recommend keeping key backups.
- DNS hijacking: The DNS bridge is not a replacement for DNSSEC. Clients SHOULD validate DNSSEC where available. Registry names are additionally protected by the DID document's cryptographic binding.
- Fee proof replay: Fee transaction proofs (
fee_tx) SHOULD be single-use. Implementations MUST track redeemed proofs to prevent double-registration.
This specification is a living document. Implementations should track the version field in the DNS TXT record.