.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Email::MIME::CreateHTML 3pm" .TH Email::MIME::CreateHTML 3pm "2022-12-06" "perl v5.36.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Email::MIME::CreateHTML \- Multipart HTML Email builder .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 10 \& use Email::MIME::CreateHTML; \& my $email = Email::MIME\->create_html( \& header => [ \& From => \*(Aqmy@address\*(Aq, \& To => \*(Aqyour@address\*(Aq, \& Subject => \*(AqHere is the information you requested\*(Aq, \& ], \& body => $html, \& text_body => $plain_text \& ); \& \& use Email::Send; \& my $sender = Email::Send\->new({mailer => \*(AqSMTP\*(Aq}); \& $sender\->mailer_args([Host => \*(Aqsmtp.example.com\*(Aq]); \& $sender\->send($email); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" This module allows you to build \s-1HTML\s0 emails, optionally with a text-only alternative and embedded media objects. For example, an \s-1HTML\s0 email with an alternative version in plain text and with all the required images contained in the mail. .PP The \s-1HTML\s0 content is parsed looking for embeddable media objects. A resource loading routine is used to fetch content from those URIs and replace the URIs in the \s-1HTML\s0 with CIDs. The default resource loading routine is deliberately conservative, only allowing resources to be fetched from the local filesystem. It's possible and relatively straightforward to plug in a custom resource loading routine that can resolve URIs using a broader range of protocols. An example of one using \s-1LWP\s0 is given later in the \*(L"\s-1COOKBOOK\*(R"\s0. .PP The \s-1MIME\s0 structure is then assembled, embedding the content of the resources where appropriate. Note that this module does not send any mail, it merely does the work of building the appropriate \s-1MIME\s0 message. The message can be sent with Email::Send or any other mailer that can be fed a string representation of an email message. .SS "Mail Construction" .IX Subsection "Mail Construction" The mail construction is compliant with rfc2557. .PP \&\s-1HTML,\s0 no embedded objects (images, flash, etc), no text alternative .PP .Vb 1 \& text/html .Ve .PP \&\s-1HTML,\s0 no embedded objects, with text alternative .PP .Vb 3 \& multipart/alternative \& text/plain \& text/html .Ve .PP \&\s-1HTML\s0 with embedded objects, no text alternative .PP .Vb 5 \& multipart/related \& text/html \& embedded object one \& embedded object two \& ... .Ve .PP \&\s-1HTML\s0 with embedded objects, with text alternative .PP .Vb 7 \& multipart/alternative \& text/plain \& multipart/related \& text/html \& embedded object one \& embedded object two \& ... .Ve .SH "METHODS" .IX Header "METHODS" There is only one method, which is installed into the Email::MIME package: .IP "Email::MIME\->create_html(%parameters)" 4 .IX Item "Email::MIME->create_html(%parameters)" This method creates an Email::MIME object from a set of named parameters. Of these the \f(CW\*(C`header\*(C'\fR and \f(CW\*(C`body\*(C'\fR parameters are mandatory and all others are optional. See the \*(L"\s-1PARAMETERS\*(R"\s0 section for more information. .SS "LOW-LEVEL \s-1API\s0" .IX Subsection "LOW-LEVEL API" Email::MIME::CreateHTML also defines a lower-level interface of 3 building-block routines that you can use for finer-grain construction of \s-1HTML\s0 mails. These may be optionally imported: .PP .Vb 1 \& use Email::MIME::CreateHTML qw(embed_objects parts_for_objects build_html_mail); .Ve .ie n .IP "($modified_html, $cid_mapping) = embed_objects($html, \e%options)" 4 .el .IP "($modified_html, \f(CW$cid_mapping\fR) = embed_objects($html, \e%options)" 4 .IX Item "($modified_html, $cid_mapping) = embed_objects($html, %options)" This parses the \s-1HTML\s0 and replaces URIs in the embed list with a \s-1CID.\s0 The modified \s-1HTML\s0 and \s-1CID\s0 to \s-1URI\s0 mapping is returned. Relevant parameters are: .Sp .Vb 5 \& embed \& inline_css \& base \& object_cache \& resolver .Ve .Sp The meanings and defaults of these parameters are explained below. .ie n .IP "@mime_parts = parts_for_objects($cid_mapping, \e%options)" 4 .el .IP "\f(CW@mime_parts\fR = parts_for_objects($cid_mapping, \e%options)" 4 .IX Item "@mime_parts = parts_for_objects($cid_mapping, %options)" This creates a list of Email::MIME parts for each of the objects in the supplied \s-1CID\s0 mapping. Relevant options are: .Sp .Vb 3 \& base \& object_cache \& resolver .Ve .Sp The meanings and defaults of these parameters are explained below. .ie n .IP "$email = build_html_email(\e@headers, $html, \e%body_attributes, \e@html_mime_parts, $plain_text_mime)" 4 .el .IP "\f(CW$email\fR = build_html_email(\e@headers, \f(CW$html\fR, \e%body_attributes, \e@html_mime_parts, \f(CW$plain_text_mime\fR)" 4 .IX Item "$email = build_html_email(@headers, $html, %body_attributes, @html_mime_parts, $plain_text_mime)" The assembles a ready-to-send Email::MIME object (that can be sent with Email::Send). .SH "PARAMETERS" .IX Header "PARAMETERS" .IP "header => \fIlist\fR" 4 .IX Item "header => list" A list reference containing a set of headers to be created. If no Date header is specified, one will be provided for you based on the \&\fBgmtime()\fR of the local machine. .IP "body => \fIscalar\fR" 4 .IX Item "body => scalar" A scalar value holding the \s-1HTML\s0 message body. .IP "body_attributes => \fIhash reference\fR" 4 .IX Item "body_attributes => hash reference" This is passed as the attributes parameter to the \f(CW\*(C`create\*(C'\fR method (supplied by \f(CW\*(C`Email::MIME::Creator\*(C'\fR) that creates the html part of the mail. The body content-type will be set to \f(CW\*(C`text/html\*(C'\fR unless it is overidden here. .IP "embed => \fIboolean\fR" 4 .IX Item "embed => boolean" Attach relative images and other media to the message. This is enabled by default. The module will attempt to embed objects defined by \f(CW\*(C`embed_elements\*(C'\fR. Note that this option only affects the parsing of the \s-1HTML\s0 and will not affect the \f(CW\*(C`objects\*(C'\fR option. .Sp The object's \s-1URI\s0 will be rewritten as a Content \s-1ID.\s0 .IP "embed_elements => \fIreference to hash of hashes with boolean values\fR" 4 .IX Item "embed_elements => reference to hash of hashes with boolean values" The set of elements that you want to be embedded. Defaults to the \f(CW%Email::MIME::CreateHTML::EMBED\fR package global. This should be a data structure of the form: .Sp .Vb 5 \& embed_elements => { \& $elementname_1 => {$attrname_1 => $boolean_1}, \& $elementname_2 => {$attrname_2 => $boolean_2}, \& ... \& } .Ve .Sp i.e. resource will be embedded if \f(CW\*(C`$embed_elements\->{$elementname}\->{$attrname}\*(C'\fR is true. .IP "resolver => \fIobject\fR" 4 .IX Item "resolver => object" If a resolver is supplied this will be used to fetch the resources that are embedded as \s-1MIME\s0 objects in the email. If no resolver is given the default behaviour is to choose the best available resolver to read \f(CW$uri\fR with any \f(CW$base\fR value prefixed. Resources fetched using the resolver will be cached if an \f(CW\*(C`object_cache\*(C'\fR is supplied. .IP "base => \fIscalar\fR" 4 .IX Item "base => scalar" This must be a filepath or a \s-1URI.\s0 .Sp If \f(CW\*(C`embed\*(C'\fR is true (the default) then \f(CW\*(C`base\*(C'\fR will be used when fetching the objects. .Sp Examples of good bases: .Sp .Vb 3 \& ./local/images \& /home/somewhere/images \& http://mywebserver/images .Ve .IP "inline_css => \fIboolean\fR" 4 .IX Item "inline_css => boolean" Inline any \s-1CSS\s0 external \s-1CSS\s0 files referenced through link elements. Enabled by default. Some mail clients will only interpret css if it is inlined. .IP "objects => \fIhash reference\fR" 4 .IX Item "objects => hash reference" A reference to a hash of external objects. Keys are Content Ids and the values are filepaths or URIs used to fetch the resource with the resolver. We use \f(CW\*(C`MIME::Types\*(C'\fR to derive the type from the file extension. For example in an \s-1HTML\s0 mail you would use the file keyed on '12345678@bbc.co.uk' like \f(CW\*(C`a test\*(C'\fR .IP "object_cache => \fIcache object\fR" 4 .IX Item "object_cache => cache object" A cache object can be supplied to cache external resources such as images. This must support the following interface: .Sp .Vb 3 \& $o = new ... \& $o\->set($key, $value) \& $value = $o\->get($key) .Ve .Sp Both the Cache and Cache::Cache distributions on \s-1CPAN\s0 conform to this. .IP "text_body => \fIscalar\fR" 4 .IX Item "text_body => scalar" A scalar value holding the contents of an additional \fIplain text\fR message body. .IP "text_body_attributes => \fIhash reference\fR" 4 .IX Item "text_body_attributes => hash reference" This is passed as the attributes parameter to the \f(CW\*(C`create\*(C'\fR method (supplied by \f(CW\*(C`Email::MIME::Creator\*(C'\fR) that creates the plain text part of the mail. The body Content-Type will be set to \f(CW\*(C`text/plain\*(C'\fR unless it is overidden here. .SH "GLOBAL VARIABLES" .IX Header "GLOBAL VARIABLES" .ie n .IP "%Email::MIME::CreateHTML::EMBED" 4 .el .IP "\f(CW%Email::MIME::CreateHTML::EMBED\fR" 4 .IX Item "%Email::MIME::CreateHTML::EMBED" This is the default set of elements (and the relevant attributes that point at a resource) that will be embedded. The for this is: .Sp .Vb 8 \& \*(Aqbgsound\*(Aq => {\*(Aqsrc\*(Aq=>1}, \& \*(Aqbody\*(Aq => {\*(Aqbackground\*(Aq=>1}, \& \*(Aqimg\*(Aq => {\*(Aqsrc\*(Aq=>1}, \& \*(Aqinput\*(Aq => {\*(Aqsrc\*(Aq=>1}, \& \*(Aqtable\*(Aq => {\*(Aqbackground\*(Aq=>1}, \& \*(Aqtd\*(Aq => {\*(Aqbackground\*(Aq=>1}, \& \*(Aqth\*(Aq => {\*(Aqbackground\*(Aq=>1}, \& \*(Aqtr\*(Aq => {\*(Aqbackground\*(Aq=>1} .Ve .Sp You can override this using the \f(CW\*(C`embed_elements\*(C'\fR parameter. .SH "COOKBOOK" .IX Header "COOKBOOK" .SS "The basics" .IX Subsection "The basics" This builds an \s-1HTML\s0 email: .PP .Vb 8 \& my $email = Email::MIME\->create_html( \& header => [ \& From => \*(Aqmy@address\*(Aq, \& To => \*(Aqyour@address\*(Aq, \& Subject => \*(AqMy speedy HTML\*(Aq, \& ], \& body => $html \& ); .Ve .PP If you want a plaintext alternative, include the \f(CW\*(C`text_body\*(C'\fR option: .PP .Vb 9 \& my $email = Email::MIME\->create_html( \& header => [ \& From => \*(Aqmy@address\*(Aq, \& To => \*(Aqyour@address\*(Aq, \& Subject => \*(AqHere is the information you requested\*(Aq, \& ], \& body => $html, \& text_body => $plain_text #<\-\- \& ); .Ve .PP If you want your images to remain as links (rather than be embedded in the email) disable the \f(CW\*(C`embed\*(C'\fR option: .PP .Vb 9 \& my $email = Email::MIME\->create_html( \& header => [ \& From => \*(Aqmy@address\*(Aq, \& To => \*(Aqyour@address\*(Aq, \& Subject => \*(AqMy speedy HTML\*(Aq, \& ], \& body => $html, \& embed => 0 #<\-\- \& ); .Ve .SS "Optimising out \s-1HTML\s0 parsing" .IX Subsection "Optimising out HTML parsing" By default, the \s-1HTML\s0 is parsed to look for objects and stylesheets that need embedding. If you are controlling the construction of the \s-1HTML\s0 yourself, you can use Content Ids as the URIs within your \s-1HTML\s0 and then pass in a set of objects to associate with those Content IDs: .PP .Vb 5 \& my $html = qq{ \& My Document \&

Here is a picture:

\& \& }; .Ve .PP You then need to create a mapping of the Content IDs to object filenames: .PP .Vb 3 \& my %objects = ( \& "some_image_jpg@bbc.co.uk" => "/var/html/some_image.jpg" \& ); .Ve .PP Finally you need to disable both the \f(CW\*(C`embed\*(C'\fR and \f(CW\*(C`inline_css\*(C'\fR options to turn off \s-1HTML\s0 parsing, and pass in your mapping: .PP .Vb 11 \& my $quick_to_assemble_mime = Email::MIME\->create_html( \& header => [ \& From => \*(Aqmy@address\*(Aq, \& To => \*(Aqyour@address\*(Aq, \& Subject => \*(AqMy speedy HTML\*(Aq, \& ], \& body => $html, \& embed => 0, #<\-\- \& inline_css => 0, #<\-\- \& objects => \e%objects #<\-\- \& ); .Ve .PP \fIPreprocessing templates\fR .IX Subsection "Preprocessing templates" .PP If you have for example a personalised newsletter where your \s-1HTML\s0 will vary slightly from one email to the next, but you don't want to re-parse the \s-1HTML\s0 each time to re-fetch and attach objects, you can use the \f(CW\*(C`embed_objects\*(C'\fR function to pre-process the template, converting URIs into CIDs: .PP .Vb 2 \& use Email::MIME::CreateHTML qw(embed_objects); \& my ($preproc_tmpl_content, $cid_mapping) = embed_objects($tmpl_content); .Ve .PP You can then reuse this and the \s-1CID\s0 mapping: .PP .Vb 2 \& my $template = compile_template($preproc_tmpl_content); \& foreach $newsletter (@newsletters) { \& \& #Do templating \& my $html = $template\->process($newsletter); \& \& #Build MIME structure \& my $mime = Email::MIME\->create_html( \& header => [ \& From => $reply_address, \& To => $newsletter\->address, \& Subject => \*(AqWeekly newsletter\*(Aq, \& ], \& body => $html, \& embed => 0, #Already done \& inline_css => 0, #Already done \& objects => $cid_mapping #Here\*(Aqs one we prepared earlier \& ); \& \& #Send email \& send_email($mime); \& } .Ve .PP Note that one caveat with this approach is that all possible images that might be used in the template will be attached to the email. Depending on your template logic, it may be that some are never actually referenced from within the email (e.g. if an image is conditionally displayed) so this may create unnecessarily large emails. .SS "Plugging in a custom resource resolver" .IX Subsection "Plugging in a custom resource resolver" A custom resource resolver can be specified by passing your own object to resolver: .PP .Vb 10 \& my $mime = Email::MIME\->create_html( \& header => [ \& From => \*(Aqmy@address\*(Aq, \& To => \*(Aqyour@address\*(Aq, \& Subject => \*(AqHere is the information you requested\*(Aq, \& ], \& body => $html, \& base => \*(Aqhttp://internal.foo.co.uk/images/\*(Aq, \& resolver => new MyResolver, #<\-\- \& ); .Ve .PP The object needs to have the following \s-1API:\s0 .PP .Vb 6 \& package MyResolver; \& sub new { \& my ($self, $options) = @_; \& my $base_uri = $options\->{base}; \& #... YOUR CODE HERE ... (probably want to stash $base_uri in $self) \& } \& \& sub get_resource { \& my ($self, $uri) = @_; \& my ($content,$filename,$mimetype,$xfer_encoding); \& #... YOUR CODE HERE ... \& return ($content,$filename,$mimetype,$xfer_encoding); \& } .Ve .PP where: .PP .Vb 2 \& $uri is the URI of the object we are embedding (taken from the markup or passed in via the CID mapping) \& $base_uri is base URI used to resolve relative URIs \& \& $content is a scalar containing the contents of the file \& $filename is used to set the name attribute of the Email::MIME object \& $mimetype is used to set the content_type attribute of the Email::MIME object \& $xfer_encoding is used to set the encoding attribute of the Email::MIME object \& (note this is the suitable transfer encoding NOT a character encoding) .Ve .SS "Plugging in different types of object cache" .IX Subsection "Plugging in different types of object cache" You can use a cache from the Cache::Cache distribution: .PP .Vb 9 \& use Cache::MemoryCache; \& my $mime = Email::MIME\->create_html( \& header => \e@headers, \& body => $html, \& object_cache => new Cache::MemoryCache( { \& \*(Aqnamespace\*(Aq => \*(AqMyNamespace\*(Aq, \& \*(Aqdefault_expires_in\*(Aq => 600 \& } ) \& ); .Ve .PP Or a cache from the Cache distribution: .PP .Vb 9 \& use Cache::File; \& my $mime = Email::MIME\->create_html( \& header => \e@headers, \& body => $html, \& object_cache => Cache::File\->new( \& cache_root => \*(Aq/tmp/mycache\*(Aq, \& default_expires => \*(Aq600 sec\*(Aq \& ) \& ); .Ve .PP Alternatively you can roll your own. You just need to define an object with get and set methods: .PP .Vb 5 \& my $mime = Email::MIME\->create_html( \& header => \e@headers, \& body => $html, \& object_cache => new MyCache() \& ); \& \& package MyCache; \& our %Cache; \& sub new {return bless({}, shift())} \& sub get {return $Cache{shift()}} \& sub set {$Cache{shift()} = shift()} \& 1; .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" Perl Email Project .PP Email::Simple, Email::MIME, Email::Send, Email::MIME::Creator .SH "TODO" .IX Header "TODO" Maybe add option to control the order that the text + html parts appear in the \s-1MIME\s0 message. .SH "AUTHOR" .IX Header "AUTHOR" Tony Hennessy and Simon Flack with cookbook + some refactoring by John Alden with additional contributions by Ricardo Signes and Henry Van Styn .SH "COPYRIGHT" .IX Header "COPYRIGHT" (c) \s-1BBC 2005,2006.\s0 This program is free software; you can redistribute it and/or modify it under the \s-1GNU GPL.\s0 .PP See the file \s-1COPYING\s0 in this distribution, or http://www.gnu.org/licenses/gpl.txt