|
|
|
@ -11,6 +11,7 @@ package Anvil::Tools::Email; |
|
|
|
|
use strict; |
|
|
|
|
use warnings; |
|
|
|
|
use Data::Dumper; |
|
|
|
|
use JSON; |
|
|
|
|
use Scalar::Util qw(weaken isweak); |
|
|
|
|
use Text::Diff; |
|
|
|
|
|
|
|
|
@ -104,10 +105,21 @@ sub check_config |
|
|
|
|
# We check to see if there are any emails in the queue. If we see queued emails for more than five |
|
|
|
|
# minutes, and a second mail server is configured, we'll automatically reconfigure for the next |
|
|
|
|
# known server. |
|
|
|
|
$anvil->Database->get_mail_servers({debug => $debug}); |
|
|
|
|
my ($oldest_message) = $anvil->Email->check_queue({debug => $debug}); |
|
|
|
|
if ($oldest_message > 600) |
|
|
|
|
{ |
|
|
|
|
$anvil->Email->swap_server({debug => $debug}); |
|
|
|
|
# Switch out mail servers. If there's only one mail server, this just checks the existing |
|
|
|
|
# config. |
|
|
|
|
my $mail_server_uuid = $anvil->Email->get_next_server({debug => $debug}); |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { mail_server_uuid => $mail_server_uuid }}); |
|
|
|
|
|
|
|
|
|
$anvil->Email->_configure_for_server({ |
|
|
|
|
debug => $debug, |
|
|
|
|
mail_server_uuid => $mail_server_uuid, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
return($problem); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
# If not configured look in variables for 'mail_server::last_used::<mail_server_uuid>'. The first one |
|
|
|
@ -117,26 +129,54 @@ sub check_config |
|
|
|
|
# In any case where the mail server is configured, the server that is used has their |
|
|
|
|
# 'mail_server::last_used::<mail_server_uuid>' variable set to the current time stamp. |
|
|
|
|
|
|
|
|
|
# Is the postfix daemon running? |
|
|
|
|
# Get the list of mail servers. |
|
|
|
|
my $reconfigure = 1; |
|
|
|
|
if ($reconfigure) |
|
|
|
|
|
|
|
|
|
# What, if anything, is the current mail server? |
|
|
|
|
my $current_mail_server = ""; |
|
|
|
|
my $postfix_main = $anvil->Storage->read_file({ |
|
|
|
|
debug => $debug, |
|
|
|
|
file => $anvil->data->{path}{configs}{postfix_main}, |
|
|
|
|
}); |
|
|
|
|
foreach my $line (split/\n/, $postfix_main) |
|
|
|
|
{ |
|
|
|
|
# Get the list of mail servers. |
|
|
|
|
$anvil->Database->get_mail_servers({debug => $debug}); |
|
|
|
|
if (($line =~ /relayhost = \[(.*?)\]:/) or ($line =~ /relayhost = (.*?):/)) |
|
|
|
|
{ |
|
|
|
|
$current_mail_server = $1; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { current_mail_server => $current_mail_server }}); |
|
|
|
|
|
|
|
|
|
# What is the UUID for this mail server? |
|
|
|
|
my $mail_server_uuid = $anvil->data->{mail_servers}{address_to_uuid}{$current_mail_server} ? $anvil->data->{mail_servers}{address_to_uuid}{$current_mail_server} : ""; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { mail_server_uuid => $mail_server_uuid }}); |
|
|
|
|
|
|
|
|
|
if ($mail_server_uuid) |
|
|
|
|
{ |
|
|
|
|
# Looks OK, so run the configure (it'll do nothing if there are no changes). |
|
|
|
|
$reconfigure = 0; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { reconfigure => $reconfigure }}); |
|
|
|
|
|
|
|
|
|
$anvil->Email->_configure_for_server({ |
|
|
|
|
debug => $debug, |
|
|
|
|
mail_server_uuid => $mail_server_uuid, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
### TODO: This just bootstraps the initial config |
|
|
|
|
if ($reconfigure) |
|
|
|
|
{ |
|
|
|
|
my $used_mail_server_count = exists $anvil->data->{mail_servers}{use_order} ? keys %{$anvil->data->{mail_servers}{use_order}} : 0; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { used_mail_server_count => $used_mail_server_count }}); |
|
|
|
|
if (not $used_mail_server_count) |
|
|
|
|
{ |
|
|
|
|
# Just pick the first one. |
|
|
|
|
foreach my $mail_server_uuid (keys %{$anvil->data->{mail_servers}{mail_server}}) |
|
|
|
|
{ |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { mail_server_uuid => $mail_server_uuid }}); |
|
|
|
|
$anvil->Email->_configure_for_server({ |
|
|
|
|
debug => $debug, |
|
|
|
|
mail_server_uuid => $mail_server_uuid, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
last; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -160,25 +200,100 @@ sub check_queue |
|
|
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; |
|
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Email->check_queue()" }}); |
|
|
|
|
|
|
|
|
|
my $oldest_message = 0; |
|
|
|
|
my $oldest_message = 0; |
|
|
|
|
my ($queue, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{postqueue}." -j"}); |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
|
|
|
|
queue => $queue, |
|
|
|
|
return_code => $return_code, |
|
|
|
|
}}); |
|
|
|
|
|
|
|
|
|
### TODO |
|
|
|
|
# If configured/running, the number of messages in queue is checked. If '0', |
|
|
|
|
# 'mail_server::queue_empty' is updated with the current time. If 1 or more, the time since the queue |
|
|
|
|
# was last 0 is checked. If > 300, the mail server is reconfigured to use the mail server with the |
|
|
|
|
# oldest 'mail_server::last_used::<mail_server_uuid>' time. |
|
|
|
|
# This is empty if there is nothing in the queue. |
|
|
|
|
foreach my $email (split/\n/, $queue) |
|
|
|
|
{ |
|
|
|
|
my $json = JSON->new->allow_nonref; |
|
|
|
|
my $postqueueu = $json->decode($email); |
|
|
|
|
my $queue_id = $postqueueu->{queue_id}; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { queue_id => $queue_id }}); |
|
|
|
|
|
|
|
|
|
$anvil->data->{mail}{queue}{$queue_id}{sender} = $postqueueu->{sender}; |
|
|
|
|
$anvil->data->{mail}{queue}{$queue_id}{queue_name} = $postqueueu->{queue_name}; |
|
|
|
|
$anvil->data->{mail}{queue}{$queue_id}{arrival_time} = $postqueueu->{arrival_time}; |
|
|
|
|
$anvil->data->{mail}{queue}{$queue_id}{message_age} = time - $postqueueu->{arrival_time}; |
|
|
|
|
$anvil->data->{mail}{queue}{$queue_id}{message_size} = $postqueueu->{message_size}; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
|
|
|
|
"mail::queue::${queue_id}::sender" => $anvil->data->{mail}{queue}{$queue_id}{sender}, |
|
|
|
|
"mail::queue::${queue_id}::queue_name" => $anvil->data->{mail}{queue}{$queue_id}{queue_name}, |
|
|
|
|
"mail::queue::${queue_id}::arrival_time" => $anvil->data->{mail}{queue}{$queue_id}{arrival_time}, |
|
|
|
|
"mail::queue::${queue_id}::message_age" => $anvil->data->{mail}{queue}{$queue_id}{message_age}, |
|
|
|
|
"mail::queue::${queue_id}::message_size" => $anvil->data->{mail}{queue}{$queue_id}{message_size}, |
|
|
|
|
}}); |
|
|
|
|
foreach my $recipient_hash (@{$postqueueu->{recipients}}) |
|
|
|
|
{ |
|
|
|
|
my $address = $recipient_hash->{address}; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { queue_id => $queue_id }}); |
|
|
|
|
|
|
|
|
|
$anvil->data->{mail}{queue}{$queue_id}{recipient}{$address}{delay_reason} = $recipient_hash->{delay_reason}; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
|
|
|
|
"mail::queue::${queue_id}::recipient::${address}::delay_reason" => $anvil->data->{mail}{queue}{$queue_id}{recipient}{$address}{delay_reason}, |
|
|
|
|
}}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ($anvil->data->{mail}{queue}{$queue_id}{message_age} > $oldest_message) |
|
|
|
|
{ |
|
|
|
|
$oldest_message = $anvil->data->{mail}{queue}{$queue_id}{message_age}; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { oldest_message => $oldest_message }}); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { oldest_message => $oldest_message }}); |
|
|
|
|
return($oldest_message); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
=head2 swap_server |
|
|
|
|
=head2 get_next_server |
|
|
|
|
|
|
|
|
|
When two or more mail servers are configured, this will return the C<< mail_server_uuid >> of the mail server used in the most distant past. If two or more mail servers have never been used before, a random unused server is returned. |
|
|
|
|
|
|
|
|
|
If only one mail servers exists, its UUID is returned, making this method safe to call without concern for configured mail server count. |
|
|
|
|
|
|
|
|
|
This method takes no parameters. |
|
|
|
|
|
|
|
|
|
=cut |
|
|
|
|
sub swap_server |
|
|
|
|
sub get_next_server |
|
|
|
|
{ |
|
|
|
|
my $self = shift; |
|
|
|
|
my $parameter = shift; |
|
|
|
|
my $anvil = $self->parent; |
|
|
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; |
|
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Email->check_queue()" }}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# If configured/running, the number of messages in queue is checked. If '0', |
|
|
|
|
# 'mail_server::queue_empty' is updated with the current time. If 1 or more, the time since the queue |
|
|
|
|
# was last 0 is checked. If > 300, the mail server is reconfigured to use the mail server with the |
|
|
|
|
# oldest 'mail_server::last_used::<mail_server_uuid>' time. |
|
|
|
|
my $oldest_mail_server_time = time; |
|
|
|
|
my $oldest_mail_server_uuid = ""; |
|
|
|
|
foreach my $mail_server_uuid (keys %{$anvil->data->{mail_servers}{mail_server}}) |
|
|
|
|
{ |
|
|
|
|
my $last_used = $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{last_used}; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
|
|
|
|
mail_server_uuid => $mail_server_uuid, |
|
|
|
|
last_used => $last_used, |
|
|
|
|
}}); |
|
|
|
|
|
|
|
|
|
if ($last_used < $oldest_mail_server_time) |
|
|
|
|
{ |
|
|
|
|
$oldest_mail_server_time = $last_used; |
|
|
|
|
$oldest_mail_server_uuid = $mail_server_uuid; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
|
|
|
|
oldest_mail_server_time => $oldest_mail_server_time, |
|
|
|
|
oldest_mail_server_uuid => $oldest_mail_server_uuid, |
|
|
|
|
}}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { oldest_mail_server_uuid => $oldest_mail_server_uuid }}); |
|
|
|
|
return($oldest_mail_server_uuid); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
# =head3 |
|
|
|
@ -248,8 +363,9 @@ sub _configure_for_server |
|
|
|
|
if (-e $anvil->data->{path}{configs}{postfix_relay_password}) |
|
|
|
|
{ |
|
|
|
|
$old_postfix_relay_file = $anvil->Storage->read_file({ |
|
|
|
|
debug => $debug, |
|
|
|
|
file => $anvil->data->{path}{configs}{postfix_relay_password}, |
|
|
|
|
debug => $debug, |
|
|
|
|
secure => 1, |
|
|
|
|
file => $anvil->data->{path}{configs}{postfix_relay_password}, |
|
|
|
|
}); |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { |
|
|
|
|
old_postfix_relay_file => $old_postfix_relay_file, |
|
|
|
@ -257,9 +373,7 @@ sub _configure_for_server |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
my $new_postfix_relay_file = "[".$mail_server_address."]:".$mail_server_port." ".$mail_server_username.":".$mail_server_password."\n"; |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { |
|
|
|
|
new_postfix_relay_file => $new_postfix_relay_file, |
|
|
|
|
}}); |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { new_postfix_relay_file => $new_postfix_relay_file }}); |
|
|
|
|
|
|
|
|
|
if ($new_postfix_relay_file ne $old_postfix_relay_file) |
|
|
|
|
{ |
|
|
|
@ -297,9 +411,7 @@ sub _configure_for_server |
|
|
|
|
debug => $debug, |
|
|
|
|
file => $anvil->data->{path}{configs}{postfix_main}, |
|
|
|
|
}); |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
|
|
|
|
old_postfix_relay_file => $old_postfix_relay_file, |
|
|
|
|
}}); |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_postfix_relay_file => $old_postfix_relay_file }}); |
|
|
|
|
|
|
|
|
|
my $last_line = ""; |
|
|
|
|
my $relayhost_seen = 0; |
|
|
|
@ -678,7 +790,6 @@ sub _configure_for_server |
|
|
|
|
user => "root", |
|
|
|
|
group => "root", |
|
|
|
|
overwrite => 1, |
|
|
|
|
secure => 1, |
|
|
|
|
}); |
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
|
|
|
|
reload => $reload, |
|
|
|
|