File Coverage

blib/lib/App/Smarkmail.pm
Criterion Covered Total %
statement 44 46 95.6
branch 8 14 57.1
condition n/a
subroutine 9 9 100.0
pod 1 1 100.0
total 62 70 88.5


line stmt bran cond sub pod time code
1 1     1   383 use strict;
  1         6  
  1         22  
2 1     1   5 use warnings;
  1         1  
  1         91  
3             package App::Smarkmail 0.006;
4             # ABSTRACT: pipemailer that changes plaintext to multi/alt with Markdown
5              
6 1     1   1164 use Email::MIME;
  1         114075  
  1         36  
7 1     1   9 use Email::MIME::Creator;
  1         3  
  1         20  
8 1     1   6 use Email::MIME::Modifier;
  1         2  
  1         16  
9 1     1   475 use HTML::Entities ();
  1         5962  
  1         44  
10 1     1   653 use Text::Markdown;
  1         25994  
  1         441  
11              
12             #pod =head1 DESCRIPTION
13             #pod
14             #pod This module implements logic used by the F command, which accepts an
15             #pod email message on standard input, tries to convert it from a plaintext message
16             #pod to multipart alternative, and then sends it via F
17             #pod
18             #pod All of this is really sketchy and probably has secret mail-damaging or
19             #pod mail-losing bugs. -- rjbs, 2008-02-24
20             #pod
21             #pod =method markdown_email
22             #pod
23             #pod my $email = App::Smarkmail->markdown_email($message, \%arg);
24             #pod
25             #pod This method accepts an email message, either as an Email::MIME object or as a
26             #pod string or a reference to a string, and returns an Email::MIME object. If the
27             #pod method is I an object, the object will be altered in place.
28             #pod
29             #pod If the message is a single part plaintext message, or a multipart/mixed or
30             #pod multipart/related message in which the first part is plaintext, then the
31             #pod plaintext part will be replaced with a multipart/alternative part. The
32             #pod multi/alt part will have two alternatives, text and HTML. The HTML part will
33             #pod be generated by running the plaintext part through
34             #pod L.
35             #pod
36             #pod If the text message ends in a signature -- that is, a line containing only
37             #pod "--\x20" followed by no more than five lines -- the signature will be excluded
38             #pod from Markdown processing and will be appended to the HTML part wrapped in
39             #pod C
 and C tags. 
40             #pod
41             #pod Note that the HTML alternative is listed second, even though it is I true
42             #pod to the original composition than the first. This is because the assumption is
43             #pod that you want the recipient to see the HTML part, if possible.
44             #pod Multipart/alternative messages with HTML parts listed before plaintext parts
45             #pod seem to tickle some bugs in some popular MUAs.
46             #pod
47             #pod =cut
48              
49             sub markdown_email {
50 2     2 1 240 my ($self, $msg, $arg) = @_;
51              
52 2 50       5 my $to_send = eval { ref $msg and $msg->isa('Email::MIME') }
  2 50       23  
53             ? $msg
54             : Email::MIME->new($msg);
55              
56 2 100       2313 if ($to_send->content_type =~ m{^text/plain}) {
    50          
57 1         61 my ($text, $html) = $self->_parts_from_text($to_send);
58              
59 1         9 $to_send->content_type_set('multipart/alternative');
60 1         310 $to_send->parts_set([ $text, $html ]);
61             } elsif ($to_send->content_type =~ m{^multipart/(?:related|mixed)}) {
62 1         116 my @parts = $to_send->subparts;
63 1 50       13 if ($parts[0]->content_type =~ m{^text/plain}) {
64 1         46 my ($text, $html) = $self->_parts_from_text(shift @parts);
65              
66 1         7 my $alt = Email::MIME->create(
67             attributes => { content_type => 'multipart/alternative' },
68             parts => [ $text, $html ],
69             );
70              
71 1         2609 $to_send->parts_set([ $alt, @parts ]);
72             }
73             }
74              
75 2         7153 return $to_send;
76             }
77              
78             sub _parts_from_text {
79 2     2   7 my ($self, $email) = @_;
80              
81 2         6 my $text = $email->body;
82 2         148 my ($body, $sig) = split /^-- $/m, $text, 2;
83              
84 2 50       11 if (($sig =~ tr/\n/\n/) > 5) {
85 0         0 $body = $text;
86 0         0 $sig = '';
87             }
88              
89 2         13 my $html = Text::Markdown::markdown($body, { tab_width => 2 });
90              
91 2 50       3280 if ($sig) {
92 2         13 $html .= sprintf "
-- %s
",
93             HTML::Entities::encode_entities($sig);
94             }
95              
96 2         54 my $html_part = Email::MIME->create(
97             attributes => { content_type => 'text/html', },
98             body => $html,
99             );
100              
101 2         5472 my $text_part = Email::MIME->create(
102             attributes => { content_type => 'text/plain', },
103             body => $text,
104             );
105              
106 2         1863 return ($text_part, $html_part);
107             }
108              
109             1;
110              
111             __END__