Zero Knowledge Email aka zkEmails
Honestly, this whole thing started accidentally.
I was setting up signup and notification emails for a personal project. Nothing fancy, just the usual “thank you for signing up” stuff. I quickly ChatGPT-ed (yes, I use this term now) for a list of providers that support a free email-sending tier. I picked Brevo because they allow 300 emails per day on the free plan.
While wiring this up, I ran into a surprisingly annoying problem. I logged into the Brevo dashboard and created an SMTP credential. The UI asked me to copy the apiKey during creation, clearly stating it won’t be shown again. Fair enough that’s obviously the password.
But then, what’s the username?
I confidently assumed apiName would work. Copied it, configured everything, and started testing.
As you might have already guessed —> “Authentication Failed.”
Back to the dashboard. I stared at the UI again, looking for anything that resembled a username.
Time for some trial and error now!!.
openssl s_client -connect {brevo_smtp_host}:{port} -crlf -quiet
EHLO <custom-domain>.com # domain authenticated with Brevo
AUTH LOGIN
{username}
{password}
QUIT
Eventually, I discovered that a gnarly string like
<identifier>@smtp-brevo.com labeled Login in the UI worked perfectly. Now that I’m writing this and looking back at the UI, I feel stupid.
I don’t know why it did not click immediately. Anyway, reconfigured everything and it worked like a charm. Phew. Work done. Went out for dinner.
An Array of Fleeting Ideas
While sitting in the cab, I was reading through some zero-knowledge articles and papers I had collected during a math course on elliptic curves. The first few lectures were pure “WTF is happening?” but then gradually things started to make sense.
Well let’s reserve the learnings of that for another post. However, in course of that an obvious question hit me.
Why don’t we have end-to-end encryption for email? I know some of you folks will point me to ProtonMail but bear with me :)
More specifically:
- Why doesn’t my Gmail have E2E encryption?
- Why should Gmail read everything?
- And why have we collectively accepted this for decades?
To make matters worse, Sergey is back, Gemini is being pushed hard, and let’s be real, that means even more of our emails will be read, indexed, and mined. “Knock Knock”, Privacy who?
So I decided to build something for myself.
Grabbing the toolkit for some under the hood fun
I came back home and started tinkering around SMTP and IMAP. I wrote small snippets of code to:
- manually send emails using SMTP
- list messages using IMAP
- inspect headers
- see how providers actually store and expose messages
After a few hours of talking loudly to myself, ChatGpting and debugging, I had a working prototype.
Introducing zkEmails (because why not?)
Table of Contents
- What is ZKE?
- Prerequisites
- Installation
- Gmail App Password Setup
- Getting Started
- How It Works
- Troubleshooting
What is ZKE?
ZKE (Zero Knowledge Emails) is a privacy-focused email client that adds end-to-end encryption to your existing Gmail account. Your messages are encrypted on your device before being sent, and only the intended recipient can decrypt them.
Key Features:
- Works with your existing Gmail account
- End-to-end encryption (only you and your recipient can read messages)
- Both GUI and command-line interfaces available
- Multi-profile support for multiple email accounts
- No servers involved - encryption happens locally
Prerequisites
Required
- Java 17 or higher - The installer will help you install this if needed
- Gmail account with 2-Factor Authentication enabled
- Gmail App Password (not your regular Gmail password)
Supported Platforms
- macOS (Intel and Apple Silicon)
- Linux (Ubuntu, Debian, Fedora, etc.)
- Windows (via WSL)
Installation
Quick Install (Recommended)
Open your terminal and run:
curl -fsSL https://raw.githubusercontent.com/unlimited91/zkemails/1.0.0.beta2/install.sh | bash
This will:
- Check for Java 17+ (and offer to install via SDKMAN if missing)
- Download the latest ZKE release
- Create the
zkecommand in your PATH
After installation, restart your terminal or run:
source ~/.zshrc # for zsh
source ~/.bashrc # for bash
Verify Installation
zke --help
You should see the help menu with available commands.
Manual Install
If you prefer to install manually:
- Download the installer script:
curl -fsSL https://raw.githubusercontent.com/unlimited91/zkemails/1.0.0.beta2/install.sh -o install.sh chmod +x install.sh - Run the installer:
./install.sh - Or install a specific version:
./install.sh -v 1.0.0.beta2
Gmail App Password Setup
Important: ZKE requires a Gmail App Password, not your regular Gmail password.
Step 1: Enable 2-Factor Authentication
- Go to Google Account Security
- Under “How you sign in to Google”, click 2-Step Verification
- Follow the prompts to enable 2FA if not already enabled
Step 2: Create an App Password
- Go to App Passwords
- If you don’t see this option, 2FA may not be enabled
- Click Select app and choose “Mail”
- Click Select device and choose “Other (Custom name)”
- Enter “ZKE” as the name
- Click Generate
- Copy the 16-character password (looks like:
xxxx xxxx xxxx xxxx) - Remove the spaces when using it in ZKE
Keep this password safe! You’ll need it to initialize ZKE.
Getting Started
Option 1: GUI Mode (Recommended for beginners)
Launch the graphical interface:
zke gui
The GUI provides:
- Inbox view with encrypted messages
- Compose new encrypted messages
- Manage contacts and invites
- Multi-profile support
Option 2: CLI Mode (For terminal lovers)
Initialize Your Profile
zke init --email your.email@gmail.com
You’ll be prompted for your Gmail App Password.
Invite a Contact
Before you can exchange encrypted messages, you need to exchange keys with your contact:
zke invite --to friend@gmail.com
This sends an invitation email. Once they accept, you can exchange encrypted messages.
Accept an Invite
When someone invites you:
# List pending invites
zke lsi
# Accept an invite
zke ack invi --invite-id <INVITE-UUID>
Sync Keys
After your contact accepts your invite, sync their public key:
zke sync-ack
Send Encrypted Messages
# Opens an editor to compose
zke sem --to friend@gmail.com
# Or specify subject
zke sem --to friend@gmail.com --subject "Secret plans"
Read Encrypted Messages
# List encrypted messages
zke rem
# Read a specific message
zke rem --message 42
# View entire conversation thread
zke rem --thread 42
# Reply to a message
zke rem --reply 42
How It Works
Key Exchange (TOFU - Trust On First Use)
- You send an invite - ZKE generates a unique key pair and sends your public key
- They accept - They generate their keys and send their public key back
- Keys are exchanged - Now you can encrypt messages for each other
Encryption
- Messages are encrypted using your contact’s public key
- Only they can decrypt it with their private key
- Your private key never leaves your device
Local Storage
All data is stored locally in ~/.zkemails/:
config.json- Email server configurationkeys.json- Your encryption keys (keep private!)contacts.json- Public keys of your contactsinbox/- Cached encrypted messagesoutbox/- Sent messages
Troubleshooting
“Java not found” error
The installer should offer to install Java via SDKMAN. If it fails:
# Install SDKMAN
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
# Install Java 17
sdk install java 17-tem
“Authentication failed” error
- Make sure you’re using a Gmail App Password, not your regular password
- Verify 2FA is enabled on your Google account
- Try generating a new App Password
“Connection refused” error
Check your internet connection and firewall settings. ZKE needs access to:
imap.gmail.com:993(reading emails)smtp.gmail.com:587(sending emails)
GUI doesn’t start
Make sure you have Java 17+ with JavaFX support:
java -version
If using SDKMAN, install a JDK with JavaFX:
sdk install java 17.0.9-zulu
Messages not decrypting
- Verify the sender is in your contacts:
zke lsc - Make sure you’ve completed the key exchange:
zke sync-ack
Need more help?
- Check logs in
~/.zkemails/logs/ - Run commands with
--verboseflag for more details - Open an issue at GitHub Issues
Command Reference
| Command | Description |
|---|---|
zke gui |
Launch graphical interface |
zke init |
Initialize with your email |
zke invite |
Send invite to start encrypted chat |
zke sem |
Send encrypted message |
zke rem |
Read encrypted messages |
zke lsi |
List pending invites |
zke ack invi |
Accept an invite |
zke sync-ack |
Sync keys from accepted invites |
zke lsc |
List contacts |
zke lsp |
List profiles |
zke pset |
Switch active profile |
Use zke <command> --help for detailed options.
Uninstall
To remove ZKE:
rm -rf ~/.zkemails
Remove the PATH entry from your ~/.zshrc or ~/.bashrc if desired.
Questions or feedback? Open an issue at https://github.com/unlimited91/zkemails/issues