DKIM (RFC 6376) adds a signature to a message. The signing domain publishes its public key in DNS, at <selector>._domainkey.<domain>. The signature covers the body and a list of headers, so it still checks out after the message is stored.
Verifying
for result <- MailAuth.DKIM.verify(raw) do
IO.puts("#{result.domain}: #{result.result} #{result.reason}")
endEach signature gets a MailAuth.DKIM.Result, in the order they appear. Up to :max_signatures (default 5) are checked; the rest are :none, reason :too_many_signatures.
What is checked:
- the tags:
v=1, anda,b,bh,d,h,spresent;h=includesFrom;i=isd=or a subdomain of it;x=is not in the past - the key: present, not revoked, of the type
a=names, at least:min_key_bits(default 1024) and at most 4096 bits - the algorithm:
rsa-sha256anded25519-sha256(RFC 8463).rsa-sha1is:permerrorunlessallow_sha1: true(RFC 8301) - the body hash, then the signature
A pass can carry warnings: :from_not_oversigned, :body_length_limit, :subject_not_signed, :to_not_signed.
A key with the t=y flag gives testing?: true. The domain says it is testing DKIM; the result is as computed, and you may choose not to trust it.
Signing
{:ok, signed} =
MailAuth.DKIM.sign(raw,
domain: "example.com",
selector: "s1",
private_key: File.read!("s1.pem")
)The defaults: relaxed/relaxed, the headers in MailAuth.DKIM.default_headers/0, with From, Subject, To and Date oversigned. Pass a list of option lists to sign with several keys at once.
MailAuth.DKIM.signature_header/2 returns the header alone.
Keys
%{private_key: pem, dns_record: txt, dns_name: name} =
MailAuth.DKIM.generate_key(:ed25519, domain: "example.com", selector: "s2")RSA keys are 2048 bits by default. Ed25519 keys are short, but some receivers don't check them yet, so sign with both when you use Ed25519.