send-email: --batch-size to work around some SMTP server limit

Some email servers (e.g. smtp.163.com) limit the number emails to be
sent per session (connection) and this will lead to a faliure when
sending many messages.

Teach send-email to disconnect after sending a number of messages
(configurable via the --batch-size=<num> option), wait for a few
seconds (configurable via the --relogin-delay=<seconds> option) and
reconnect, to work around such a limit.

Also add two configuration variables to give these options the default.

Note:

  We will use this as a band-aid for now, but in the longer term, we
  should look at and react to the SMTP error code from the server;
  Xianqiang reports that 450 and 451 are returned by problematic
  servers.

  cf. https://public-inbox.org/git/7993e188.d18d.15c3560bcaf.Coremail.zxq_yx_007@163.com/

Signed-off-by: xiaoqiang zhao <zxq_yx_007@163.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
xiaoqiang zhao 2017-05-21 20:59:50 +08:00 committed by Junio C Hamano
parent b06d364310
commit 5453b83bdf
4 changed files with 45 additions and 0 deletions

View File

@ -2914,6 +2914,16 @@ sendemail.xmailer::
sendemail.signedoffcc (deprecated):: sendemail.signedoffcc (deprecated)::
Deprecated alias for `sendemail.signedoffbycc`. Deprecated alias for `sendemail.signedoffbycc`.
sendemail.smtpBatchSize::
Number of messages to be sent per connection, after that a relogin
will happen. If the value is 0 or undefined, send all messages in
one connection.
See also the `--batch-size` option of linkgit:git-send-email[1].
sendemail.smtpReloginDelay::
Seconds wait before reconnecting to smtp server.
See also the `--relogin-delay` option of linkgit:git-send-email[1].
showbranch.default:: showbranch.default::
The default set of branches for linkgit:git-show-branch[1]. The default set of branches for linkgit:git-show-branch[1].
See linkgit:git-show-branch[1]. See linkgit:git-show-branch[1].

View File

@ -248,6 +248,21 @@ must be used for each option.
commands and replies will be printed. Useful to debug TLS commands and replies will be printed. Useful to debug TLS
connection and authentication problems. connection and authentication problems.
--batch-size=<num>::
Some email servers (e.g. smtp.163.com) limit the number emails to be
sent per session (connection) and this will lead to a faliure when
sending many messages. With this option, send-email will disconnect after
sending $<num> messages and wait for a few seconds (see --relogin-delay)
and reconnect, to work around such a limit. You may want to
use some form of credential helper to avoid having to retype
your password every time this happens. Defaults to the
`sendemail.smtpBatchSize` configuration variable.
--relogin-delay=<int>::
Waiting $<int> seconds before reconnecting to SMTP server. Used together
with --batch-size option. Defaults to the `sendemail.smtpReloginDelay`
configuration variable.
Automating Automating
~~~~~~~~~~ ~~~~~~~~~~

View File

@ -2608,6 +2608,8 @@ _git_config ()
sendemail.thread sendemail.thread
sendemail.to sendemail.to
sendemail.validate sendemail.validate
sendemail.smtpbatchsize
sendemail.smtprelogindelay
showbranch.default showbranch.default
status.relativePaths status.relativePaths
status.showUntrackedFiles status.showUntrackedFiles

View File

@ -81,6 +81,10 @@ git send-email --dump-aliases
This setting forces to use one of the listed mechanisms. This setting forces to use one of the listed mechanisms.
--smtp-debug <0|1> * Disable, enable Net::SMTP debug. --smtp-debug <0|1> * Disable, enable Net::SMTP debug.
--batch-size <int> * send max <int> message per connection.
--relogin-delay <int> * delay <int> seconds between two successive login.
This option can only be used with --batch-size
Automating: Automating:
--identity <str> * Use the sendemail.<id> options. --identity <str> * Use the sendemail.<id> options.
--to-cmd <str> * Email To: via `<str> \$patch_path` --to-cmd <str> * Email To: via `<str> \$patch_path`
@ -153,6 +157,7 @@ my $have_email_valid = eval { require Email::Valid; 1 };
my $have_mail_address = eval { require Mail::Address; 1 }; my $have_mail_address = eval { require Mail::Address; 1 };
my $smtp; my $smtp;
my $auth; my $auth;
my $num_sent = 0;
# Regexes for RFC 2047 productions. # Regexes for RFC 2047 productions.
my $re_token = qr/[^][()<>@,;:\\"\/?.= \000-\037\177-\377]+/; my $re_token = qr/[^][()<>@,;:\\"\/?.= \000-\037\177-\377]+/;
@ -216,6 +221,7 @@ my ($cover_cc, $cover_to);
my ($to_cmd, $cc_cmd); my ($to_cmd, $cc_cmd);
my ($smtp_server, $smtp_server_port, @smtp_server_options); my ($smtp_server, $smtp_server_port, @smtp_server_options);
my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path); my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
my ($batch_size, $relogin_delay);
my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth); my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
my ($validate, $confirm); my ($validate, $confirm);
my (@suppress_cc); my (@suppress_cc);
@ -247,6 +253,8 @@ my %config_settings = (
"smtppass" => \$smtp_authpass, "smtppass" => \$smtp_authpass,
"smtpdomain" => \$smtp_domain, "smtpdomain" => \$smtp_domain,
"smtpauth" => \$smtp_auth, "smtpauth" => \$smtp_auth,
"smtpbatchsize" => \$batch_size,
"smtprelogindelay" => \$relogin_delay,
"to" => \@initial_to, "to" => \@initial_to,
"tocmd" => \$to_cmd, "tocmd" => \$to_cmd,
"cc" => \@initial_cc, "cc" => \@initial_cc,
@ -358,6 +366,8 @@ $rc = GetOptions(
"force" => \$force, "force" => \$force,
"xmailer!" => \$use_xmailer, "xmailer!" => \$use_xmailer,
"no-xmailer" => sub {$use_xmailer = 0}, "no-xmailer" => sub {$use_xmailer = 0},
"batch-size=i" => \$batch_size,
"relogin-delay=i" => \$relogin_delay,
); );
usage() if $help; usage() if $help;
@ -1664,6 +1674,14 @@ foreach my $t (@files) {
} }
} }
$message_id = undef; $message_id = undef;
$num_sent++;
if (defined $batch_size && $num_sent == $batch_size) {
$num_sent = 0;
$smtp->quit if defined $smtp;
undef $smtp;
undef $auth;
sleep($relogin_delay) if defined $relogin_delay;
}
} }
# Execute a command (e.g. $to_cmd) to get a list of email addresses # Execute a command (e.g. $to_cmd) to get a list of email addresses