NAME
Mail::Make::SMIME - S/MIME signing and encryption for Mail::Make (RFC 5751)
SYNOPSIS
use Mail::Make;
my $mail = Mail::Make->new;
$mail->from( 'jacques@example.com' );
$mail->to( 'recipient@example.com' );
$mail->subject( 'Signed message' );
$mail->plain( 'This message is signed.' );
# Sign only
my $signed = $mail->smime_sign(
Cert => '/path/to/my.cert.pem',
Key => '/path/to/my.key.pem',
) || die $mail->error;
$signed->smtpsend( Host => 'smtp.example.com' );
# Encrypt only
my $encrypted = $mail->smime_encrypt(
RecipientCert => '/path/to/recipient.cert.pem',
) || die $mail->error;
# Sign then encrypt
my $protected = $mail->smime_sign_encrypt(
Cert => '/path/to/my.cert.pem',
Key => '/path/to/my.key.pem',
RecipientCert => '/path/to/recipient.cert.pem',
) || die $mail->error;
# Using the Mail::Make::SMIME object directly
use Mail::Make::SMIME;
my $smime = Mail::Make::SMIME->new(
cert => '/path/to/my.cert.pem',
key => '/path/to/my.key.pem',
) || die Mail::Make::SMIME->error;
my $signed = $smime->sign( entity => $mail ) || die $smime->error;
VERSION
v0.1.2
DESCRIPTION
Mail::Make::SMIME provides S/MIME signing, encryption, and combined sign-then-encrypt operations for Mail::Make objects, following RFC 5751 (S/MIME Version 3.2).
It delegates cryptographic operations to Crypt::SMIME, which wraps the OpenSSL libcrypto library. All certificates and keys must be supplied in PEM format, either as strings or as file paths.
MEMORY USAGE AND LIMITATIONS
In-memory processing
All cryptographic operations performed by this module load the complete serialised message into memory before signing or encrypting it. This is a consequence of two factors:
- 1.
Crypt::SMIMEAPI -
Crypt::SMIME accepts and returns plain Perl strings. It does not expose a streaming or filehandle-based interface.
- 2. Protocol constraints
-
Signing requires computing a cryptographic hash (e.g. SHA-256) over the entire content to be signed. Although the hash algorithm itself is sequential and could theoretically operate on a stream, the resulting
multipart/signedstructure must carry the original content followed by the detached signature. The signature cannot be emitted until the complete content has been hashed, which means either buffering the whole message in memory or reading it twice (once to hash, once to emit) — the latter requiring a temporary file.Encryption uses a symmetric cipher (AES by default) operating on PKCS#7
EnvelopedData. The ASN.1 DER encoding ofEnvelopedDatadeclares the total length of the encrypted payload in the structure header, which must be known before the first byte is emitted. Streaming without a temporary file is therefore not possible with standard PKCS#7.
Practical impact
For typical email messages, such as plain text, HTML, and modest attachments, memory consumption is not a concern. Problems may arise with very large attachments (tens of megabytes or more).
Future work
A future v0.2.0 of Mail::Make::SMIME may optionally delegate to the openssl smime command-line tool via IPC::Run, using temporary files, to support large messages without holding them in memory. This mirrors the approach already used by Mail::Make::GPG.
If in-memory processing is a concern for your use case, consider using Mail::Make::GPG instead: OpenPGP uses partial body packets (RFC 4880 §4.2.2) which allow true streaming without knowing the total message size in advance.
CONSTRUCTOR
new( %opts )
my $smime = Mail::Make::SMIME->new(
cert => '/path/to/cert.pem',
key => '/path/to/key.pem',
key_password => 'secret', # or CODE ref
ca_cert => '/path/to/ca.pem',
);
All options are optional at construction time and can be overridden per method call.
METHODS
ca_cert( [$pem_or_path] )
Gets or sets the CA certificate used for signature verification.
cert( [$pem_or_path] )
Gets or sets the signer certificate.
encrypt( entity => $mail, RecipientCert => $cert [, %opts] )
Encrypts $mail for one or more recipients. Returns a new Mail::Make object whose entity is a application/pkcs7-mime; smime-type=enveloped-data message.
RecipientCert may be a PEM string, a file path, or an array reference of either, for multi-recipient encryption.
key( [$pem_or_path] )
Gets or sets the private key.
key_password( [$string_or_coderef] )
Gets or sets the private key passphrase.
sign( entity => $mail [, %opts] )
Signs $mail with a detached S/MIME signature and returns a new Mail::Make object whose entity is a multipart/signed message.
The signature is always detached (smime-type=signed-data with Content-Type: multipart/signed), which allows non-S/MIME-aware clients to read the message body.
Options (all override constructor defaults):
- Cert => $pem_string_or_path
-
Signer certificate in PEM format.
- Key => $pem_string_or_path
-
Private key in PEM format.
- KeyPassword => $string_or_coderef
-
Passphrase for an encrypted private key, or a CODE ref that returns one.
- CACert => $pem_string_or_path
-
CA certificate(s) to include in the signature for chain verification.
sign_encrypt( entity => $mail, RecipientCert => $cert [, %opts] )
Signs $mail then encrypts the signed result. Accepts all options of both "sign" and "encrypt".
DEPENDENCIES
Crypt::SMIME (XS module wrapping OpenSSL libcrypto).
SEE ALSO
Mail::Make, Mail::Make::GPG, Crypt::SMIME
RFC 5751 - Secure/Multipurpose Internet Mail Extensions (S/MIME) Version 3.2
RFC 4880 - OpenPGP Message Format (partial body length packets, §4.2.2)
RFC 5652 - Cryptographic Message Syntax (CMS / PKCS#7 EnvelopedData)
AUTHOR
Jacques Deguest <jack@deguest.jp>
COPYRIGHT & LICENSE
Copyright(c) 2026 DEGUEST Pte. Ltd.
All rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.