NAME

Mail::Make::Headers - Mail Header Collection for Mail::Make

SYNOPSIS

use Mail::Make::Headers;

my $h = Mail::Make::Headers->new ||
    die( Mail::Make::Headers->error );

$h->set( 'MIME-Version', '1.0' );
$h->content_type( 'text/html; charset=utf-8' );
$h->content_transfer_encoding( 'quoted-printable' );
$h->content_id( 'part1.abc@example.com' );

print $h->as_string;

VERSION

v0.9.0

DESCRIPTION

An ordered collection of mail header fields for Mail::Make::Entity.

Provides typed accessors for the headers most relevant to MIME construction (Content-Type, Content-Disposition, Content-Transfer-Encoding, Content-ID), with strict validation on every assignment, plus a generic "set"/"get" interface for arbitrary headers.

Header injection is prevented: field names and values are validated for illegal characters on every "set" call.

Field names

Field names are treated case-insensitively, and _ may be used instead of - (for example Content_Type is treated as Content-Type). Names are canonicalised for storage (e.g. Message-ID, MIME-Version, Content-Type).

Values and security

Values are sanitised to prevent header injection:

  • CR and LF are replaced with spaces.

  • ASCII control characters are removed (except tab).

This keeps the header container safe even if values originate from external input.

Ordering

Email headers sometimes have meaningful ordering (e.g. Received: lines). For this reason, as_string_without_sort preserves insertion order and is recommended for general email usage.

as_string applies a conservative ordering suitable for display or certain use-cases, but may not be appropriate for all messages.

METHODS

new

my $h = Mail::Make::Headers->new;
my $h = Mail::Make::Headers->new( Field => Value, ... );

Construct a new headers object. Constructor pairs are passed through push_header.

as_string( [ $eol ] )

Returns all headers as a single string, each line terminated by $eol (default CRLF). Does not include the trailing blank line that separates headers from body.

as_string_without_sort

my $s = $h->as_string_without_sort;
my $s = $h->as_string_without_sort( $eol );

Return formatted header lines preserving insertion order. Recommended for general email usage.

clear

$h->clear;

Remove all header fields.

content_disposition( [ $value ] )

Convenience typed accessor for the Content-Disposition header. On retrieval returns a Mail::Make::Headers::ContentDisposition object, or undef if not set.

content_id( [ $value ] )

Sets or gets the Content-ID header. Angle brackets are normalised automatically. Validates for control characters.

content_transfer_encoding( [ $encoding ] )

Sets or gets the Content-Transfer-Encoding header. Validates that the value is one of 7bit, 8bit, binary, base64, or quoted-printable. Value is normalised to lowercase.

content_type( [ $value ] )

Convenience typed accessor for the Content-Type header. On retrieval returns a Mail::Make::Headers::ContentType object, or undef if not set.

get

my @values = $h->get( $field );
my $value  = $h->get( $field );

Alias for:

$h->header( $field );

In list context returns all values for the field. In scalar context returns the values joined with ", ".

has( $name )

Returns 1 if the named header is present, 0 otherwise.

$h->header( $field )
$h->header( $field => $value )
$h->header( $f1 => $v1, $f2 => $v2, ... )

Get or set header fields.

In list context, a multi-valued field is returned as a list of values.

In scalar context, values are returned joined with ", ".

When setting multiple fields, the old value(s) of the last field is returned (undef if the field did not exist).

The $value may be a string (or something that stringifies) or an arrayref of strings. Values are sanitised as described above.

header_field_names

my @names = $h->header_field_names;
my $names = $h->header_field_names;

Return the list of distinct field names (canonical spelling). In scalar context returns an arrayref.

length

my $count = $h->length;

Returns the total number of header field entries currently stored.

Each value is counted separately, so a multi-valued field (set via repeated calls to "push_header") contributes one to the count per value added.

Returns 0 when no headers have been set.

init_header

