From 54546da3f07380375470bc130f15a33830419ac8 Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Fri, 5 Nov 2021 16:05:48 -0300 Subject: [PATCH] Bug 29330: Restore handling of serialized MIME messages in message_queue This patch changes how multipart MIME messages are handled on the message_queue table. The email, with the required attachments, is now generated using Koha::Email, and serialized using Koha::Email->as_string. This bug also adds Koha::Email->new_from_string which is used to read that data from the DB, and produce a Koha::Email object, that can be further augmented/modified using regular Koha::Email methods. This implementation should be considered a middle ground, with backportability in mind. higher-level methods should encapsulate setting the default headers and addresses, to clean the area a bit further. Preparation: - You need a valid SMTP configuration in koha-conf.xml. If you use Gmail you can generate an 'app password' and set things like this: smtp.gmail.com 587 5 STARTTLS youraddress@gmail.com youpassword 1 - Set KohaAdminAddress to your address. To test: 1. Pick a patron. Make sure it doesn't have any email address (Acevedo?) 2. Set an overdue notice trigger for its category 3. Check something out, with due date in the past to force an overdue 4. Run: $ kshell k$ misc/cronjobs/overdue_notices.pl -v k$ exit $ koha-mysql kohadev > SELECT * FROM message_queue WHERE borrowernumber=the_borrowernumber; => SUCCESS: A notice has been created 5. Run: $ kshell k$ misc/cronjobs/process_message_queue.pl --verbose => SUCCESS: SMTP is ok => Email is sent => FAIL: Your inbox shows an email with weird content 6. Apply this patches 7. Run: $ koha-mysql kohadev > DELETE FROM message_queue; 8. Repeat 4 and 5 => SUCCESS: You got an email with an attachment! => SUCCESS: The attachment contains an email that couldn't be delivered! 9. Try all the things that enqueue messages :-D => SUCCESS: No behavior change 10. Sign off :-D Signed-off-by: Tomas Cohen Arazi Signed-off-by: David Nind Signed-off-by: Victor Grousset/tuxayo Signed-off-by: Martin Renvoize Signed-off-by: Marcel de Rooy Edited the POD, restoring a few lines that describe the needed hash keys of the attachments. Signed-off-by: Jonathan Druart Signed-off-by: Kyle M Hall --- C4/Letters.pm | 100 +++++++++++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/C4/Letters.pm b/C4/Letters.pm index 70b65de220..b931dea1e7 100644 --- a/C4/Letters.pm +++ b/C4/Letters.pm @@ -19,10 +19,9 @@ package C4::Letters; use Modern::Perl; -use MIME::Lite; use Date::Calc qw( Add_Delta_Days ); use Encode; -use Carp; +use Carp qw( carp croak ); use Template; use Module::Load::Conditional qw(can_load); @@ -964,7 +963,6 @@ sub EnqueueLetter { $params->{'letter'} = _add_attachments( { letter => $params->{'letter'}, attachments => $params->{'attachments'}, - message => MIME::Lite->new( Type => 'multipart/mixed' ), } ); } @@ -1228,45 +1226,50 @@ sub ResendMessage { =head2 _add_attachements + _add_attachments({ letter => $letter, attachments => $attachments }); + named parameters: letter - the standard letter hashref attachments - listref of attachments. each attachment is a hashref of: type - the mime type, like 'text/plain' content - the actual attachment filename - the name of the attachment. - message - a MIME::Lite object to attach these to. returns your letter object, with the content updated. + This routine picks the I of I and generates a MIME + email, attaching the passed I using Koha::Email. The + content is replaced by the string representation of the MIME object, + and the content-type is updated to B for later handling. =cut sub _add_attachments { my $params = shift; - my $letter = $params->{'letter'}; - my $attachments = $params->{'attachments'}; + my $letter = $params->{letter}; + my $attachments = $params->{attachments}; return $letter unless @$attachments; - my $message = $params->{'message'}; - - # First, we have to put the body in as the first attachment - $message->attach( - Type => $letter->{'content-type'} || 'TEXT', - Data => $letter->{'is_html'} - ? _wrap_html($letter->{'content'}, $letter->{'title'}) - : $letter->{'content'}, - ); + + my $message = Koha::Email->new; + + if ( $letter->{is_html} ) { + $message->html_body( _wrap_html( $letter->{content}, $letter->{title} ) ); + } + else { + $message->text_body( $letter->{content} ); + } foreach my $attachment ( @$attachments ) { $message->attach( - Type => $attachment->{'type'}, - Data => $attachment->{'content'}, - Filename => $attachment->{'filename'}, + Encode::encode( "UTF-8", $attachment->{content} ), + content_type => 'application/octet-stream', + name => $attachment->{filename}, + disposition => 'attachment', ); } - # we're forcing list context here to get the header, not the count back from grep. - ( $letter->{'content-type'} ) = grep( /^Content-Type:/, split( /\n/, $params->{'message'}->header_as_string ) ); - $letter->{'content-type'} =~ s/^Content-Type:\s+//; - $letter->{'content'} = $message->body_as_string; + + $letter->{'content-type'} = 'MIME'; + $letter->{content} = $message->as_string; return $letter; @@ -1400,21 +1403,37 @@ sub _send_message_by_email { ); return; }; - my $email = try { - Koha::Email->create( - { - to => $to_address, - ( - C4::Context->preference('NoticeBcc') - ? ( bcc => C4::Context->preference('NoticeBcc') ) - : () - ), - from => $from_address, - reply_to => $message->{'reply_address'} || $branch_replyto, - sender => $branch_returnpath, - subject => "" . $message->{subject} + my $email; + + try { + + my $params = { + to => $to_address, + ( + C4::Context->preference('NoticeBcc') + ? ( bcc => C4::Context->preference('NoticeBcc') ) + : () + ), + from => $from_address, + reply_to => $message->{'reply_address'} || $branch_replyto, + sender => $branch_returnpath, + subject => "" . $message->{subject} + }; + + if ( $message->{'content_type'} && $message->{'content_type'} eq 'MIME' ) { + + # The message has been previously composed as a valid MIME object + # and serialized as a string on the DB + $email = Koha::Email->new_from_string($content); + $email->create($params); + } else { + $email = Koha::Email->create($params); + if ($is_html) { + $email->html_body( _wrap_html( $content, $subject ) ); + } else { + $email->text_body($content); } - ); + } } catch { if ( ref($_) eq 'Koha::Exceptions::BadParameter' ) { @@ -1438,15 +1457,6 @@ sub _send_message_by_email { }; return unless $email; - if ( $is_html ) { - $email->html_body( - _wrap_html( $content, $subject ) - ); - } - else { - $email->text_body( $content ); - } - my $smtp_server; if ( $library ) { $smtp_server = $library->smtp_server; -- 2.39.5