All posts
Guide·Jul 6, 2026·8 min read

End-to-end encrypted email: how it actually works

End-to-end encrypted email means only the two endpoints hold the keys. The three layers, how the encrypt-to-recipient envelope works, and how agents do it.

Dvir Atias

Dvir Atias

Founder

End-to-end encrypted email is email that is encrypted on the sender's device and can only be decrypted on the recipient's device, because the two endpoints are the only parties that ever hold the decryption keys. The mail provider in the middle stores and relays ciphertext it cannot read. It works with a pair of keys per participant: you encrypt to the recipient's published public key, and only their matching private key, which never leaves their machine, can open it. That is the entire promise, and it is a much stronger and much rarer property than the "encryption" most email services advertise.

The word "encrypted" gets stretched to cover three very different things, and the gap between them is where privacy is won or lost. This guide separates those layers, walks through the key exchange and the envelope, is honest about what leaks even when everything is done right, explains why true end-to-end is rare in ordinary email, and shows how to do it programmatically between agents with AgenticEmail.

What is end-to-end encrypted email?

End-to-end encryption (E2EE) means the content of a message is readable only at the two ends of the conversation. Everything in between, including the servers that route and store the message, sees ciphertext and nothing else. Crucially, the keys that decrypt the message exist only on the endpoints. If the provider cannot produce a plaintext copy even under subpoena, because it never had the key, the system is end-to-end encrypted. If it can, it is not, no matter what the marketing says.

This is a property of who holds the keys, not of whether encryption is "used." Almost all email today is encrypted in some sense. Very little of it is end-to-end encrypted.

The three layers people conflate

When a service says your email is "encrypted," it is usually talking about one of these three layers. They are not interchangeable.

LayerWhat it protectsWho can still read the plaintext
TLS in transitThe hop between two servers, on the wireEvery server that terminates the connection
Encryption at restBytes sitting on the provider's disksThe provider (it holds the keys)
True end-to-endThe content, everywhere except the endpointsOnly sender and recipient

TLS in transit (STARTTLS between mail servers, HTTPS to your webmail) encrypts each network hop. It is essential and nearly universal, but it protects the connection, not the message. At every server the message is decrypted, processed, and re-encrypted for the next hop. Anyone who controls one of those servers sees plaintext.

Encryption at rest means the provider encrypts stored mail on its disks. This defends against a stolen hard drive, not against the provider itself, its cloud host, or a legal order, because the provider holds the keys and decrypts on demand to show you your inbox.

True end-to-end is the only layer where the provider is structurally unable to read the content, because the keys live on the endpoints. This is the layer PGP, Signal, and a handful of privacy-focused mail systems implement, and it is the one this article is about. For the case that end-to-end should be the default rather than a bolt-on, see zero-knowledge email.

How the key exchange and the envelope work

End-to-end encryption runs on asymmetric (public-key) cryptography. Each participant generates a keypair: a public key they can hand out freely, and a private key they guard and never share. Anything encrypted to the public key can be decrypted only by the matching private key.

The flow has two moving parts, key exchange and the message envelope:

  1. Publish. Each side generates a keypair locally and publishes its public key to somewhere the other side can find it. The private key stays on the device.
  2. Resolve. Before sending, the sender fetches the recipient's published public key.
  3. Encrypt to the recipient. The sender builds an envelope using hybrid encryption: a fresh random symmetric key encrypts the actual message body with a fast cipher like AES-256-GCM, and that symmetric key is itself wrapped to the recipient's public key. Public-key crypto is slow and size-limited, so you use it only to seal the small symmetric key, not the whole message. For multiple recipients, the same content key is wrapped once per recipient.
  4. Decrypt at the endpoint. The recipient uses their private key to unwrap the symmetric key, then decrypts the body.

A well-built system also signs the payload before encrypting it, with a separate signing keypair, so the recipient can verify who actually sent the message and that it was not tampered with. Encryption gives you confidentiality, signatures give you authenticity, and you want both.

AgenticEmail implements exactly this with standards-based JOSE primitives, so the wire format is inspectable and interoperable rather than a bespoke scheme. The envelope is a multi-recipient JWE using ECDH-ES over NIST P-256 with AES-256-GCM, wrapping an Ed25519 JWS that signs the payload before encryption. The same format is produced and consumed by both the TypeScript and Python SDKs. If you are weighing this against the classic tool, PGP encryption and its modern alternatives covers the tradeoffs.

What it protects, and what still leaks

End-to-end encryption protects the content: the body, and, done properly, the subject line, and attachments. It does not, by itself, hide the metadata that email needs in order to route.

What still leaks even with perfect E2EE:

  • The envelope headers. The To and From addresses have to be readable so servers can deliver the message. E2EE hides what you said, not who you said it to.
  • Timing and size. When a message was sent, how big it was, and how often two parties talk are all observable.
  • The subject line, unless it is encrypted inside the body. This is the classic trap. In many E2EE email setups the subject travels as a normal, plaintext header outside the encrypted payload. If your subject is "Wire transfer confirmation for account 4471," you have leaked the point of the message. The only fix is to move the real subject inside the encrypted envelope and send a blank or generic outer subject. AgenticEmail encrypts the subject as part of the sealed payload for this reason.

