Mailey

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 2026

Overview

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.

typescript
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.

ProviderRuleExample
gmail.com, googlemail.comDrop dots and +tags, unify the domainJ.Doe+shop@Gmail.com → jdoe@gmail.com
outlook, hotmail, live, msnDrop +tagsann+dev@outlook.com → ann@outlook.com
proton.me, protonmail.com, pm.meDrop +tagsx+a@proton.me → x@proton.me
yahoo, ymail, rocketmailDrop -tagsbo-news@yahoo.com → bo@yahoo.com
everything elseLowercase only — tags are preservedOps+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.

bash
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 for sign-in, claim or export.
  • 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

SurfaceLimit
Resolver (public site)60 lookups / minute / IP
Resolver (API key)120 requests / minute / key
Code issuance8 / 10 minutes / IP, 5 / 15 minutes / inbox
Transfers30 / minute / account
Key export6 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.