NAME

Mail::DKIM2::Signer - Sign a message with a DKIM2-Signature header

SYNOPSIS

use Mail::DKIM2::Signer;

# A signature covers a Message-Instance, so a message that has none yet
# gets one first (an originating hop: m=1).
use Mail::DKIM2::MessageInstance;
use Mail::DKIM2::Common qw(fold_header);
unless ($message =~ /^Message-Instance:/mi) {
    my $mi = Mail::DKIM2::MessageInstance->calculate($message);
    $message = fold_header('Message-Instance: ' . $mi->as_string) . "\r\n" . $message;
}

my $signer = Mail::DKIM2::Signer->new(
    Domain   => 'example.com',
    Selector => 'sel1',
    KeyFile  => '/etc/dkim2/sel1.pem',
    MailFrom => '<sender@example.com>',
    RcptTo   => ['<recipient@example.net>'],
);

# One shot ...
$signer->load($message);
# ... or streaming, with CRLF line endings
$signer->PRINT($chunk) for @chunks;
$signer->CLOSE;

die $signer->result_detail unless $signer->result eq 'signed';
my $header = $signer->as_string;    # "DKIM2-Signature: i=1; ..." (folded)

# The same message to several envelope recipients: one pass, one cheap
# signature per recipient.
for my $rcpt (@rcpts) {
    my $header = $signer->sign_for_recipient($rcpt);
}

DESCRIPTION

Adds a DKIM2-Signature header for this hop. The message must already carry the Message-Instance header this hop wants to sign over (see Mail::DKIM2::MessageInstance; a message with none is a fail); the Signer reads the existing Message-Instance and DKIM2-Signature headers, chooses the next i=, builds the signing input of spec-06 section 8.5, and signs it. It does not alter the message: the caller prepends the header as_string returns.

Extends Mail::DKIM2::HeaderParser, which provides PRINT, CLOSE, load and the tie interface.

This module implements draft-ietf-dkim-dkim2-spec-06; see "STATUS" in Mail::DKIM2 for what that means for the wire format and the API, and "CONVENTIONS" in Mail::DKIM2 for the option, input and error conventions every module here follows.

CONSTRUCTOR

new(%options)

Required:

Domain

The signing domain, the d= tag.

Selector

The selector of the key, published at <Selector>._domainkey.<Domain>.

Key or KeyFile

The private key as a Crypt::PK::RSA or Crypt::PK::Ed25519 object, or the path of a PEM file holding one (loaded with "load_private_key" in Mail::DKIM2::Common).

Optional:

Algorithm

rsa-sha256 (the default) or ed25519-sha256.

MailFrom

The envelope sender of this hop, recorded in mf=. Bare addresses are bracketed; '<>' or undef records the null sender.

RcptTo

An arrayref of this hop's envelope recipients, recorded in rt=.

NextDomain

The d= of the hop that will sign next, recorded in nd= for an imaginary forwarding hop (spec-06 section 9.3). Excludes MailFrom and RcptTo.

Timestamp

The t= value; defaults to now. Fix it for reproducible test output.

Nonce

The n= value, at most 64 characters.

Flags

An arrayref of f= flags, such as donotmodify.

An option not listed here croaks.

METHODS

PRINT($bytes), CLOSE(), load($input)

Feed the message; see Mail::DKIM2::HeaderParser.

result()

Undef until CLOSE; then 'signed', or 'fail' when the message cannot be signed (no Message-Instance to sign over, a chain already at the length limit, or a repeated i= or m=). A failure is a result, not an exception: PRINT and CLOSE return normally.

details()

The reason for a 'fail' result, or undef.

result_detail()

result and details together, e.g. "fail (PERMERROR ...)".

as_string()

The complete DKIM2-Signature: ... header, folded for insertion, or the empty string if there is no signature. The folding is part of what was signed and must not be changed.

signature()

The Mail::DKIM2::Signature object, available after CLOSE.

sign_for_recipient($rcpt)

Re-signs for a different envelope recipient (one address or an arrayref of them) and returns the folded header. Spec-06 section 9.6 signs only the Message-Instance and DKIM2-Signature fields, so the body and header hashes in the Message-Instance are the same for every recipient and only rt= changes; an extra recipient costs one signature over a few hundred bytes, not another pass over the message. Feed the message once, then call this per recipient. Croaks on a signature carrying nd=, which excludes rt=.

AUTHOR

Bron Gondwana <brong@fastmailteam.com>

COPYRIGHT AND LICENSE

Copyright (c) 2025-2026 Fastmail Pty Ltd. This is free software; you can redistribute it and/or modify it under the same terms as Perl itself.