Being clear-eyed about metadata is not a weakness of E2EE, it is the honest boundary of it. Anyone who tells you end-to-end encryption makes email fully anonymous is overselling it.

Why true end-to-end email is rare

If E2EE is so much stronger, why is almost no ordinary email end-to-end encrypted? Three structural reasons:

  • Key exchange is hard for humans. Both sides must have keypairs and must have published and verified each other's public keys before the first message. That coordination step is where consumer PGP died.
  • It breaks provider features. Server-side search, spam filtering, and previews all need to read the body. A provider that cannot read your mail cannot index it for you.
  • It only works when both ends participate. You cannot end-to-end encrypt to someone who has no key. Email to a normal Gmail or Outlook address will be plaintext at rest on their side no matter what you do, because the recipient has nothing to decrypt with. E2EE is inherently a both-sides property.

That last point is the one to internalize. End-to-end encryption is not something you can unilaterally apply to the whole email network. It is something two participants who both opted in can do with each other.

How to do it programmatically with AgenticEmail

AgenticEmail is API-first email infrastructure for AI agents, and its end-to-end encryption is built for the one setting where both-sides participation is realistic: agent to agent. It is opt-in and works only between two AgenticEmail inboxes that have each published a key. Plaintext is the default, and inbound mail from the outside world arrives as plaintext, because Gmail and the rest have no key to decrypt with. Read that boundary plainly: this is a developer feature for machine-to-machine mail, not a consumer product, and not a claim that all mail on the platform is encrypted.

It is also zero-knowledge. The private key is generated and kept client-side, in the SDK or CLI on your machine, and never reaches AgenticEmail's servers. The platform stores and relays only ciphertext and public keys, so neither AgenticEmail nor its cloud provider can read encrypted content. More on that model in encrypted email for AI agents.

The flow mirrors the theory above. First, each inbox generates an identity locally and publishes its public JWKS:

# Publish this inbox's public keys so others can encrypt to it.
# The private key was generated locally and never leaves your machine.
curl -X PUT https://api.agenticemail.dev/v1/inboxes/{id}/public-key \
  -H "Authorization: Bearer $AGENTICEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "keys": [ { "kty": "EC", "crv": "P-256", "use": "enc", "x": "...", "y": "..." },
                   { "kty": "OKP", "crv": "Ed25519", "use": "sig", "x": "..." } ] }'

Any agent can then fetch that inbox's keys at GET /v1/public-keys/{address} to encrypt to it. In the SDK you never touch the JWE by hand. You attach an identity and let the client resolve the recipient's key, encrypt, sign, and send:

import AgenticEmail, { generateIdentity } from "agenticemail";

// Generated and stored client-side; the private key stays here.
const identity = await generateIdentity("agent-a@inbox.agenticemail.dev");

const client = new AgenticEmail({
  apiKey: process.env.AGENTICEMAIL_API_KEY!,
  e2e: { identity, autoPublish: true, allowPlaintextFallback: false },
});

// If the recipient inbox has published a key, this send is encrypted
// end to end before it ever touches the API. If not, the send is refused.
await client.messages.send({
  inboxId: identity.address,
  to: "agent-b@inbox.agenticemail.dev",
  subject: "Contract terms",
  text: "Proposed settlement attached.",
});

On the wire, the API sees only { "encrypted": true, "envelope": "<JWE>" }. The subject and body live inside the sealed payload, so the server never sees them. On read, the SDK decrypts with the local private key and verifies the sender's signature. The CLI does the same with agenticemail keys generate and agenticemail keys publish. For a step-by-step walkthrough, see how to send encrypted email, and the full endpoint reference lives in the docs.

Frequently asked questions

Is Gmail end-to-end encrypted?

No. Gmail uses TLS in transit and encrypts messages at rest, but Google holds the keys and can read message content, which is what makes server-side search and spam filtering work. That is encryption, but not end-to-end encryption. True E2EE would require the keys to live only on the endpoints.

Can I send an end-to-end encrypted email to any address?

No, and this is the core constraint. End-to-end encryption needs the recipient to hold a private key that matches a public key you can encrypt to. A normal mailbox at Gmail or Outlook has no such key, so mail to it cannot be end-to-end encrypted. It works only when both sides have published keys, which is why AgenticEmail scopes it to agent-to-agent mail between two of its inboxes.

Does end-to-end encryption hide the subject line?

Only if the system encrypts the subject inside the body. Many setups leave the subject as a plaintext header for routing and display, which leaks the gist of the message. AgenticEmail seals the subject inside the encrypted payload so it is not exposed, but you should always assume the outer To, From, and timing are visible.

What encryption does AgenticEmail use?

A standards-based JOSE envelope: a multi-recipient JWE using ECDH-ES over NIST P-256 with AES-256-GCM for confidentiality, wrapping an Ed25519 JWS that signs the payload before encryption for authenticity. The format is wire-compatible across the TypeScript and Python SDKs. See the encrypted email API for the programmatic surface.

Talk to a real person