keymail — email, but secure
keymail is end-to-end encrypted mail. Your subject and body are sealed in your browser before they ever leave it, so the server only ever stores ciphertext. If the server is compromised, an attacker gets nothing readable — not a subject, not a body, not a filename.
There are no passwords. You sign in with a passkey (Face ID, Touch ID, a security key), which also unwraps the encryption keys that live only on your devices.
Getting started
- Create your inbox. Pick a name — that's your
address,
you@keymail.dev— and create a passkey. Your encryption keys are generated right there in the browser. - Write someone. Hit Compose, type their address, write, and Send securely. keymail seals the message to the recipient's public key before sending.
- Read. Everything in your inbox is decrypted on your device as you open it. Search works too — it runs locally, because the server can't read your mail to search it for you.
A verified badge on a message means keymail checked the sender's signature: it really came from them, and it arrived sealed.
Conversations
Replies group into a single conversation. Open one and you see the whole thread — the first message and every reply, flat and in order, with older messages collapsed to a line you can click to expand. Reply sits right below the latest message.
Screening & spam
Someone who has never written to you does a small automatic check before their first message lands — a proof of work their computer solves in a moment. It's invisible to real senders and instant for anyone you've written to, but it makes bulk spam expensive. You can tune how strict this is in Settings → Screening; people you write to are always let straight through.
Writing mail
- Formatting. The composer is rich text — bold,
italic, headings, lists, quotes, code, links — and it's stored as
Markdown. Type Markdown (
##,-,>) or use the toolbar / ⌘B, ⌘I. - Attachments. The paperclip attaches images, video, or any file. Each is encrypted with its own key in your browser; the server stores only ciphertext and never sees a filename.
- Signature. Set one in Settings. It's kept on your device and shown as a distinct block, so it's always clear where your message ends.
- Undo send. After you send, there's a few-second window to pull it back before it goes.
Keyboard shortcuts
Press ? anywhere in keymail for the full list. The essentials:
Importing your Gmail
Import (also in the account menu) copies your old mail into keymail. Everything runs in your browser: each message is converted and sealed to your key on this device, then stored like any other keymail message — the server only ever receives ciphertext, and your Google sign-in never leaves the browser. Labels come along inside the sealed message; spam and chat histories are skipped; re-running an import is safe.
From Google Takeout — no setup: export at takeout.google.com (Mail, mbox format) and choose the file on the import page.
Straight from Gmail — click Connect Gmail and approve read-only access in the Google window; your Google sign-in and token stay in this browser. While keymail's Google app is in Google's "testing" tier, an account must be on its tester list to connect — ask us, or use Takeout, which needs nothing.
Self-hosting? Register your own OAuth client (Web application, your
origin, Gmail API enabled, consent screen in Testing) and either set
KEYMAIL_GOOGLE_CLIENT_ID on the server or paste the client
ID on the import page — it stays in your browser.
Apps & newsletters
Websites can offer Sign in with keymail. Allowing one tells it your keymail address and lets it write to you — into its own Apps or Newsletters tab, never your inbox. An app can never read your mail, see your keys, or send as you, and you can cut any of them off instantly in Settings → Connected apps. Prefer one single inbox? Settings → Where app mail goes folds the tabs away.
Building an app? The developer reference lives at /docs/api.
Custom domains & aliases
A mailbox can answer to more than one address. Bring your own domain and
you@yourdomain.com becomes an alias for your
keymail inbox — same keys, same inbox, one place to read. Or give a
different name its own separate mailbox on the same
domain. Aliases are transparent: mail sealed to either address opens in
the same inbox.
The address lives on your domain; the mail is handled at keymail.dev.
Your address reads you@yourdomain.com, but you keep signing in
at keymail.dev and your domain doesn't have to serve — or point at —
anything. It works just like an MX record does for ordinary
email: one small record delegates your mail, nothing else moves.
DNS: keymail-only (recommended)
One TXT record delegates your domain's keymail to the server
that handles it. That's the whole setup — no A record, no
certificate, nothing served on your domain, your website and existing
email untouched.
; "keymail for this domain is handled at keymail.dev"
_keymail.yourdomain.com. TXT "v=keymail1; host=keymail.dev"
Then keymail maps the address to your inbox — as an alias of an existing mailbox, or its own:
keymail alias add you@yourdomain.com <your-mailbox>
Other keymail servers looking up you@yourdomain.com follow the
delegation to keymail.dev, which returns your keys and preserves your
domain in the sealed address. Done — you send and receive as
you@yourdomain.com without leaving keymail.dev.
Prefer a branded host? Point
host=keymail.yourdomain.com and add
keymail.yourdomain.com CNAME keymail.dev — keymail fetches a
certificate for that subdomain automatically. Or hand keymail the whole
apex (yourdomain.com A <keymail IP>) if you want the app
served there too. The plain TXT above is the simplest.
DNS: keymail + the email bridge
Add this if you also want to receive ordinary email — messages from Gmail, Outlook, anyone — at your keymail address. keymail runs a border MX that turns real email into keymail's front door: an unknown sender is politely refused at the door with a link back to you, so nothing unsealed is accepted by default, and no mail is ever sent on your behalf.
On top of the keymail-only records above, add an MX:
; route ordinary inbound email to the keymail bridge
yourdomain.com. MX 10 keymail.dev.
This is a full mail takeover for the domain — remove any existing MX records first, and know that regular inbound email will now be handled by keymail's doorbell, not your old provider. A sender who verifies themselves through the doorbell reaches you fully end-to-end sealed; a first-party allowlist (receipts, alerts) is opt-in and clearly marked.
Prefer keymail-only until you've decided you want the world's email pointed here — the bridge is the bigger commitment, and it's a single record to add whenever you're ready.
Self-hosting
keymail is one static binary. Run it on a machine you control and your mail lives there, with the same rule as everywhere else: the server holds public keys and ciphertext, and your private keys stay in your browser. There are two ways to do it.
Your own domain
Point a DNS name at your box, open ports 80 and 443, and start keymail. It
fetches its own certificate from Let's Encrypt. You are
you@km.you.example, and every keymail server in the world can
write to you, because keymail looks up the host in the address and connects
to it. There is nothing to register with keymail.dev or anyone else.
KEYMAIL_HOST=km.you.example KEYMAIL_TLS=1 ./keymail serve -data /var/lib/keymail
./keymail inbox create you -data /var/lib/keymail -host km.you.example
The second command prints a claim link. Open it in a browser and your keys are minted there. That is the whole setup.
A standalone server does not yet have passkey sign-in, the encrypted key vault, or the bridge for ordinary email. Those run on keymail.dev today and are next to arrive for self-hosters.
Keep your @keymail.dev address
Your mailbox can move to your box and keep its address. keymail.dev remembers where it went and does one of two things: forwards everything to you, so nobody has to know, or tells senders where you are so they deliver to you directly. You keep signing in at keymail.dev either way; it passes your browser's requests through to your machine.
Start keymail on your box, telling it that its addresses are written on keymail.dev:
KEYMAIL_HOST=km.you.example KEYMAIL_HOME=keymail.dev KEYMAIL_TLS=1 ./keymail serve -data /var/lib/keymail
By default your server tells senders its own name so they can reach you
directly. Set KEYMAIL_ADVERTISE_ENDPOINT=0 to stay behind
keymail.dev instead, so your box's name never appears in an answer. Add
-bridge-key with a long random secret if you also want ordinary
email, from Gmail and the like, handed on to you.
Move the mailbox. Export it from keymail.dev, then import it on your box. The export is your mailbox exactly as the server held it: ciphertext and public keys, never anything readable.
# on keymail.dev, signed in: download https://keymail.dev/api/export as you.tar
# on your box:
./keymail inbox import you.tar -data /var/lib/keymail
Tell keymail.dev where the mailbox lives now. For the moment that is a request an operator runs for you; a button in Settings is coming. Either way, keymail.dev only accepts the change if your box already answers for your address with the same keys, so nobody can point your name at a server that does not hold your mailbox.
After the move, keymail.dev keeps one line about you: your address and the server it lives at. No ciphertext, no keys. A compromised keymail.dev could misroute your mail; it could not read it.
The full guide, including how to move back, is docs/selfhost.md
in the source repository.