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. 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: Fetch the manifest
Bob’s wallet calls Gmail’s node to ask what it accepts:
GET https://drs.gmail.com/.well-known/directory.json{ "protocol": "directory-v1", "domain": "gmail.com", "accepts": [ { "value_type": "USDC", "transfer_type": "ethereum" }, { "value_type": "USDC", "transfer_type": "base" }, { "value_type": "ETH", "transfer_type": "ethereum" }, { "value_type": "USD", "transfer_type": "ach" } ]}Gmail accepts USDC on Ethereum, USDC on Base, ETH, and USD via ACH. Bob’s wallet matches this against what it can send. Bob has USDC on Ethereum — there’s a match.
Step 3: Resolve the address
Bob’s wallet requests routing instructions for Alice:
POST https://drs.gmail.com/resolveContent-Type: application/json
{ "address": "alice@gmail.com", "value_type": "USDC", "transfer_type": "ethereum" }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": "MEUCIQD..."}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 4: Verify the signature
Before sending anything, Bob’s wallet verifies the contract:
- Serialize the contract to canonical JSON (sorted keys, no whitespace).
- Verify the Ed25519 signature using Gmail’s public key from DNS.
- Check that
expires_athasn’t passed.
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. An exchange processing a batch of transactions can verify contracts from domains it never connected to.
Step 5: Send
Bob’s wallet sends 50 USDC to 0x7a25... on Ethereum. Transaction complete.
There is no step 6
The protocol ends at settlement. There is no callback. There is no confirmation endpoint. There is no receipt.
This is by design. DNS doesn’t get notified when you connect to the IP it gave you. Directory doesn’t get notified when you send to the destination it gave you.
Gmail already knows. The destination in the routing contract is an address Gmail controls — their own wallet, their custody provider, their deposit account. 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.
This is the point. The address is permanent. The routing is ephemeral. Gmail manages it. Alice controls her preferences. Bob never manages wallet addresses.
What Gmail does behind the scenes
Gmail is the operator. As an operator, Gmail can:
- Rotate destinations — generate a unique deposit address per request for privacy.
- Migrate chains — move all users from Ethereum to Base without anyone noticing.
- Support new currencies — add BTC support by updating the manifest and adding routes.
- Set policies — require KYC before returning routes, enforce transfer limits, block sanctioned addresses.
- Manage keys — rotate the Ed25519 signing key and update DNS accordingly.
None of this affects how senders interact with the protocol. The interface is always: resolve, verify, send.
Paying the domain itself
You don’t always need a local part. If Gmail marks its domain as payable, you can send money to gmail.com directly — that pays Google. alice@gmail.com pays Alice. Both work on the same node.
POST /resolve{ "address": "gmail.com" }The domain is the building. The local part is the suite number. 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.
The manifest advertises this with "payable": true. An admin field provides a contact email for the node operator.
{ "protocol": "directory-v1", "domain": "gmail.com", "payable": true, "admin": "directory-admin@google.com", "accepts": [...]}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.