Insert mail footers into the first attachment of the email, trying to match its type (text/html). Convert email messages with only 1 part to singlepart, instead of multipart. Fixes bug #11560.

This commit is contained in:
Colin Kuskie 2010-06-15 12:26:02 -07:00
parent ef419c8b7b
commit 169fa47cdc
3 changed files with 162 additions and 6 deletions

View file

@ -18,6 +18,7 @@
- fixed #11623: Navigation CSS-id
- fixed #11629: WebGUI Collateral Manager = Error
- fixed #11622: Archived CSS entries displayable.
- fixed #11560: Email footer hidden from Outlook users
7.9.6
- new checkbox in the asset manager for clearing the package flag on import

View file

@ -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
@ -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);
}
}
#-------------------------------------------------------------------
@ -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;
}
#-------------------------------------------------------------------
@ -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;

View file

@ -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
WebGUI::Test->addToCleanup(SQL => 'delete from mailQueue');
@ -78,6 +78,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 );
@ -89,13 +91,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
@ -127,7 +129,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;
#----------------------------------------------------------------------------
@ -354,4 +402,58 @@ 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