$h->init_header( $field => $value )

Set the header only if it is not already present.

new_field( $name [, $value ] )

Factory method: returns a new typed header object (Mail::Make::Headers::ContentType, Mail::Make::Headers::ContentDisposition, etc.) or a Mail::Make::Headers::Generic object for unknown field names.

print( $fh )

Writes all headers followed by a blank line to the given filehandle.

add( $field => $value )

$h->add( 'X-Custom' => 'hello' );
$h->add( $f1 => $v1, $f2 => $v2, ... );

Alias for "push_header". Adds value(s) for the specified field(s) without removing any pre-existing values.

message_id( [$value | %opts] )

# Read current Message-ID
my $mid = $h->message_id;

# Set an explicit value
$h->message_id( '<unique@example.com>' );

# Generate a new Message-ID automatically
$h->message_id( { generate => 1, domain => 'example.com' } );

# Remove the Message-ID header
$h->message_id( undef );

Accessor and generator for the Message-ID header field.

Called with no arguments, returns the current Message-ID value.

Called with a plain string, sets the Message-ID to that value after clearing any existing one. If { strict => 1 } is passed in the options hash, the value is validated against the RFC 2822 msg-id grammar.

Called with { generate => 1 }, a new unique Message-ID is generated using the supplied domain option (or the system hostname if none is given). The domain must be a valid FQDN containing at least one dot.

Called with undef, removes the Message-ID header.

Returns $self in setter mode, the Message-ID string in getter mode, and undef on error.

push_header

$h->push_header( $field => $value )
$h->push_header( $f1 => $v1, $f2 => $v2, ... )

Add new value(s) for the specified field(s). Previous values are retained.

$value may be a scalar or an arrayref.

remove( $field, ... )

$h->remove( 'X-Custom' );
$h->remove( 'Cc', 'Bcc' );

Alias for "remove_header".

remove_header( $field, ... )

$h->remove_header( $field, ... )

Remove the specified fields and return the removed values.

In list context, returns the values removed.

In scalar context, returns the last removed value or 0 if nothing was removed.

replace( $field => $value )

$h->replace( 'Subject' => 'New subject' );

Alias for "replace_header".

replace_header

$h->replace_header( $field => $value )
$h->replace_header( $f1 => $v1, $f2 => $v2, ... )

Replace the value(s) of one or more header fields.

All existing occurrences of the specified field are removed before the new value(s) are added.

If $value is undef, the field is removed.

The old value(s) of the last field processed are returned. In list context, all previous values are returned. In scalar context, values are returned joined with ", ".

This method is similar to header() in setter mode, but explicitly treats undef as a request to delete the field.

reset( [$flag] )

$h->reset(1);

Internal cache-invalidation method. When called with a true value, signals that the serialised header string cached internally is stale and must be regenerated on the next call to "as_string".

User code rarely needs to call this directly; it is invoked automatically by any method that modifies the header set ("add", "remove_header", "replace_header", "message_id", etc.).

scan

$h->scan( sub { my( $k, $v ) = @_; ... } );

Call the callback for each stored header field/value pair (one call per value).

set

$h->set( $field => $value );
$h->set( $f1 => $v1, $f2 => $v2, ... );

Alias for replace_header().

If $value is undef, the field is removed.

exists

if ( $h->exists( $field ) ) { ... }

Return true if at least one value is present for the given field.

Field names are case-insensitive and _ is treated as -.

set( $name, $value )

Sets (replaces or appends) the named header. $value may be a plain string or any object that stringifies.

Validates the field name (printable ASCII, no colon or whitespace) and the value (no bare CR/LF header injection).

AUTHOR

Jacques Deguest <jack@deguest.jp>

SEE ALSO

Mail::Make, Mail::Make::Entity, Mail::Make::Headers::Generic, Mail::Make::Headers::ContentType, Mail::Make::Headers::ContentDisposition

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.