Skip to content

Commit

Permalink
Insert mail footers into the first attachment of the email, trying to…
Browse files Browse the repository at this point in the history
… match its type (text/html). Convert email messages with only 1 part to singlepart, instead of multipart. Fixes bug #11560.
  • Loading branch information
perlDreamer committed Jun 15, 2010
1 parent 541f262 commit c821e20
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 6 deletions.
1 change: 1 addition & 0 deletions docs/changelog/7.x.x.txt
Expand Up @@ -2,6 +2,7 @@
- fixed #11619: Trash Expired Events not trashing events
- fixed #11623: Navigation CSS-id
- fixed #11622: Archived CSS entries displayable.
- fixed #11560: Email footer hidden from Outlook users

7.8.21
- fixed #11597: manageTrash and newlines
Expand Down
59 changes: 56 additions & 3 deletions lib/WebGUI/Mail/Send.pm
Expand Up @@ -22,6 +22,7 @@ use Net::SMTP;
use WebGUI::Group;
use WebGUI::Macro;
use WebGUI::User;
use WebGUI::HTML;
use Encode qw(encode);

=head1 NAME
Expand Down Expand Up @@ -84,15 +85,57 @@ sub addAttachment {

=head2 addFooter ( )
Adds the mail footer as set by the site admin to the end of this message.
Adds the mail footer as set by the site admin to the end of the first
part of this message. If the first part of the message has an HTML MIME-type,
then it will translate the footer to HTML.
If the message is empty, it will create a MIME entity part to hold it.
Macros in the footer will be evaluated.
=cut

sub addFooter {
my $self = shift;
return if $self->{_footerAdded};
my $text = "\n\n".$self->session->setting->get("mailFooter");
WebGUI::Macro::process($self->session, \$text);
$self->addText($text);
$self->{_footerAdded} = 1;
my @parts = $self->getMimeEntity->parts();
##No parts yet, add one with the footer content.
if (! $parts[0]) {
$self->addText($text);
return;
}
##Get the content of the first part, drop it from the set of parts
my $mime_body = $parts[0]->bodyhandle;
my $body_content = join '', $mime_body->as_lines;
my $mime_type;
if ($parts[0]->effective_type eq 'text/plain') {
$body_content .= $text;
my $new_part = MIME::Entity->build(
Charset => "UTF-8",
Encoding => "quoted-printable",
Type => 'text/plain',
Data => encode('utf8', $body_content),
);
shift @parts;
unshift @parts, $new_part;
$self->getMimeEntity->parts(\@parts);
}
elsif ($parts[0]->effective_type eq 'text/html') {
$text = WebGUI::HTML::format($text, 'mixed');
$body_content =~ s{(?=</body>)}{$text};
my $new_part = MIME::Entity->build(
Charset => "UTF-8",
Encoding => "quoted-printable",
Type => 'text/html',
Data => encode('utf8', $body_content),
);
shift @parts;
unshift @parts, $new_part;
$self->getMimeEntity->parts(\@parts);
}
}

#-------------------------------------------------------------------
Expand Down Expand Up @@ -339,7 +382,13 @@ sub create {
delete $headers->{toGroup};
$message->attach(Data=>"This message was intended for ".$to." but was overridden in the config file.\n\n");
}
bless {_message=>$message, _session=>$session, _toGroup=>$headers->{toGroup}, _isInbox => $isInbox }, $class;
return bless {
_message => $message,
_session => $session,
_toGroup => $headers->{toGroup},
_isInbox => $isInbox,
_footerAdded => 0,
}, $class;
}

