git-send-email: add option to specify sendmail command
The sendemail.smtpServer configuration option and --smtp-server command line option both support using a sendmail-like program to send emails by specifying an absolute file path. However, this is not ideal for the following reasons: 1. It overloads the meaning of smtpServer (now a program is being used for the server?) 2. It doesn't allow for non-absolute paths, arguments, or arbitrary scripting Requiring an absolute path is bad for portability, as the same program may be in different locations on different systems. If a user wishes to pass arguments to their program, they have to use the smtpServerOption option, which is cumbersome (as it must be repeated for each option) and doesn't adhere to normal git conventions. Introduce a new configuration option sendemail.sendmailCmd as well as a command line option --sendmail-cmd that can be used to specify a command (with or without arguments) or shell expression to run to send email. The name of this option is consistent with --to-cmd and --cc-cmd. This invocation honors the user's $PATH so that absolute paths are not necessary. Arbitrary shell expressions are also supported, allowing users to do basic scripting. Give this option a higher precedence over --smtp-server and sendemail.smtpServer, as the new interface is more flexible. For backward compatibility, continue to support absolute paths in --smtp-server and sendemail.smtpServer. Signed-off-by: Gregory Anders <greg@gpanders.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
48bf2fa8ba
commit
cd5b33fbdc
@ -167,6 +167,14 @@ Sending
|
|||||||
`sendemail.envelopeSender` configuration variable; if that is
|
`sendemail.envelopeSender` configuration variable; if that is
|
||||||
unspecified, choosing the envelope sender is left to your MTA.
|
unspecified, choosing the envelope sender is left to your MTA.
|
||||||
|
|
||||||
|
--sendmail-cmd=<command>::
|
||||||
|
Specify a command to run to send the email. The command should
|
||||||
|
be sendmail-like; specifically, it must support the `-i` option.
|
||||||
|
The command will be executed in the shell if necessary. Default
|
||||||
|
is the value of `sendemail.sendmailcmd`. If unspecified, and if
|
||||||
|
--smtp-server is also unspecified, git-send-email will search
|
||||||
|
for `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH.
|
||||||
|
|
||||||
--smtp-encryption=<encryption>::
|
--smtp-encryption=<encryption>::
|
||||||
Specify the encryption to use, either 'ssl' or 'tls'. Any other
|
Specify the encryption to use, either 'ssl' or 'tls'. Any other
|
||||||
value reverts to plain SMTP. Default is the value of
|
value reverts to plain SMTP. Default is the value of
|
||||||
@ -211,13 +219,16 @@ a password is obtained using 'git-credential'.
|
|||||||
|
|
||||||
--smtp-server=<host>::
|
--smtp-server=<host>::
|
||||||
If set, specifies the outgoing SMTP server to use (e.g.
|
If set, specifies the outgoing SMTP server to use (e.g.
|
||||||
`smtp.example.com` or a raw IP address). Alternatively it can
|
`smtp.example.com` or a raw IP address). If unspecified, and if
|
||||||
specify a full pathname of a sendmail-like program instead;
|
`--sendmail-cmd` is also unspecified, the default is to search
|
||||||
the program must support the `-i` option. Default value can
|
for `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH if such a
|
||||||
be specified by the `sendemail.smtpServer` configuration
|
program is available, falling back to `localhost` otherwise.
|
||||||
option; the built-in default is to search for `sendmail` in
|
+
|
||||||
`/usr/sbin`, `/usr/lib` and $PATH if such program is
|
For backward compatibility, this option can also specify a full pathname
|
||||||
available, falling back to `localhost` otherwise.
|
of a sendmail-like program instead; the program must support the `-i`
|
||||||
|
option. This method does not support passing arguments or using plain
|
||||||
|
command names. For those use cases, consider using `--sendmail-cmd`
|
||||||
|
instead.
|
||||||
|
|
||||||
--smtp-server-port=<port>::
|
--smtp-server-port=<port>::
|
||||||
Specifies a port different from the default port (SMTP
|
Specifies a port different from the default port (SMTP
|
||||||
|
@ -70,6 +70,7 @@ git send-email --dump-aliases
|
|||||||
|
|
||||||
Sending:
|
Sending:
|
||||||
--envelope-sender <str> * Email envelope sender.
|
--envelope-sender <str> * Email envelope sender.
|
||||||
|
--sendmail-cmd <str> * Command to run to send email.
|
||||||
--smtp-server <str:int> * Outgoing SMTP server to use. The port
|
--smtp-server <str:int> * Outgoing SMTP server to use. The port
|
||||||
is optional. Default 'localhost'.
|
is optional. Default 'localhost'.
|
||||||
--smtp-server-option <str> * Outgoing SMTP server option to use.
|
--smtp-server-option <str> * Outgoing SMTP server option to use.
|
||||||
@ -243,6 +244,7 @@ my ($confirm);
|
|||||||
my (@suppress_cc);
|
my (@suppress_cc);
|
||||||
my ($auto_8bit_encoding);
|
my ($auto_8bit_encoding);
|
||||||
my ($compose_encoding);
|
my ($compose_encoding);
|
||||||
|
my ($sendmail_cmd);
|
||||||
# Variables with corresponding config settings & hardcoded defaults
|
# Variables with corresponding config settings & hardcoded defaults
|
||||||
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
|
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
|
||||||
my $thread = 1;
|
my $thread = 1;
|
||||||
@ -290,6 +292,7 @@ my %config_settings = (
|
|||||||
"assume8bitencoding" => \$auto_8bit_encoding,
|
"assume8bitencoding" => \$auto_8bit_encoding,
|
||||||
"composeencoding" => \$compose_encoding,
|
"composeencoding" => \$compose_encoding,
|
||||||
"transferencoding" => \$target_xfer_encoding,
|
"transferencoding" => \$target_xfer_encoding,
|
||||||
|
"sendmailcmd" => \$sendmail_cmd,
|
||||||
);
|
);
|
||||||
|
|
||||||
my %config_path_settings = (
|
my %config_path_settings = (
|
||||||
@ -423,6 +426,7 @@ $rc = GetOptions(
|
|||||||
"no-bcc" => \$no_bcc,
|
"no-bcc" => \$no_bcc,
|
||||||
"chain-reply-to!" => \$chain_reply_to,
|
"chain-reply-to!" => \$chain_reply_to,
|
||||||
"no-chain-reply-to" => sub {$chain_reply_to = 0},
|
"no-chain-reply-to" => sub {$chain_reply_to = 0},
|
||||||
|
"sendmail-cmd=s" => \$sendmail_cmd,
|
||||||
"smtp-server=s" => \$smtp_server,
|
"smtp-server=s" => \$smtp_server,
|
||||||
"smtp-server-option=s" => \@smtp_server_options,
|
"smtp-server-option=s" => \@smtp_server_options,
|
||||||
"smtp-server-port=s" => \$smtp_server_port,
|
"smtp-server-port=s" => \$smtp_server_port,
|
||||||
@ -996,16 +1000,19 @@ if (defined $reply_to) {
|
|||||||
$reply_to = sanitize_address($reply_to);
|
$reply_to = sanitize_address($reply_to);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defined $smtp_server) {
|
if (!defined $sendmail_cmd && !defined $smtp_server) {
|
||||||
my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );
|
my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );
|
||||||
push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH};
|
push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH};
|
||||||
foreach (@sendmail_paths) {
|
foreach (@sendmail_paths) {
|
||||||
if (-x $_) {
|
if (-x $_) {
|
||||||
$smtp_server = $_;
|
$sendmail_cmd = $_;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*
|
|
||||||
|
if (!defined $sendmail_cmd) {
|
||||||
|
$smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($compose && $compose > 0) {
|
if ($compose && $compose > 0) {
|
||||||
@ -1485,11 +1492,17 @@ EOF
|
|||||||
|
|
||||||
if ($dry_run) {
|
if ($dry_run) {
|
||||||
# We don't want to send the email.
|
# We don't want to send the email.
|
||||||
} elsif (file_name_is_absolute($smtp_server)) {
|
} elsif (defined $sendmail_cmd || file_name_is_absolute($smtp_server)) {
|
||||||
my $pid = open my $sm, '|-';
|
my $pid = open my $sm, '|-';
|
||||||
defined $pid or die $!;
|
defined $pid or die $!;
|
||||||
if (!$pid) {
|
if (!$pid) {
|
||||||
exec($smtp_server, @sendmail_parameters) or die $!;
|
if (defined $sendmail_cmd) {
|
||||||
|
exec ("sh", "-c", "$sendmail_cmd \"\$@\"", "-", @sendmail_parameters)
|
||||||
|
or die $!;
|
||||||
|
} else {
|
||||||
|
exec ($smtp_server, @sendmail_parameters)
|
||||||
|
or die $!;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
print $sm "$header\n$message";
|
print $sm "$header\n$message";
|
||||||
close $sm or die $!;
|
close $sm or die $!;
|
||||||
@ -1585,14 +1598,21 @@ EOF
|
|||||||
printf($dry_run ? __("Dry-Sent %s\n") : __("Sent %s\n"), $subject);
|
printf($dry_run ? __("Dry-Sent %s\n") : __("Sent %s\n"), $subject);
|
||||||
} else {
|
} else {
|
||||||
print($dry_run ? __("Dry-OK. Log says:\n") : __("OK. Log says:\n"));
|
print($dry_run ? __("Dry-OK. Log says:\n") : __("OK. Log says:\n"));
|
||||||
if (!file_name_is_absolute($smtp_server)) {
|
if (!defined $sendmail_cmd && !file_name_is_absolute($smtp_server)) {
|
||||||
print "Server: $smtp_server\n";
|
print "Server: $smtp_server\n";
|
||||||
print "MAIL FROM:<$raw_from>\n";
|
print "MAIL FROM:<$raw_from>\n";
|
||||||
foreach my $entry (@recipients) {
|
foreach my $entry (@recipients) {
|
||||||
print "RCPT TO:<$entry>\n";
|
print "RCPT TO:<$entry>\n";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n";
|
my $sm;
|
||||||
|
if (defined $sendmail_cmd) {
|
||||||
|
$sm = $sendmail_cmd;
|
||||||
|
} else {
|
||||||
|
$sm = $smtp_server;
|
||||||
|
}
|
||||||
|
|
||||||
|
print "Sendmail: $sm ".join(' ',@sendmail_parameters)."\n";
|
||||||
}
|
}
|
||||||
print $header, "\n";
|
print $header, "\n";
|
||||||
if ($smtp) {
|
if ($smtp) {
|
||||||
|
@ -2097,6 +2097,37 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '
|
|||||||
test_cmp expected-list actual-list
|
test_cmp expected-list actual-list
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '
|
||||||
|
clean_fake_sendmail &&
|
||||||
|
PATH="$(pwd):$PATH" \
|
||||||
|
git send-email \
|
||||||
|
--from="Example <nobody@example.com>" \
|
||||||
|
--to=nobody@example.com \
|
||||||
|
--sendmail-cmd="fake.sendmail" \
|
||||||
|
HEAD^ &&
|
||||||
|
test_path_is_file commandline1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ 'test using arguments with --sendmail-cmd' '
|
||||||
|
clean_fake_sendmail &&
|
||||||
|
git send-email \
|
||||||
|
--from="Example <nobody@example.com>" \
|
||||||
|
--to=nobody@example.com \
|
||||||
|
--sendmail-cmd='\''"$(pwd)/fake.sendmail" -f nobody@example.com'\'' \
|
||||||
|
HEAD^ &&
|
||||||
|
test_path_is_file commandline1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success $PREREQ 'test shell expression with --sendmail-cmd' '
|
||||||
|
clean_fake_sendmail &&
|
||||||
|
git send-email \
|
||||||
|
--from="Example <nobody@example.com>" \
|
||||||
|
--to=nobody@example.com \
|
||||||
|
--sendmail-cmd='\''f() { "$(pwd)/fake.sendmail" "$@"; };f'\'' \
|
||||||
|
HEAD^ &&
|
||||||
|
test_path_is_file commandline1
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success $PREREQ 'invoke hook' '
|
test_expect_success $PREREQ 'invoke hook' '
|
||||||
mkdir -p .git/hooks &&
|
mkdir -p .git/hooks &&
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user