DKIMpy: DKIM, ARC, and TLSRPT email signing and verification

1.1.8 · active · verified Thu Apr 16

DKIMpy is a Python library for creating and verifying DKIM (DomainKeys Identified Mail), ARC (Authenticated Receive Chain), and TLSRPT (TLS Report) signatures on email messages. It provides a robust implementation for email authentication, relying on cryptographic operations and DNS lookups. The current version is 1.1.8, and it maintains a stable release cadence with updates addressing security and compatibility.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to sign an email using `dkimpy.dkim.DKIM` and how to initiate verification using `dkimpy.dkim.verify`. For actual signing, a private key (bytes) and a domain/selector (bytes) are required. Full verification relies on accurate DNS TXT records for the public key, which `dkimpy` will query automatically.

import os
from dkimpy.dkim import DKIM, verify, DKIMException

# In a real application, load your actual private key and use your domain/selector.
# Example key generation (using openssl):
#   openssl genrsa -out dkim.private 1024
#   openssl rsa -in dkim.private -pubout -out dkim.public
# Then load: `with open('dkim.private', 'rb') as f: private_key = f.read()`
private_key = os.environ.get('DKIM_PRIVATE_KEY', b"") # Should be bytes
domain = os.environ.get('DKIM_DOMAIN', 'example.com')
selector = os.environ.get('DKIM_SELECTOR', 's1')

# Sample email content (bytes) - DKIMpy works with byte strings
email_message_bytes = b"""From: sender@example.com\r\nTo: recipient@example.com\r\nSubject: Test DKIM Signature\r\n\r\nThis is the body of the email.\r\n"""

# --- 1. Sign an email ---
print("--- Signing an Email ---")
if not private_key:
    print("Warning: DKIM_PRIVATE_KEY environment variable not set. Signing will likely fail.")
    print("Please provide a valid private key for real signing.")

try:
    # Initialize the DKIM signer
    signer = DKIM(
        message=email_message_bytes,
        selector=selector.encode(), # Selector must be bytes
        domain=domain.encode(),     # Domain must be bytes
        privkey=private_key
    )
    
    # Sign the message
    signed_email_bytes = signer.sign()
    print("Email signed successfully. First 500 bytes of signed email:")
    print(signed_email_bytes[:500].decode(errors='ignore'))
    print("...")

except DKIMException as e:
    print(f"Error signing email: {e}")
except Exception as e:
    print(f"An unexpected error occurred during signing: {e}")


# --- 2. Verify a received email ---
# For actual verification, the signed email needs to be received, and
# dkimpy will perform DNS lookups for the public key (TXT record).
print("\n--- Verification Example (requires real signed email and DNS) ---")
received_signed_email_bytes = signed_email_bytes # Use the just-signed email for demonstration

try:
    # The `verify` function is a module-level function
    # It returns a list of (dkim_domain, dkim_selector, ...) tuples for each valid signature.
    result = verify(received_signed_email_bytes)
    
    if result:
        print(f"Verification successful. Found {len(result)} valid DKIM signatures.")
        # print(f"Result details: {result}") # Uncomment for verbose output
    else:
        print("Verification failed or no valid DKIM-Signature found.")

except DKIMException as e:
    print(f"Verification encountered an error: {e}")
except Exception as e:
    print(f"An unexpected error occurred during verification: {e}")

view raw JSON →