Privacy Tools Guide

Generate a GPG key pair with gpg --gen-key, export your public key with gpg --armor --export [email], and share it with contacts. To sign an email, use gpg --clearsign email.txt which generates a signed version others can verify with gpg --verify email.txt.asc. Recipients obtain your public key, verify it against your key fingerprint (check over a trusted channel), and then verify your signatures automatically. This proves the message came from you and wasn’t altered in transit.

Understanding GPG Email Signatures

When someone signs an email with GPG, they attach a cryptographic signature generated using their private key. The recipient can then verify this signature using the sender’s public key. If verification succeeds, you know:

  1. The message was created by someone with access to the sender’s private key
  2. The message has not been altered since it was signed
  3. The sender controls the email address associated with that GPG key

GPG supports two types of signatures: clear-signed and detached. Clear-signed messages display the original text with the signature attached inline, while detached signatures are stored in separate files. Most email clients use clear-signed format for automatic verification.

Setting Up Your GPG Environment

Before working with signed emails, ensure you have GPG installed. On macOS, install via Homebrew:

brew install gnupg

On Linux, use your package manager:

sudo apt-get install gnupg  # Debian/Ubuntu
sudo dnf install gnupg      # Fedora

Generate a new GPG key if you don’t have one:

gpg --full-generate-key

Select RSA (2048 or 4096 bits), set an expiration date, and enter your name and email. Choose a strong passphrase to protect your private key.

Configuring Your Email Client for Signed Emails

Most terminal-based email clients support GPG signing. Here’s how to configure a few popular options.

Mutt Configuration

Add these lines to your ~/.muttrc:

set pgp_sign_as = "0xYOURKEYID"
set crypt_use_gpgme = yes

Replace 0xYOURKEYID with your actual key ID (found via gpg --list-keys).

Neomutt Configuration

Neomutt uses similar settings. Add to your ~/.neomuttrc:

set pgp_sign_as = "0xYOURKEYID"
set crypt_verify_sig = yes

Emacs with Mu4e

For Emacs users, add to your configuration:

(setq mml-secure-gpg-signers '("your-email@example.com"))
(setq mm-verify-option 'known)
(setq mm-decrypt-option 'known)

Signing an Email Manually

For testing or scripting purposes, you can sign emails directly from the command line. Create a simple message and sign it:

echo "Hello, this is a test message." | gpg --clearsign

The output resembles:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hello, this is a test message.
-----BEGIN PGP SIGNATURE-----
iQEzBEBCAAoFiEEexample1234567890FAKEexample=
=A1B2
-----END PGP SIGNATURE-----

To sign a complete email file:

gpg --clearsign --armor --local-user 0xYOURKEYID --output signed-email.txt original-email.txt

Verifying GPG Signatures in Emails

When you receive a signed email, verify the signature using GPG. First, ensure you have the sender’s public key imported:

gpg --import sender-public-key.asc

Or fetch from a keyserver:

gpg --keyserver keyserver.ubuntu.com --search-keys sender@example.com
gpg --recv-keys SENDER_KEY_ID

Verify a clear-signed message:

gpg --verify signed-email.txt

A successful verification shows output like:

gpg: Signature made Mon 16 Mar 2026 10:30:00 UTC
gpg:                using RSA key ABC123DEF456
gpg: Good signature from "Sender Name <sender@example.com>"

The “Good signature” message confirms the message is authentic and untampered.

Handling Signature Verification Failures

When verification fails, GPG provides diagnostic information. Common failure scenarios include:

Missing public key:

gpg: Can't check signature: No public key

Solution: Import the sender’s public key first.

Tampered message:

gpg: BAD signature from "Sender Name <sender@example.com>"

Solution: The message was modified after signing. Do not trust its contents.

Expired key:

gpg: Warning: This key has expired!

Solution: Request an updated key from the sender or verify through an alternative channel.

Automating Email Verification in Scripts

For developers building automated systems, integrate GPG verification into your workflow. Here’s a Python example using the gpg library:

import gpg

def verify_email_signature(signed_message_path, expected_signer_email=None):
    with open(signed_message_path, 'rb') as f:
        with gpg.Context() as ctx:
            try:
                result = ctx.verify(f)
                if result.signatures:
                    sig = result.signatures[0]
                    key = ctx.get_key(sig.fpr)
                    uid = key.uids[0]

                    if expected_signer_email and expected_signer_email not in uid.uid:
                        return False, f"Unexpected signer: {uid.uid}"

                    return True, f"Valid signature from {uid.uid}"
            except gpg.errors.GPGError as e:
                return False, f"Verification failed: {e}"

    return False, "No signature found"

Store this function in your verification pipeline to automatically validate incoming emails.

Best Practices for Production Use

When implementing GPG-signed emails in production environments, follow these recommendations:

  1. Key management: Use hardware security modules (HSMs) for sensitive private keys, especially for automated signing systems.

  2. Key expiration: Set reasonable expiration dates (1-2 years) on signing keys and establish a key rotation policy.

  3. Web of trust: For high-security contexts, verify keys through multiple channels before trusting them for critical communications.

  4. Keyserver reliability: Use multiple keyserver sources and implement fallback logic in your verification scripts.

  5. Timestamp verification: Be aware that GPG signatures don’t include timestamps. For time-sensitive communications, add application-level timestamps.

Troubleshooting Common Issues

If verification still fails after following these steps, check these common causes:

Built by theluckystrike — More at zovo.one