package Email::MIME::Kit::Assembler::Markdown; { $Email::MIME::Kit::Assembler::Markdown::VERSION = '0.100000'; } use Moose; with 'Email::MIME::Kit::Role::Assembler'; # ABSTRACT: build multipart/alternative messages from Markdown alone use Email::MIME 1.900; use Moose::Util::TypeConstraints qw(maybe_type role_type); use Text::Markdown; has manifest => ( is => 'ro', required => 1, ); has html_wrapper => ( is => 'ro', isa => 'Str', ); has text_wrapper => ( is => 'ro', isa => 'Str', ); has munge_signature => ( is => 'ro', isa => 'Bool', default => 0, ); has renderer => ( reader => 'renderer', writer => '_set_renderer', clearer => '_unset_renderer', isa => maybe_type(role_type('Email::MIME::Kit::Role::Renderer')), lazy => 1, default => sub { $_[0]->kit->default_renderer }, init_arg => undef, ); has marker => (is => 'ro', isa => 'Str', default => 'CONTENT'); has path => ( is => 'ro', isa => 'Str', lazy => 1, default => sub { $_[0]->manifest->{path} }, ); sub BUILD { my ($self) = @_; my $class = ref $self; confess "$class does not support alternatives" if @{ $self->manifest->{alternatives} || [] }; confess "$class does not support attachments" if @{ $self->manifest->{attachments} || [] }; confess "$class does not support MIME content attributes" if %{ $self->manifest->{attributes} || {} }; } sub _prep_header { my ($self, $header, $stash) = @_; my @done_header; for my $entry (@$header) { confess "no field name candidates" unless my (@hval) = grep { /^[^:]/ } keys %$entry; confess "multiple field name candidates: @hval" if @hval > 1; my $value = $entry->{ $hval[ 0 ] }; if (ref $value) { my ($v, $p) = @$value; $value = join q{; }, $v, map { "$_=$p->{$_}" } keys %$p; } else { my $renderer = $self->renderer; if (exists $entry->{':renderer'}) { undef $renderer if ! defined $entry->{':renderer'}; confess 'alternate renderers not supported'; } $value = ${ $renderer->render(\$value, $stash) } if defined $renderer; } push @done_header, $hval[0] => $value; } return \@done_header; } sub assemble { my ($self, $stash) = @_; my $markdown = ${ $self->kit->get_kit_entry( $self->path ) }; if ($self->renderer) { my $output_ref = $self->renderer->render(\$markdown, $stash); $markdown = $$output_ref; } my $plaintext = $markdown; if ($self->munge_signature) { my ($body, $sig) = split /^-- $/m, $markdown, 2; if (defined $sig) { $sig =~ s{^}{
}mg; $markdown = "$body\n\n$sig"; } } my %content = ( html => Text::Markdown->new(tab_width => 2)->markdown($markdown), text => $plaintext, ); for my $type (keys %content) { my $type_wrapper = "$type\_wrapper"; if (my $wrapper_path = $self->$type_wrapper) { my $wrapper = ${ $self->kit->get_kit_entry($wrapper_path) }; my $marker = $self->marker; my $marker_re = qr{}; confess "$type_wrapper does not contain comment containing marker" unless $wrapper =~ $marker_re; $wrapper =~ s/$marker_re/$content{$type}/; $content{$type} = $wrapper; } } my $header = $self->_prep_header( $self->manifest->{header}, $stash, ); my $html_part = Email::MIME->create( body => $content{html}, attributes => { content_type => "text/html", charset => 'utf-8', encoding => 'quoted-printable', }, ); my $text_part = Email::MIME->create( body => $content{text}, attributes => { content_type => "text/plain", charset => 'utf-8', encoding => 'quoted-printable', }, ); my $container = Email::MIME->create( header_str => $header, parts => [ $text_part, $html_part ], attributes => { content_type => 'multipart/alternative' }, ); return $container; } no Moose; no Moose::Util::TypeConstraints; 1; __END__ =pod =head1 NAME Email::MIME::Kit::Assembler::Markdown - build multipart/alternative messages from Markdown alone =head1 VERSION version 0.100000 =head1 SYNOPSIS In your mkit's (JSON, here) manifest: { "renderer" : "TT", "assembler": [ "Markdown", { "html_wrapper": "wrapper.html" } ], "path" : "body.mkdn", "header": [ { "Subject": "DynaWoop is now hiring!" }, { "From" : "[% from_addr %]" } { "To" : "[% user.email %]" } ] } This kit will build a multipart/alternative message with a plaintext part (containing the rendered contents of F ) and an HTML part (containing F rendered into HTML using Markdown). At present, attachments are not supported. Actually, quite a few things found in the standard assembler are not yet supported. The standard assembler desperately needs to be refactored to make its features easier to incorporate into other assemblers. The C parameter for the Markdown assembler is the path to a kit entry. If given, that kit entry will be used for the HTML part, and the Markdown-produced HTML will be injected into it, replacing a comment containing the C given in the Markdown assembler's configuration. The default marker is C, so the F used above might read as follows:

DynaWoop Dynamic Woopages

Click to unsubscribe: here

The C setting works exactly the same way, down to looking for an HTML-like comment containing the marker. It wraps the Markdown content after it has been rendered by the kit's Renderer, if any. If given (and true), the C option will perform some basic munging of a sigdash-prefixed signature in the source text, hardening line breaks. The specific munging performed is not guaranteed to remain exactly stable. =for Pod::Coverage assemble BUILD =head1 AUTHOR Ricardo Signes =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011 by Ricardo Signes. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut