Skip to content

Commit cd5b33f

Browse files
gpandersgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 48bf2fa commit cd5b33f

File tree

3 files changed

+76
-14
lines changed

3 files changed

+76
-14
lines changed

Documentation/git-send-email.txt

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,14 @@ Sending
167167
`sendemail.envelopeSender` configuration variable; if that is
168168
unspecified, choosing the envelope sender is left to your MTA.
169169

170+
--sendmail-cmd=<command>::
171+
Specify a command to run to send the email. The command should
172+
be sendmail-like; specifically, it must support the `-i` option.
173+
The command will be executed in the shell if necessary. Default
174+
is the value of `sendemail.sendmailcmd`. If unspecified, and if
175+
--smtp-server is also unspecified, git-send-email will search
176+
for `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH.
177+
170178
--smtp-encryption=<encryption>::
171179
Specify the encryption to use, either 'ssl' or 'tls'. Any other
172180
value reverts to plain SMTP. Default is the value of
@@ -211,13 +219,16 @@ a password is obtained using 'git-credential'.
211219

212220
--smtp-server=<host>::
213221
If set, specifies the outgoing SMTP server to use (e.g.
214-
`smtp.example.com` or a raw IP address). Alternatively it can
215-
specify a full pathname of a sendmail-like program instead;
216-
the program must support the `-i` option. Default value can
217-
be specified by the `sendemail.smtpServer` configuration
218-
option; the built-in default is to search for `sendmail` in
219-
`/usr/sbin`, `/usr/lib` and $PATH if such program is
220-
available, falling back to `localhost` otherwise.
222+
`smtp.example.com` or a raw IP address). If unspecified, and if
223+
`--sendmail-cmd` is also unspecified, the default is to search
224+
for `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH if such a
225+
program is available, falling back to `localhost` otherwise.
226+
+
227+
For backward compatibility, this option can also specify a full pathname
228+
of a sendmail-like program instead; the program must support the `-i`
229+
option. This method does not support passing arguments or using plain
230+
command names. For those use cases, consider using `--sendmail-cmd`
231+
instead.
221232

222233
--smtp-server-port=<port>::
223234
Specifies a port different from the default port (SMTP

git-send-email.perl

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ sub usage {
7070
7171
Sending:
7272
--envelope-sender <str> * Email envelope sender.
73+
--sendmail-cmd <str> * Command to run to send email.
7374
--smtp-server <str:int> * Outgoing SMTP server to use. The port
7475
is optional. Default 'localhost'.
7576
--smtp-server-option <str> * Outgoing SMTP server option to use.
@@ -243,6 +244,7 @@ sub do_edit {
243244
my (@suppress_cc);
244245
my ($auto_8bit_encoding);
245246
my ($compose_encoding);
247+
my ($sendmail_cmd);
246248
# Variables with corresponding config settings & hardcoded defaults
247249
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
248250
my $thread = 1;
@@ -290,6 +292,7 @@ sub do_edit {
290292
"assume8bitencoding" => \$auto_8bit_encoding,
291293
"composeencoding" => \$compose_encoding,
292294
"transferencoding" => \$target_xfer_encoding,
295+
"sendmailcmd" => \$sendmail_cmd,
293296
);
294297

295298
my %config_path_settings = (
@@ -423,6 +426,7 @@ sub read_config {
423426
"no-bcc" => \$no_bcc,
424427
"chain-reply-to!" => \$chain_reply_to,
425428
"no-chain-reply-to" => sub {$chain_reply_to = 0},
429+
"sendmail-cmd=s" => \$sendmail_cmd,
426430
"smtp-server=s" => \$smtp_server,
427431
"smtp-server-option=s" => \@smtp_server_options,
428432
"smtp-server-port=s" => \$smtp_server_port,
@@ -996,16 +1000,19 @@ sub expand_one_alias {
9961000
$reply_to = sanitize_address($reply_to);
9971001
}
9981002

999-
if (!defined $smtp_server) {
1003+
if (!defined $sendmail_cmd && !defined $smtp_server) {
10001004
my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );
10011005
push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH};
10021006
foreach (@sendmail_paths) {
10031007
if (-x $_) {
1004-
$smtp_server = $_;
1008+
$sendmail_cmd = $_;
10051009
last;
10061010
}
10071011
}
1008-
$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*
1012+
1013+
if (!defined $sendmail_cmd) {
1014+
$smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*
1015+
}
10091016
}
10101017

10111018
if ($compose && $compose > 0) {
@@ -1485,11 +1492,17 @@ sub send_message {
14851492

14861493
if ($dry_run) {
14871494
# We don't want to send the email.
1488-
} elsif (file_name_is_absolute($smtp_server)) {
1495+
} elsif (defined $sendmail_cmd || file_name_is_absolute($smtp_server)) {
14891496
my $pid = open my $sm, '|-';
14901497
defined $pid or die $!;
14911498
if (!$pid) {
1492-
exec($smtp_server, @sendmail_parameters) or die $!;
1499+
if (defined $sendmail_cmd) {
1500+
exec ("sh", "-c", "$sendmail_cmd \"\$@\"", "-", @sendmail_parameters)
1501+
or die $!;
1502+
} else {
1503+
exec ($smtp_server, @sendmail_parameters)
1504+
or die $!;
1505+
}
14931506
}
14941507
print $sm "$header\n$message";
14951508
close $sm or die $!;
@@ -1585,14 +1598,21 @@ sub send_message {
15851598
printf($dry_run ? __("Dry-Sent %s\n") : __("Sent %s\n"), $subject);
15861599
} else {
15871600
print($dry_run ? __("Dry-OK. Log says:\n") : __("OK. Log says:\n"));
1588-
if (!file_name_is_absolute($smtp_server)) {
1601+
if (!defined $sendmail_cmd && !file_name_is_absolute($smtp_server)) {
15891602
print "Server: $smtp_server\n";
15901603
print "MAIL FROM:<$raw_from>\n";
15911604
foreach my $entry (@recipients) {
15921605
print "RCPT TO:<$entry>\n";
15931606
}
15941607
} else {
1595-
print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n";
1608+
my $sm;
1609+
if (defined $sendmail_cmd) {
1610+
$sm = $sendmail_cmd;
1611+
} else {
1612+
$sm = $smtp_server;
1613+
}
1614+
1615+
print "Sendmail: $sm ".join(' ',@sendmail_parameters)."\n";
15961616
}
15971617
print $header, "\n";
15981618
if ($smtp) {

t/t9001-send-email.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2097,6 +2097,37 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '
20972097
test_cmp expected-list actual-list
20982098
'
20992099

2100+
test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '
2101+
clean_fake_sendmail &&
2102+
PATH="$(pwd):$PATH" \
2103+
git send-email \
2104+
--from="Example <[email protected]>" \
2105+
2106+
--sendmail-cmd="fake.sendmail" \
2107+
HEAD^ &&
2108+
test_path_is_file commandline1
2109+
'
2110+
2111+
test_expect_success $PREREQ 'test using arguments with --sendmail-cmd' '
2112+
clean_fake_sendmail &&
2113+
git send-email \
2114+
--from="Example <[email protected]>" \
2115+
2116+
--sendmail-cmd='\''"$(pwd)/fake.sendmail" -f [email protected]'\'' \
2117+
HEAD^ &&
2118+
test_path_is_file commandline1
2119+
'
2120+
2121+
test_expect_success $PREREQ 'test shell expression with --sendmail-cmd' '
2122+
clean_fake_sendmail &&
2123+
git send-email \
2124+
--from="Example <[email protected]>" \
2125+
2126+
--sendmail-cmd='\''f() { "$(pwd)/fake.sendmail" "$@"; };f'\'' \
2127+
HEAD^ &&
2128+
test_path_is_file commandline1
2129+
'
2130+
21002131
test_expect_success $PREREQ 'invoke hook' '
21012132
mkdir -p .git/hooks &&
21022133

0 commit comments

Comments
 (0)