From 832a630d337ab0e8aa407921fcda46ba96bd3474 Mon Sep 17 00:00:00 2001 From: Hammat Wele Date: Tue, 3 Mar 2026 18:36:08 +0000 Subject: [PATCH] Bug 41965: Mismatch between SMTP server and FROM branch in multi-branch notice sending MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In a multi-branch setup, when sending notices (e.g., overdue notices), the From address may correctly correspond to the branch where the checkout occurred, but the SMTP server used to send the email is taken from another branch (often the patron’s home library or the system default). This leads to email delivery failures. SMTP and From must always be derived from the same logical branch. To Reproduce You must have: 1- A default SMTP server defined in koha-conf.xml: smtp.gmail.com 587 5 STARTTLS email@gmail.com ertyuytre 1 2- A second SMTP server configured in Koha. Configuration Steps 1- Go to Administration -> SMTP servers 2- Create a new SMTP server named Midway 3- Go to Administration -> Libraries 4- Edit Springfield 1- Email: springfield@example.com 2- SMTP server: Default 5- Edit Midway 1- Email: midway@example.com 2- SMTP server: Midway 6- Click your username -> Set library -> switch to Midway 7- Find a borrower belonging to Springfield and ensure they have an email 8- Find a record with items 9- Checkout an item to that borrower with a past due date 10- Run: ./misc/cronjobs/overdue_notices.pl 11- Check message_queue table ==> from_address = midway@example.com 12- Run: ./misc/cronjobs/process_message_queue.pl -v ==> The SMTP used is the Default one, Expected: Midway SMTP ==> The SMTP server used must correspond to the branch that owns the from_address. 13- Apply the patch 14- Run prove t/db_dependent/Letters.t ==> Test should pass 15- Repeat step 12 ==> The smtp used is the Midway one --- C4/Letters.pm | 15 ++++++- t/db_dependent/Letters.t | 85 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/C4/Letters.pm b/C4/Letters.pm index 1db40371776..c6530b67d53 100644 --- a/C4/Letters.pm +++ b/C4/Letters.pm @@ -1592,10 +1592,21 @@ sub _send_message_by_email { return unless $email; my $smtp_server; - if ($library) { + if ( $library && $from_address eq $branch_email ) { $smtp_server = $library->smtp_server; } else { - $smtp_server = Koha::SMTP::Servers->get_default; + my $libs = Koha::Libraries->search( { branchemail => $from_address } ); + while ( my $lib = $libs->next ) { + my $lib_smtp = $lib->smtp_server; + if ($lib_smtp) { + $smtp_server = $lib_smtp; + last; + } + } + + unless ($smtp_server) { + $smtp_server = Koha::SMTP::Servers->get_default; + } } if ($username) { diff --git a/t/db_dependent/Letters.t b/t/db_dependent/Letters.t index f248a07f7f5..5f0c11206a8 100755 --- a/t/db_dependent/Letters.t +++ b/t/db_dependent/Letters.t @@ -19,7 +19,7 @@ use Modern::Perl; use File::Basename qw(dirname); -use Test::More tests => 105; +use Test::More tests => 106; use Test::NoWarnings; use Test::MockModule; @@ -1825,4 +1825,87 @@ subtest 'Virtual method ->strftime in notices' => sub { is( $get_letter->()->{content}, $expected_output, 'Check generated content for us dateformat' ); }; +subtest 'SMTP resolution based on from_address' => sub { + + plan tests => 2; + + my $lib_default = $builder->build_object( + { + class => 'Koha::Libraries', + value => { + branchcode => 'DEF', + branchname => 'Default Library', + branchemail => 'default@library.com', + } + } + ); + + my $lib_custom = $builder->build_object( + { + class => 'Koha::Libraries', + value => { + branchcode => 'CUS', + branchname => 'Custom Library', + branchemail => 'custom@library.com', + } + } + ); + + my $smtp_custom = $builder->build_object( + { + class => 'Koha::SMTP::Servers', + value => { + name => 'Custom SMTP', + host => 'smtp.custom.test', + } + } + ); + my $smtp_default = $builder->build_object( + { + class => 'Koha::SMTP::Servers', + value => { + name => 'Default SMTP', + host => 'smtp.default.test', + } + } + ); + + $lib_default->smtp_server( { smtp_server => $smtp_default } ); + $lib_custom->smtp_server( { smtp_server => $smtp_custom } ); + + my $used_transport; + my $mock_stuffer = Test::MockModule->new('Email::Stuffer'); + $mock_stuffer->mock( + 'send_or_die', + sub { + my ( $self, $args ) = @_; + $used_transport = $args->{transport}; + return 1; + } + ); + + C4::Letters::_send_message_by_email( + { + to_address => 'user@test.com', + from_address => 'custom@library.com', + content => 'Test', + subject => 'Test subject', + } + ); + + is( $used_transport->host, 'smtp.custom.test', 'Uses custom SMTP' ); + + C4::Letters::_send_message_by_email( + { + to_address => 'user@test.com', + from_address => 'default@library.com', + content => 'Test', + subject => 'Test subject', + } + ); + + is( $used_transport->host, 'smtp.default.test', 'Uses default SMTP' ); + +}; + $schema->storage->txn_rollback; -- 2.34.1