#-------------------------------------------------------------------
Expand Down Expand Up @@ -462,6 +511,10 @@ sub send {
my $smtpServer = $session->setting->get("smtpServer");
my $status = 1;

if ($mail->parts <= 1) {
warn "making singlepart";
$mail->make_singlepart;
}
if ($mail->head->get("To")) {
if ($session->config->get("emailToLog")){
my $message = $mail->stringify;
Expand Down
108 changes: 105 additions & 3 deletions t/Mail/Send.t
Expand Up @@ -42,7 +42,7 @@ if ( $@ ) { diag( "Can't prepare mail server: $@" ) }
#----------------------------------------------------------------------------
# Tests

plan tests => 17; # Increment this number for each test you create
plan tests => 33; # Increment this number for each test you create

#----------------------------------------------------------------------------
# Test create
Expand Down Expand Up @@ -76,6 +76,8 @@ is( $mime->parts(0)->as_string =~ m/\n/, $newlines,
"addText should add newlines after 78 characters",
);

is ( $mime->parts(0)->effective_type, 'text/plain', '... sets the correct MIME type' );

#----------------------------------------------------------------------------
# Test addHtml
$mail = WebGUI::Mail::Send->create( $session );
Expand All @@ -87,13 +89,13 @@ $mail->addHtml($text);
$mime = $mail->getMimeEntity;

# TODO: Test that addHtml creates an HTML wrapper if no html or body tag exists
# TODO: Test that addHtml creates a body with the right content type

# addHtml should add newlines after 78 characters
$newlines = length $text / 78;
is( $mime->parts(0)->as_string =~ m/\n/, $newlines,
"addHtml should add newlines after 78 characters",
);
is ( $mime->parts(0)->effective_type, 'text/html', '... sets the correct MIME type' );

# TODO: Test that addHtml does not create an HTML wrapper if html or body tag exist

Expand Down Expand Up @@ -125,7 +127,53 @@ my $messageId = $mail->queue;
my $dbMail = WebGUI::Mail::Send->retrieve($session, $messageId);
is($dbMail->getMimeEntity->head->get('List-ID'), "=?UTF-8?Q?H=C3=84ufige=20Fragen?=\n", 'addHeaderField: handles utf-8 correctly');

# TODO: Test that addHtml creates a body with the right content type
{
my $mail = WebGUI::Mail::Send->create( $session );
ok ! $mail->{_footerAdded}, 'footerAdded flag set to false by default';
$mail->addFooter;
ok $mail->{_footerAdded}, '... flag set after calling addFooter';
my $number_of_parts;
$number_of_parts = $mail->getMimeEntity->parts;
is $number_of_parts, 1, '... added 1 part for a footer';
$mail->addFooter;
ok $mail->{_footerAdded}, '... flag still set after calling addFooter again';
$number_of_parts = $mail->getMimeEntity->parts;
is $number_of_parts, 1, '... 2nd footer not added';

}

{
my $mail = WebGUI::Mail::Send->create( $session );
$mail->addText('some text');
$mail->addFooter;
my $number_of_parts;
$number_of_parts = $mail->getMimeEntity->parts;
is $number_of_parts, 1, 'addFooter did not add any other parts';
my $body = $mail->getMimeEntity->parts(0)->as_string;
$body =~ s/\A.+?(?=some text)//s;
is $body, "some text\n\nMy Company\ninfo\@mycompany.com\nhttp://www.mycompany.com\n", '... footer appended to the first part as text';
}

{
my $mail = WebGUI::Mail::Send->create( $session );
$mail->addHtml('some <b>markup</b>');
$mail->addFooter;
my $number_of_parts;
$number_of_parts = $mail->getMimeEntity->parts;
is $number_of_parts, 1, 'addFooter did not add any other parts';
my $body = $mail->getMimeEntity->parts(0)->as_string;
$body =~ s/\A.+?<body>\n//sm;
$body =~ s!</body>.+\Z!!sm;
is $body, "some <b>markup</b>\n<br />\n<br />\nMy Company<br />\ninfo\@mycompany.com<br />\nhttp://www.mycompany.com<br />\n", '... footer appended to the first part as text';
}

{
my $mail = WebGUI::Mail::Send->create( $session );
$mail->addText('This is a textual email');
my $result = $mail->getMimeEntity->is_multipart;
ok(defined $result && $result, 'by default, we make multipart messages');
}

my $smtpServerOk = 0;

#----------------------------------------------------------------------------
Expand Down Expand Up @@ -352,6 +400,60 @@ cmp_bag(
'send: when the original is sent, new messages are created for each user in the group, following their user profile settings'
);

SKIP: {
my $numtests = 2; # Number of tests in this block

skip "Cannot test making emails single part", $numtests unless $smtpServerOk;

# Send the mail
my $mail
= WebGUI::Mail::Send->create( $session, {
to => 'norton@localhost',
} );
$mail->addText("They say it has no memory. That's where I want to live the rest of my life. A warm place with no memory.");

ok ($mail->getMimeEntity->is_multipart, 'starting with a multipart message');
$mail->send;
my $received = WebGUI::Test->getMail;

if (!$received) {
skip "Cannot making single part: No response received from smtpd", $numtests;
}

# Test the mail
my $parser = MIME::Parser->new();
$parser->output_to_core(1);
my $parsed_message = $parser->parse_data($received->{contents});
ok (!$parsed_message->is_multipart, 'converted to singlepart since it only has 1 part.');
}

SKIP: {
my $numtests = 2; # Number of tests in this block

skip "Cannot test making emails single part", $numtests unless $smtpServerOk;

# Send the mail
my $mail
= WebGUI::Mail::Send->create( $session, {
to => 'norton@localhost',
} );
$mail->addText("You know what the Mexicans say about the Pacific?");
$mail->addText("They say it has no memory. That's where I want to live the rest of my life. A warm place with no memory.");

ok ($mail->getMimeEntity->is_multipart, 'starting with a multipart message');
$mail->send;
my $received = WebGUI::Test->getMail;

if (!$received) {
skip "Cannot making single part: No response received from smtpd", $numtests;
}

# Test the mail
my $parser = MIME::Parser->new();
$parser->output_to_core(1);
my $parsed_message = $parser->parse_data($received->{contents});
ok ( $parsed_message->is_multipart, 'left as multipart since it has more than 1 part');
}
# TODO: Test the emailToLog config setting
#----------------------------------------------------------------------------
# Cleanup
Expand Down

0 comments on commit c821e20

Please sign in to comment.