Documentation
How Mailey works, in full
The derivation standard, the normalization rules, the API surface and the limits that apply to each of them.
updated September 2026Overview
Mailey turns an email address into an on-chain account. The account exists before anyone signs up: it is derived, not created. Three things follow from that.
- You can pay someone who has never heard of a wallet.
- The recipient claims the account later, by proving the inbox is theirs.
- The account is an ordinary EOA, so it works in every wallet on day one.
MDS-1 derivation standard
MDS-1 maps a canonical inbox to a secp256k1 key. It is deterministic, stateless, and published so that answers from the resolver can be checked.
canonical = normalize(email) // see "Normalization"
eid = sha256(canonical)
for (let i = 0; ; i++) {
const sk = hkdf("sha512", ROOT,
"mailey/mds-1", // salt
`acct:${canonical}:${i}`, // info
32);
if (0n < toBigInt(sk) && toBigInt(sk) < SECP256K1_N) {
return sk; // otherwise advance the counter
}
}
account = keccak256(pubkey(sk))[12:]
commitment = keccak256(`${eid}:${account.toLowerCase()}`)Properties
- Pure. No database read is needed to derive an address.
- Portable. The output is a plain EOA — no factory, no proxy, no chain binding.
- Stable. One inbox maps to exactly one account, forever. There is no rotation.
Normalization
Two spellings of the same mailbox must not produce two accounts. Normalization runs before derivation and is part of the standard.
| Provider | Rule | Example |
|---|---|---|
| gmail.com, googlemail.com | Drop dots and +tags, unify the domain | J.Doe+shop@Gmail.com → jdoe@gmail.com |
| outlook, hotmail, live, msn | Drop +tags | ann+dev@outlook.com → ann@outlook.com |
| proton.me, protonmail.com, pm.me | Drop +tags | x+a@proton.me → x@proton.me |
| yahoo, ymail, rocketmail | Drop -tags | bo-news@yahoo.com → bo@yahoo.com |
| everything else | Lowercase only — tags are preserved | Ops+ci@acme.com → ops+ci@acme.com |
Custom domains keep their tags because many teams route + addresses to different mailboxes. Folding them would merge accounts that different people control.
API
Authentication
Bearer keys, created in the developer console. Keys are shown once and stored hashed. Rate limit: 120 requests per minute per key.
GET https://mailey.app/api/v1/resolve?email=cfo@acme.com
Authorization: Bearer mk_live_…
200 OK
{
"ok": true,
"data": {
"address": "0x7c3f…9a12",
"canonical": "cfo@acme.com",
"eid": "8f14e45f…",
"commitment": "0x9ab3…",
"derivation": "mds-1",
"claimed": false,
"self_custody": false,
"chain": { "id": 4663, "name": "Robinhood Chain" }
}
}Session endpoints
POST /api/auth/start— issue a code forsign-in,claimorexport.POST /api/auth/verify— exchange a code for a session cookie.POST /api/send— transfer to an inbox or an address.POST /api/export— one-shot key release, requires a fresh export code.
Status and limits
| Surface | Limit |
|---|---|
| Resolver (public site) | 60 lookups / minute / IP |
| Resolver (API key) | 120 requests / minute / key |
| Code issuance | 8 / 10 minutes / IP, 5 / 15 minutes / inbox |
| Transfers | 30 / minute / account |
| Key export | 6 attempts / 15 minutes / account |
Changelog
September 2026
- MDS-1 resolver live on Robinhood Chain with published commitments.
- Key export with v3 keystore and one-way severing of hosted signing.
- Payment requests, contacts, audit log and scoped API keys.