How It Works
This walks through a complete transaction. Bob wants to send $50 in USDC to Alice. He has Alice’s address: alice@gmail.com.
The address is an email address
alice@gmail.com is both Alice’s email and her Directory address. The domain — gmail.com — is the routing authority. It decides where Alice’s money goes, the same way it decides where her email goes.
Alice configured her preferences through Gmail. She told Gmail: “When someone sends me crypto, route it to my Ethereum wallet.” She can change this at any time — switch to Base, switch to Solana, add ACH for fiat — and no sender ever needs to know.
Step 1: DNS discovery
Bob’s wallet looks up gmail.com in DNS, the same way an email client looks up mail servers:
_drs._tcp.gmail.com SRV 10 5 443 drs.gmail.com_drskey.gmail.com TXT "v=drs1; k=ed25519; p=BASE64PUBLICKEY"The SRV record says: “Gmail’s Directory node is at drs.gmail.com on port 443.”
The TXT record publishes Gmail’s Ed25519 public key. Operators MAY publish multiple _drskey TXT records during key rotation; clients MUST try each one until verification succeeds. Bob’s wallet will use this later to verify that routing instructions actually came from Gmail.
This is the trust anchor. Gmail controls these DNS records the same way it controls its MX records for email. Nobody else can change them.
Step 2: Resolve the address
Bob’s wallet requests routing instructions for Alice:
POST https://drs.gmail.com/resolveContent-Type: application/json
{ "address": "alice@gmail.com" }Gmail looks up Alice’s current preferences and returns a signed routing contract:
{ "address": "alice@gmail.com", "routes": [ { "value_type": "USDC", "transfer_type": "ethereum", "destination": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", "ttl_seconds": 300 } ], "issued_at": "2026-03-08T12:00:00Z", "expires_at": "2026-03-08T12:05:00Z", "signature": "wBsgQ8a0J2e5o1lZdKjR9p+hN3m7TXuk...base64-ed25519"}This is the routing contract. It says: “Send USDC to 0x7a25... on Ethereum. This instruction is valid for 5 minutes.”
The destination could be anything. Alice’s permanent wallet. A temporary deposit address Gmail generated just for this transaction. A smart contract. Alice doesn’t care — Gmail handles it according to her preferences.
Step 3: Verify the signature
Before sending anything, Bob’s wallet verifies the contract:
- Canonicalize the contract’s signable fields to JSON (RFC 8785 JCS).
- Verify the Ed25519 signature using one of Gmail’s public keys from DNS.
- Check that
issued_at/expires_atare within clock-skew tolerance.
If the signature is invalid or the contract is expired, the wallet rejects it. This is why the public key lives in DNS — it lets anyone verify without calling Gmail again. Third parties can verify contracts they never connected to.
Step 4: Send
Bob’s wallet sends 50 USDC to 0x7a25... on Ethereum. Transaction complete.
There is no step 5
The protocol ends at settlement. There is no callback, no confirmation endpoint, no receipt.
Gmail already knows. The destination in the routing contract is an address Gmail controls. Gmail monitors it the same way they monitor any other address: on-chain events, banking webhooks, custody APIs. The notification mechanism is native to the transfer layer, not the routing layer.
From the sender’s perspective, routing contracts are fire-and-forget. Resolve, verify, send, done. If the sender doesn’t act on the contract, it expires and a new one must be requested. No stale state accumulates on either side.
What happens next time
If Bob sends money to Alice again tomorrow, the flow repeats. Gmail might return a different destination — Alice switched to Base, or Gmail rotated her deposit address, or Alice changed her mind entirely and now wants fiat via ACH. Bob’s wallet doesn’t cache the old contract. Every resolution is fresh.
The address is permanent. The routing is ephemeral. Gmail manages it. Alice controls her preferences. Bob never manages wallet addresses.
The optional manifest
An operator MAY publish a capability manifest at /.well-known/directory.json as a hint about what pairs it accepts:
{ "protocol": "directory-v1", "domain": "gmail.com", "accepts": [ { "value_type": "USDC", "transfer_type": "ethereum" }, { "value_type": "USDC", "transfer_type": "base" }, { "value_type": "USD", "transfer_type": "ach" } ]}Clients MUST NOT require the manifest. A node that only exposes POST /resolve and DNS records is a conforming DRS node.
Paying the domain itself
You don’t always need a local part. You can send money to gmail.com directly — if the operator publishes a route for the domain, it pays Google. alice@gmail.com pays Alice. Both work on the same node.
POST /resolveContent-Type: application/json
{ "address": "gmail.com" }The domain is the building. The local part is the suite. If you send to the building, the operator decides where it goes — their treasury, their corporate account, whatever they configure as the domain’s default route.
For any domain, not just Gmail
Gmail is an example. Any domain can do this:
- Your bank runs a node so customers can receive money at
you@chase.com— or paychase.comdirectly. - Your employer runs a node so payroll goes to
you@company.com. - An exchange runs a node so traders receive at
you@exchange.com. - Your personal domain runs a node so
me@mydomain.comroutes to your wallet — ormydomain.comroutes to your default address.
The only requirement is DNS control. If you own the domain, you can run the node.