Mail between people on Vulpine, addressed like email: rodsirloin@fwetch.fox. It is sealed so only the person it is for can read it, signed so the sender is who they say, and held in a message box until it is read. The same address takes payments. Any domain can have its own mail: the whole standard is two small files a host serves, and the BSV message-box protocol does the delivering.
New here? The developers' page shows how Vulpine signs things.
local@domain
rodsirloin), a user number (72), or an address..fox name (fwetch.fox) or an ordinary web domain.Once fwetch.fox points at fwetch.lol, every Vulpine identity has handle@fwetch.fox and number@fwetch.fox with nothing to set up.
1. Find the domain's mail host. A .fox name points at a web address (its target); for an ordinary domain, the host is the domain itself. Ask it for /.well-known/foxmail:
{
"foxmail": 1,
"lookup": "https://fwetch.lol/api/mail/lookup/{local}",
"messageBox": "https://message-box-us-1.bsvb.tech",
"mailBox": "foxmail",
"payments": "peerpay"
}
2. Look up the person. Ask the lookup with {local} filled in:
curl https://fwetch.lol/api/mail/lookup/rodsirloin
{ "local": "rodsirloin", "identityKey": "02…", "address": "12XGh…", "name": "Rodsirloin",
"number": 1, "messageBox": "https://message-box-us-1.bsvb.tech", "mailBox": "foxmail", "payments": "peerpay" }
A name nobody holds answers 404. A person who has never signed anything answers 409: there is no key to seal mail to yet.
3. Deliver it. Send the message to that identityKey's mailBox on the messageBox host, over the BSV message-box protocol, which authenticates both sides (BRC-103) and seals the message (BRC-78). With the official client:
import { MessageBoxClient } from '@bsv/message-box-client'
const mb = new MessageBoxClient({ walletClient: wallet, host: who.messageBox })
await mb.sendMessage({ recipient: who.identityKey, messageBox: who.mailBox, body: JSON.stringify(mail) })
{
"p": "foxmail",
"from": "rachel@fwetch.fox",
"to": ["rodsirloin@fwetch.fox"],
"cc": [],
"subject": "The deeds",
"text": "…",
"attachments": [{ "name": "map.png", "ord": "<txid>_0" }],
"inReplyTo": null,
"t": 1790000000,
"pub": "02…",
"sig": "30…"
}
It is signed the way every Vulpine record is. The reader of it checks sig against pub, and that pub is the key from looks up to. Attachments are referenced, as an ordinal, a b:// file or a Library item, not packed into the message.
The wallet lists its foxmail box, checks each signature, keeps each message on the device (inbox, sent, archive), and acknowledges it so the host lets it go. Nothing goes on the chain unless someone chooses to anchor a receipt.
A message may carry a payment (the message-box protocol allows one). A wallet can ask anyone who is not a fren to attach postage, say 100 satoshis, and take mail from frens free. Spam costs money; friends cost nothing.
"payments": "peerpay" means money sent to rodsirloin@fwetch.fox goes by PeerPay (BRC-29) to the same identity key, and waits in its payment inbox to be accepted.
Serve /.well-known/foxmail, and a lookup that answers who each of your names is. You do not need to run a message box: point messageBox at any host that speaks the protocol, the BSV Association's included. Every Vulpine reader already does both for its own domains.
Status, 28 September 2026: the lookup and discovery are in the reader. The wallet's Mail app, postage and PeerPay to the same address come next.