dkim

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 4, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package dkim wraps github.com/emersion/go-msgauth/dkim for the per-domain signing path.

Responsibilities split:

  • GenerateKeypair generates a fresh RSA-2048 keypair and returns the three things the rest of the system needs: a DNS-friendly selector, the base64 public key for the user's DNS TXT value, and the PKCS#1-DER private key for BYTEA storage.

  • Sign takes a fully composed RFC 5322 message body, looks up the matching keypair by selector + domain, and returns the message with a DKIM-Signature header prepended. Callers that don't have a key (legacy domains, the seeded shared domain) skip this and the downstream SMTP relay falls back to the deployment-level signing it has always done.

  • DNSRecord renders the TXT record the user must publish to make their key resolvable. The shape is fixed by RFC 6376 §3.6.1; the selector convention "e2a{YYYYMM}" matches what we tell users in the Get-started UI.

The 2048-bit RSA choice mirrors what every major mailbox provider recommends for new selectors as of 2026. Ed25519 keys are smaller but not all receivers verify them yet — switch when adoption catches up.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DNSRecord

func DNSRecord(selector, domain, publicKeyDNS string) (string, string)

DNSRecord renders the TXT record the user must publish. Returns the hostname (left of the apex) and the record value.

Example for selector "e2a202605" + domain "mail.acme.com":

name  = "e2a202605._domainkey.mail.acme.com"
value = "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."

func ExtractPublicKeyFromTXT

func ExtractPublicKeyFromTXT(txt string) string

ExtractPublicKeyFromTXT pulls the "p=" payload out of a TXT record's raw value, trimming any whitespace mail systems sometimes inject when splitting the record across multiple strings. Returns "" if the payload is missing — callers treat that as "key not yet published".

func SelectorForNow

func SelectorForNow() string

SelectorForNow returns the selector used for new keypairs at the current wall-clock month. The "e2a" prefix scopes the selector to this product so users hosting both e2a and another mail provider under the same domain can keep selectors disjoint. The YYYYMM tail lets us rotate selectors monthly without colliding with existing records — the rotated row reuses the same column, but selector changes mean DNS lookups land on a new key.

func SelectorForTime

func SelectorForTime(t time.Time) string

SelectorForTime is the testable variant of SelectorForNow.

func Sign

func Sign(message []byte, domain, selector string, privateKeyDER []byte) ([]byte, error)

Sign prepends a DKIM-Signature header to the given RFC 5322 message body, signed with the supplied private key for "{selector}.{domain}".

We only sign the From, To, Subject, Date and Message-ID headers (plus any References / In-Reply-To that may be present). Signing every header is brittle — receivers reject messages whose intermediary MTAs rewrite or fold a covered header. The whitelist keeps DMARC alignment intact while tolerating typical Send-via-SES rewrites.

Types

type Keypair

type Keypair struct {
	Selector      string
	PublicKeyDNS  string
	PrivateKeyDER []byte
}

Keypair is the result of GenerateKeypair. PrivateKeyDER is suitable for direct BYTEA storage; PublicKeyDNS is the literal "p=" value for the TXT record.

func GenerateKeypair

func GenerateKeypair() (*Keypair, error)

GenerateKeypair mints a fresh RSA-2048 keypair scoped to the current month's selector. PrivateKeyDER is PKCS#1 DER (parseable with x509.ParsePKCS1PrivateKey); PublicKeyDNS is the base64 SPKI value with the PEM header/footer/newlines stripped so it can be pasted straight into a TXT record's "p=" field.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL