{"thread":{"id":"55668","subject":"[PATCH] git-send-email: add sendmailCommand option","startedAt":"2021-05-12T03:31:34Z","lastAt":"2021-05-14T15:16:19Z","messageCount":19,"participants":["Gregory Anders","Junio C Hamano","Felipe Contreras","Ævar Arnfjörð Bjarmason"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"424270","messageId":"20210512033039.4022-1-greg@gpanders.com","threadId":"55668","inReplyTo":null,"subject":"[PATCH] git-send-email: add sendmailCommand option","fromName":"Gregory Anders","fromEmail":"greg@gpanders.com","sentAt":"2021-05-12T03:30:40Z","receivedAt":"2021-05-12T03:31:34Z","isPatch":true,"sender":{"key":"greg@gpanders.com","avatar":"https://avatars.githubusercontent.com/u/8965202?v=4"},"body":"The sendemail.smtpServer option currently supports using a sendmail-like\nprogram to send emails by specifying an absolute file path. However,\nthis is not ideal for the following reasons:\n\n1. It overloads the meaning of smtpServer (now a program is being used\n   for the server?)\n2. It doesn't allow for non-absolute paths, arguments, or arbitrary\n   scripting.\n\nRequiring an absolute path is bad for portability, as the same\nprogram may be in different locations on different systems. If I wish\nto pass arguments to my program, I have to use the smtpServerOption\noption, which is cumbersome (as it must be repeated for each option)\nand doesn't adhere to normal git conventions.\n\nThis patch attempts to solve these problems by introducing a new\nconfiguration option sendemail.sendmailCommand as well as a command line\noption --sendmail-cmd. The value of this option is invoked with the\nstandard sendmail options passed as arguments.\n\nsendmailCommand has precedence over smtpServer. If both options are\nunspecified, the default is to search for 'sendmail' in /usr/sbin,\n/usr/lib, and $PATH. If not found, smtpServer is set to localhost. This\nmimics the current behavior when smtpServer is unspecified.\n\nThe option is passed to Perl's `exec()` function, which automatically\ndetermines whether or not to invoke a shell. If shell metacharacters are\ndetected, then a shell is used; otherwise, the command is invoked\ndirectly. This means that e.g.\n\n    [sendemail]\n            sendmailCommand = f() { if [ \"$(uname -s) = Darwin ]; then sendmail \"$@\"; else postfix \"$@\"; fi; };f\n\nwill be executed in a shell (as expected), while\n\n    [sendemail]\n            sendmailCommand = msmtp\n\nwill be executed directly.\n\nThis change deprecates the use of absolute paths in \nsendemail.smtpServer, although support is kept for backward\ncompatibility.\n---\n\nNote that this patch is incompatible with (and supersedes) the patch\ndiscussed here: \n\n    https://public-inbox.org/git/YJs2RceLliGHI5TX@gpanders.com/T/#t\n\n Documentation/git-send-email.txt |  39 ++++---\n git-send-email.perl              |  30 ++++--\n t/t9001-send-email.sh            | 169 ++++++++++++++++++-------------\n 3 files changed, 140 insertions(+), 98 deletions(-)\n\ndiff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\nindex 93708aefea..d9fe8cb7c0 100644\n--- a/Documentation/git-send-email.txt\n+++ b/Documentation/git-send-email.txt\n@@ -159,13 +159,23 @@ Sending\n ~~~~~~~\n \n --envelope-sender=<address>::\n-\tSpecify the envelope sender used to send the emails.\n-\tThis is useful if your default address is not the address that is\n-\tsubscribed to a list. In order to use the 'From' address, set the\n-\tvalue to \"auto\". If you use the sendmail binary, you must have\n-\tsuitable privileges for the -f parameter.  Default is the value of the\n-\t`sendemail.envelopeSender` configuration variable; if that is\n-\tunspecified, choosing the envelope sender is left to your MTA.\n+\tSpecify the envelope sender used to send the emails.  This is\n+\tuseful if your default address is not the address that is\n+\tsubscribed to a list. In order to use the 'From' address, set\n+\tthe value to \"auto\". If you use the sendmail binary, you must\n+\thave suitable privileges for the -f parameter.  Default is the\n+\tvalue of the `sendemail.envelopeSender` configuration variable;\n+\tif that is unspecified, choosing the envelope sender is left to\n+\tyour MTA.\n+\n+--sendmail-cmd=<command>::\n+\tSpecify a command to run to send the email. The command should\n+\tbe compatible with `sendmail` as the arguments are passed\n+\tdirectly.  The command will be executed in the shell if\n+\tnecessary.  Default is the value of `sendemail.sendmailCommand`.\n+\tIf unspecified, and if --smtp-server is also unspecified,\n+\tgit-send-email will search for `sendmail` in `/usr/sbin`,\n+\t`/usr/lib` and $PATH if such a program is available.\n \n --smtp-encryption=<encryption>::\n \tSpecify the encryption to use, either 'ssl' or 'tls'.  Any other\n@@ -211,13 +221,14 @@ a password is obtained using 'git-credential'.\n \n --smtp-server=<host>::\n \tIf set, specifies the outgoing SMTP server to use (e.g.\n-\t`smtp.example.com` or a raw IP address).  Alternatively it can\n-\tspecify a full pathname of a sendmail-like program instead;\n-\tthe program must support the `-i` option.  Default value can\n-\tbe specified by the `sendemail.smtpServer` configuration\n-\toption; the built-in default is to search for `sendmail` in\n-\t`/usr/sbin`, `/usr/lib` and $PATH if such program is\n-\tavailable, falling back to `localhost` otherwise.\n+\t`smtp.example.com` or a raw IP address).  If unspecified, and if\n+\t`--sendmail-cmd` is also unspecified, the default is to search\n+\tfor `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH if such a\n+\tprogram is available, falling back to `localhost` otherwise.\n+\n+\tFor backward compatibility, this option can also specify a full\n+\tpathname of a sendmail-like program instead; the program must\n+\tsupport the `-i` option.  Prefer using `--sendmail-cmd` instead.\n \n --smtp-server-port=<port>::\n \tSpecifies a port different from the default port (SMTP\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 175da07d94..cecca03ed1 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -70,6 +70,7 @@ sub usage {\n \n   Sending:\n     --envelope-sender       <str>  * Email envelope sender.\n+    --sendmail-cmd          <str>  * Shell command to run to send email.\n     --smtp-server       <str:int>  * Outgoing SMTP server to use. The port\n                                      is optional. Default 'localhost'.\n     --smtp-server-option    <str>  * Outgoing SMTP server option to use.\n@@ -252,6 +253,7 @@ sub do_edit {\n my (@suppress_cc);\n my ($auto_8bit_encoding);\n my ($compose_encoding);\n+my ($sendmail_command);\n # Variables with corresponding config settings & hardcoded defaults\n my ($debug_net_smtp) = 0;\t\t# Net::SMTP, see send_message()\n my $thread = 1;\n@@ -299,6 +301,7 @@ sub do_edit {\n     \"assume8bitencoding\" => \\$auto_8bit_encoding,\n     \"composeencoding\" => \\$compose_encoding,\n     \"transferencoding\" => \\$target_xfer_encoding,\n+    \"sendmailcommand\" => \\$sendmail_command,\n );\n \n my %config_path_settings = (\n@@ -432,6 +435,7 @@ sub read_config {\n \t\t    \"no-bcc\" => \\$no_bcc,\n \t\t    \"chain-reply-to!\" => \\$chain_reply_to,\n \t\t    \"no-chain-reply-to\" => sub {$chain_reply_to = 0},\n+\t\t    \"sendmail-cmd=s\" => \\$sendmail_command,\n \t\t    \"smtp-server=s\" => \\$smtp_server,\n \t\t    \"smtp-server-option=s\" => \\@smtp_server_options,\n \t\t    \"smtp-server-port=s\" => \\$smtp_server_port,\n@@ -1008,11 +1012,14 @@ sub expand_one_alias {\n \tpush @sendmail_paths, map {\"$_/sendmail\"} split /:/, $ENV{PATH};\n \tforeach (@sendmail_paths) {\n \t\tif (-x $_) {\n-\t\t\t$smtp_server = $_;\n+\t\t\t$sendmail_command ||= $_;\n \t\t\tlast;\n \t\t}\n \t}\n-\t$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*\n+\n+\tif (!defined $sendmail_command) {\n+\t\t$smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*\n+\t}\n }\n \n if ($compose && $compose > 0) {\n@@ -1490,14 +1497,15 @@ sub send_message {\n \n \tunshift (@sendmail_parameters, @smtp_server_options);\n \n+\tif (file_name_is_absolute($smtp_server)) {\n+\t\t# Preserved for backward compatibility\n+\t\t$sendmail_command ||= $smtp_server;\n+\t}\n+\n \tif ($dry_run) {\n \t\t# We don't want to send the email.\n-\t} elsif (file_name_is_absolute($smtp_server)) {\n-\t\tmy $pid = open my $sm, '|-';\n-\t\tdefined $pid or die $!;\n-\t\tif (!$pid) {\n-\t\t\texec($smtp_server, @sendmail_parameters) or die $!;\n-\t\t}\n+\t} elsif (defined $sendmail_command) {\n+\t\topen my $sm, '|-', \"$sendmail_command @sendmail_parameters\";\n \t\tprint $sm \"$header\\n$message\";\n \t\tclose $sm or die $!;\n \t} else {\n@@ -1592,14 +1600,14 @@ sub send_message {\n \t\tprintf($dry_run ? __(\"Dry-Sent %s\\n\") : __(\"Sent %s\\n\"), $subject);\n \t} else {\n \t\tprint($dry_run ? __(\"Dry-OK. Log says:\\n\") : __(\"OK. Log says:\\n\"));\n-\t\tif (!file_name_is_absolute($smtp_server)) {\n+\t\tif (defined $sendmail_command) {\n+\t\t\tprint \"Sendmail: $sendmail_command \".join(' ',@sendmail_parameters).\"\\n\";\n+\t\t} else {\n \t\t\tprint \"Server: $smtp_server\\n\";\n \t\t\tprint \"MAIL FROM:<$raw_from>\\n\";\n \t\t\tforeach my $entry (@recipients) {\n \t\t\t    print \"RCPT TO:<$entry>\\n\";\n \t\t\t}\n-\t\t} else {\n-\t\t\tprint \"Sendmail: $smtp_server \".join(' ',@sendmail_parameters).\"\\n\";\n \t\t}\n \t\tprint $header, \"\\n\";\n \t\tif ($smtp) {\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 65b3035371..82a3efb987 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -57,7 +57,7 @@ test_no_confirm () {\n \t\tgit send-email \\\n \t\t--from=\"Example <from@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$@ \\\n \t\t$patches >stdout &&\n \t\t! grep \"Send this email\" stdout &&\n@@ -94,7 +94,7 @@ test_expect_success $PREREQ 'No confirm with sendemail.confirm=never' '\n '\n \n test_expect_success $PREREQ 'Send patches' '\n-\tgit send-email --suppress-cc=sob --from=\"Example <nobody@example.com>\" --to=nobody@example.com --smtp-server=\"$(pwd)/fake.sendmail\" $patches 2>errors\n+\tgit send-email --suppress-cc=sob --from=\"Example <nobody@example.com>\" --to=nobody@example.com --sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" $patches 2>errors\n '\n \n test_expect_success $PREREQ 'setup expect' '\n@@ -112,7 +112,7 @@ test_expect_success $PREREQ 'Verify commandline' '\n \n test_expect_success $PREREQ 'Send patches with --envelope-sender' '\n \tclean_fake_sendmail &&\n-\tgit send-email --envelope-sender=\"Patch Contributor <patch@example.com>\" --suppress-cc=sob --from=\"Example <nobody@example.com>\" --to=nobody@example.com --smtp-server=\"$(pwd)/fake.sendmail\" $patches 2>errors\n+\tgit send-email --envelope-sender=\"Patch Contributor <patch@example.com>\" --suppress-cc=sob --from=\"Example <nobody@example.com>\" --to=nobody@example.com --sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" $patches 2>errors\n '\n \n test_expect_success $PREREQ 'setup expect' '\n@@ -132,7 +132,7 @@ test_expect_success $PREREQ 'Verify commandline' '\n \n test_expect_success $PREREQ 'Send patches with --envelope-sender=auto' '\n \tclean_fake_sendmail &&\n-\tgit send-email --envelope-sender=auto --suppress-cc=sob --from=\"Example <nobody@example.com>\" --to=nobody@example.com --smtp-server=\"$(pwd)/fake.sendmail\" $patches 2>errors\n+\tgit send-email --envelope-sender=auto --suppress-cc=sob --from=\"Example <nobody@example.com>\" --to=nobody@example.com --sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" $patches 2>errors\n '\n \n test_expect_success $PREREQ 'setup expect' '\n@@ -178,7 +178,7 @@ test_expect_success $PREREQ 'cc trailer with various syntax' '\n \tEOF\n \tclean_fake_sendmail &&\n \tgit send-email -1 --to=recipient@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" &&\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" &&\n \ttest_cmp expected-cc commandline1\n '\n \n@@ -197,7 +197,7 @@ test_expect_success $PREREQ 'cc trailer with get_maintainer.pl output' '\n \tclean_fake_sendmail &&\n \tgit send-email -1 --to=recipient@example.com \\\n \t\t--cc-cmd=./expected-cc-script.sh \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" &&\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" &&\n \ttest_cmp expected-cc commandline1\n '\n \n@@ -252,7 +252,7 @@ test_suppress_self () {\n \t\t--to=nobody@example.com \\\n \t\t--cc-cmd=./cccmd-sed \\\n \t\t--suppress-cc=self \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\tsuppress-self-$3.patch &&\n \n \tmv msgtxt1 msgtxt1-$3 &&\n@@ -338,7 +338,7 @@ test_expect_success $PREREQ 'Prompting works' '\n \t(echo \"to@example.com\" &&\n \t echo \"\"\n \t) | GIT_SEND_EMAIL_NOTTY=1 git send-email \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches \\\n \t\t2>errors &&\n \t\tgrep \"^From: A U Thor <author@example.com>\\$\" msgtxt1 &&\n@@ -352,7 +352,7 @@ test_expect_success $PREREQ,AUTOIDENT 'implicit ident is allowed' '\n \tsane_unset GIT_COMMITTER_NAME &&\n \tsane_unset GIT_COMMITTER_EMAIL &&\n \tGIT_SEND_EMAIL_NOTTY=1 git send-email \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t--to=to@example.com \\\n \t\t$patches </dev/null 2>errors\n \t)\n@@ -366,7 +366,7 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email'\n \tsane_unset GIT_COMMITTER_EMAIL &&\n \tGIT_SEND_EMAIL_NOTTY=1 && export GIT_SEND_EMAIL_NOTTY &&\n \ttest_must_fail git send-email \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t--to=to@example.com \\\n \t\t$patches </dev/null 2>errors &&\n \ttest_i18ngrep \"tell me who you are\" errors\n@@ -389,7 +389,7 @@ test_expect_success $PREREQ 'tocmd works' '\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to-cmd=./tocmd-sed \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\ttocmd.patch \\\n \t\t&&\n \tgrep \"^To: tocmd@example.com\" msgtxt1\n@@ -403,7 +403,7 @@ test_expect_success $PREREQ 'cccmd works' '\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n \t\t--cc-cmd=./cccmd-sed \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\tcccmd.patch \\\n \t\t&&\n \tgrep \"^\tcccmd@example.com\" msgtxt1\n@@ -423,7 +423,7 @@ test_expect_success $PREREQ 'reject long lines' '\n \ttest_must_fail git send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t--transfer-encoding=8bit \\\n \t\t$patches longline.patch \\\n \t\t2>actual &&\n@@ -443,7 +443,7 @@ test_expect_success $PREREQ 'Author From: in message body' '\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches &&\n \tsed \"1,/^\\$/d\" <msgtxt1 >msgbody1 &&\n \tgrep \"From: A <author@example.com>\" msgbody1\n@@ -454,7 +454,7 @@ test_expect_success $PREREQ 'Author From: not in message body' '\n \tgit send-email \\\n \t\t--from=\"A <author@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches &&\n \tsed \"1,/^\\$/d\" <msgtxt1 >msgbody1 &&\n \t! grep \"From: A <author@example.com>\" msgbody1\n@@ -464,7 +464,7 @@ test_expect_success $PREREQ 'allow long lines with --no-validate' '\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t--no-validate \\\n \t\t$patches longline.patch \\\n \t\t2>errors\n@@ -475,7 +475,7 @@ test_expect_success $PREREQ 'short lines with auto encoding are 8bit' '\n \tgit send-email \\\n \t\t--from=\"A <author@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t--transfer-encoding=auto \\\n \t\t$patches &&\n \tgrep \"Content-Transfer-Encoding: 8bit\" msgtxt1\n@@ -486,7 +486,7 @@ test_expect_success $PREREQ 'long lines with auto encoding are quoted-printable'\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t--transfer-encoding=auto \\\n \t\t--no-validate \\\n \t\tlongline.patch &&\n@@ -500,7 +500,7 @@ test_expect_success $PREREQ 'carriage returns with auto encoding are quoted-prin\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t--transfer-encoding=auto \\\n \t\t--no-validate \\\n \t\tcr.patch &&\n@@ -513,7 +513,7 @@ do\n \t\tgit send-email \\\n \t\t\t--from=\"Example <nobody@example.com>\" \\\n \t\t\t--to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\t--transfer-encoding=$enc \\\n \t\t\t--validate \\\n \t\t\t$patches longline.patch\n@@ -533,7 +533,7 @@ test_expect_success $PREREQ \"--validate respects relative core.hooksPath path\" '\n \ttest_must_fail git send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t--validate \\\n \t\tlongline.patch 2>actual &&\n \ttest_path_is_file my-hooks.ran &&\n@@ -552,7 +552,7 @@ test_expect_success $PREREQ \"--validate respects absolute core.hooksPath path\" '\n \ttest_must_fail git send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t--validate \\\n \t\tlongline.patch 2>actual &&\n \ttest_path_is_file my-hooks.ran &&\n@@ -571,7 +571,7 @@ do\n \t\tgit send-email \\\n \t\t\t--from=\"Example <nobody@example.com>\" \\\n \t\t\t--to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\t--transfer-encoding=$enc \\\n \t\t\t$patches &&\n \t\tgrep \"Content-Transfer-Encoding: $enc\" msgtxt1\n@@ -584,7 +584,7 @@ test_expect_success $PREREQ 'Invalid In-Reply-To' '\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n \t\t--in-reply-to=\" \" \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches \\\n \t\t2>errors &&\n \t! grep \"^In-Reply-To: < *>\" msgtxt1\n@@ -596,7 +596,7 @@ test_expect_success $PREREQ 'Valid In-Reply-To when prompting' '\n \t echo \"To Example <to@example.com>\" &&\n \t echo \"\"\n \t) | GIT_SEND_EMAIL_NOTTY=1 git send-email \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches 2>errors &&\n \t! grep \"^In-Reply-To: < *>\" msgtxt1\n '\n@@ -609,7 +609,7 @@ test_expect_success $PREREQ 'In-Reply-To without --chain-reply-to' '\n \t\t--to=nobody@example.com \\\n \t\t--no-chain-reply-to \\\n \t\t--in-reply-to=\"$(cat expect)\" \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches $patches $patches \\\n \t\t2>errors &&\n \t# The first message is a reply to --in-reply-to\n@@ -631,7 +631,7 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' '\n \t\t--to=nobody@example.com \\\n \t\t--chain-reply-to \\\n \t\t--in-reply-to=\"$(cat expect)\" \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches $patches $patches \\\n \t\t2>errors &&\n \tsed -n -e \"s/^In-Reply-To: *\\(.*\\)/\\1/p\" msgtxt1 >actual &&\n@@ -658,7 +658,7 @@ test_expect_success $PREREQ '--compose works' '\n \t--compose --subject foo \\\n \t--from=\"Example <nobody@example.com>\" \\\n \t--to=nobody@example.com \\\n-\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t$patches \\\n \t2>errors\n '\n@@ -992,7 +992,7 @@ test_confirm () {\n \t\tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$@ $patches >stdout &&\n \tgrep \"Send this email\" stdout\n }\n@@ -1034,7 +1034,7 @@ test_expect_success $PREREQ 'confirm detects EOF (inform assumes y)' '\n \t\tgit send-email \\\n \t\t\t--from=\"Example <nobody@example.com>\" \\\n \t\t\t--to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\toutdir/*.patch </dev/null\n '\n \n@@ -1046,7 +1046,7 @@ test_expect_success $PREREQ 'confirm detects EOF (auto causes failure)' '\n \t\ttest_must_fail git send-email \\\n \t\t\t--from=\"Example <nobody@example.com>\" \\\n \t\t\t--to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\t$patches </dev/null\n '\n \n@@ -1058,7 +1058,7 @@ test_expect_success $PREREQ 'confirm does not loop forever' '\n \t\tyes \"bogus\" | test_must_fail git send-email \\\n \t\t\t--from=\"Example <nobody@example.com>\" \\\n \t\t\t--to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\t$patches\n '\n \n@@ -1069,7 +1069,7 @@ test_expect_success $PREREQ 'utf8 Cc is rfc2047 encoded' '\n \tgit send-email \\\n \t--from=\"Example <nobody@example.com>\" \\\n \t--to=nobody@example.com \\\n-\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \toutdir/*.patch &&\n \tgrep \"^\t\" msgtxt1 |\n \tgrep \"=?UTF-8?q?=C3=A0=C3=A9=C3=AC=C3=B6=C3=BA?= <utf8@example.com>\"\n@@ -1085,7 +1085,7 @@ test_expect_success $PREREQ '--compose adds MIME for utf8 body' '\n \t\t--compose --subject foo \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches &&\n \tgrep \"^utf8 body\" msgtxt1 &&\n \tgrep \"^Content-Type: text/plain; charset=UTF-8\" msgtxt1\n@@ -1108,7 +1108,7 @@ test_expect_success $PREREQ '--compose respects user mime type' '\n \t\t--compose --subject foo \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches &&\n \tgrep \"^utf8 body\" msgtxt1 &&\n \tgrep \"^Content-Type: text/plain; charset=iso-8859-1\" msgtxt1 &&\n@@ -1122,7 +1122,7 @@ test_expect_success $PREREQ '--compose adds MIME for utf8 subject' '\n \t\t--compose --subject utf8-sübjëct \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches &&\n \tgrep \"^fake edit\" msgtxt1 &&\n \tgrep \"^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=\" msgtxt1\n@@ -1136,7 +1136,7 @@ test_expect_success $PREREQ 'utf8 author is correctly passed on' '\n \tgit format-patch --stdout -1 >funny_name.patch &&\n \tgit send-email --from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\tfunny_name.patch &&\n \tgrep \"^From: Füñný Nâmé <odd_?=mail@example.com>\" msgtxt1\n '\n@@ -1149,7 +1149,7 @@ test_expect_success $PREREQ 'utf8 sender is not duplicated' '\n \tgit format-patch --stdout -1 >funny_name.patch &&\n \tgit send-email --from=\"Füñný Nâmé <odd_?=mail@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\tfunny_name.patch &&\n \tgrep \"^From: \" msgtxt1 >msgfrom &&\n \ttest_line_count = 1 msgfrom\n@@ -1166,7 +1166,7 @@ test_expect_success $PREREQ 'sendemail.composeencoding works' '\n \t\t--compose --subject foo \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches &&\n \tgrep \"^utf8 body\" msgtxt1 &&\n \tgrep \"^Content-Type: text/plain; charset=iso-8859-1\" msgtxt1\n@@ -1183,7 +1183,7 @@ test_expect_success $PREREQ '--compose-encoding works' '\n \t\t--compose --subject foo \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches &&\n \tgrep \"^utf8 body\" msgtxt1 &&\n \tgrep \"^Content-Type: text/plain; charset=iso-8859-1\" msgtxt1\n@@ -1201,7 +1201,7 @@ test_expect_success $PREREQ '--compose-encoding overrides sendemail.composeencod\n \t\t--compose --subject foo \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches &&\n \tgrep \"^utf8 body\" msgtxt1 &&\n \tgrep \"^Content-Type: text/plain; charset=iso-8859-2\" msgtxt1\n@@ -1215,7 +1215,7 @@ test_expect_success $PREREQ '--compose-encoding adds correct MIME for subject' '\n \t\t--compose --subject utf8-sübjëct \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$patches &&\n \tgrep \"^fake edit\" msgtxt1 &&\n \tgrep \"^Subject: =?iso-8859-2?q?utf8-s=C3=BCbj=C3=ABct?=\" msgtxt1\n@@ -1465,7 +1465,7 @@ test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' '\n \tclean_fake_sendmail &&\n \techo bogus |\n \tgit send-email --from=author@example.com --to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\t--8bit-encoding=UTF-8 \\\n \t\t\temail-using-8bit >stdout &&\n \tgrep \"Subject\" msgtxt1 >actual &&\n@@ -1484,7 +1484,7 @@ test_expect_success $PREREQ 'asks about and fixes 8bit encodings' '\n \tclean_fake_sendmail &&\n \techo |\n \tgit send-email --from=author@example.com --to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\temail-using-8bit >stdout &&\n \tgrep \"do not declare a Content-Transfer-Encoding\" stdout &&\n \tgrep email-using-8bit stdout &&\n@@ -1498,7 +1498,7 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding works' '\n \tgit config sendemail.assume8bitEncoding UTF-8 &&\n \techo bogus |\n \tgit send-email --from=author@example.com --to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\temail-using-8bit >stdout &&\n \tegrep \"Content|MIME\" msgtxt1 >actual &&\n \ttest_cmp content-type-decl actual\n@@ -1509,7 +1509,7 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '\n \tgit config sendemail.assume8bitEncoding \"bogus too\" &&\n \techo bogus |\n \tgit send-email --from=author@example.com --to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\t--8bit-encoding=UTF-8 \\\n \t\t\temail-using-8bit >stdout &&\n \tegrep \"Content|MIME\" msgtxt1 >actual &&\n@@ -1538,7 +1538,7 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '\n \tclean_fake_sendmail &&\n \techo bogus |\n \tgit send-email --from=author@example.com --to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\t--8bit-encoding=UTF-8 \\\n \t\t\temail-using-8bit >stdout &&\n \tgrep \"Subject\" msgtxt1 >actual &&\n@@ -1563,7 +1563,7 @@ test_expect_success $PREREQ '--transfer-encoding overrides sendemail.transferEnc\n \ttest_must_fail git -c sendemail.transferEncoding=8bit \\\n \t\tsend-email \\\n \t\t--transfer-encoding=7bit \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\temail-using-8bit \\\n \t\t2>errors >out &&\n \tgrep \"cannot send message as 7bit\" errors &&\n@@ -1574,7 +1574,7 @@ test_expect_success $PREREQ 'sendemail.transferEncoding via config' '\n \tclean_fake_sendmail &&\n \ttest_must_fail git -c sendemail.transferEncoding=7bit \\\n \t\tsend-email \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\temail-using-8bit \\\n \t\t2>errors >out &&\n \tgrep \"cannot send message as 7bit\" errors &&\n@@ -1585,7 +1585,7 @@ test_expect_success $PREREQ 'sendemail.transferEncoding via cli' '\n \tclean_fake_sendmail &&\n \ttest_must_fail git send-email \\\n \t\t--transfer-encoding=7bit \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\temail-using-8bit \\\n \t\t2>errors >out &&\n \tgrep \"cannot send message as 7bit\" errors &&\n@@ -1602,7 +1602,7 @@ test_expect_success $PREREQ '8-bit and sendemail.transferencoding=quoted-printab\n \tclean_fake_sendmail &&\n \tgit send-email \\\n \t\t--transfer-encoding=quoted-printable \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\temail-using-8bit \\\n \t\t2>errors >out &&\n \tsed \"1,/^$/d\" msgtxt1 >actual &&\n@@ -1619,7 +1619,7 @@ test_expect_success $PREREQ '8-bit and sendemail.transferencoding=base64' '\n \tclean_fake_sendmail &&\n \tgit send-email \\\n \t\t--transfer-encoding=base64 \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\temail-using-8bit \\\n \t\t2>errors >out &&\n \tsed \"1,/^$/d\" msgtxt1 >actual &&\n@@ -1645,7 +1645,7 @@ test_expect_success $PREREQ 'convert from quoted-printable to base64' '\n \tclean_fake_sendmail &&\n \tgit send-email \\\n \t\t--transfer-encoding=base64 \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\temail-using-qp \\\n \t\t2>errors >out &&\n \tsed \"1,/^$/d\" msgtxt1 >actual &&\n@@ -1675,7 +1675,7 @@ test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=quoted-printabl\n \tclean_fake_sendmail &&\n \tgit send-email \\\n \t\t--transfer-encoding=quoted-printable \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\temail-using-crlf \\\n \t\t2>errors >out &&\n \tsed \"1,/^$/d\" msgtxt1 >actual &&\n@@ -1692,7 +1692,7 @@ test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=base64' '\n \tclean_fake_sendmail &&\n \tgit send-email \\\n \t\t--transfer-encoding=base64 \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\temail-using-crlf \\\n \t\t2>errors >out &&\n \tsed \"1,/^$/d\" msgtxt1 >actual &&\n@@ -1710,7 +1710,7 @@ test_expect_success $PREREQ 'refusing to send cover letter template' '\n \ttest_must_fail git send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\toutdir/0002-*.patch \\\n \t\toutdir/0000-*.patch \\\n \t\toutdir/0001-*.patch \\\n@@ -1727,7 +1727,7 @@ test_expect_success $PREREQ '--force sends cover letter template anyway' '\n \t\t--force \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\toutdir/0002-*.patch \\\n \t\toutdir/0000-*.patch \\\n \t\toutdir/0001-*.patch \\\n@@ -1750,7 +1750,7 @@ test_cover_addresses () {\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--no-to --no-cc \\\n \t\t\"$@\" \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\toutdir/0000-*.patch \\\n \t\toutdir/0001-*.patch \\\n \t\toutdir/0002-*.patch \\\n@@ -1789,7 +1789,7 @@ test_expect_success $PREREQ 'escaped quotes in sendemail.aliasfiletype=mutt' '\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=sbd \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\toutdir/0001-*.patch \\\n \t\t2>errors >out &&\n \tgrep \"^!somebody@example\\.org!$\" commandline1 &&\n@@ -1804,7 +1804,7 @@ test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' '\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=sbd \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\toutdir/0001-*.patch \\\n \t\t2>errors >out &&\n \tgrep \"^!somebody@example\\.org!$\" commandline1\n@@ -1818,7 +1818,7 @@ test_expect_success $PREREQ 'sendemail.aliasfile=~/.mailrc' '\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=sbd \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\toutdir/0001-*.patch \\\n \t\t2>errors >out &&\n \tgrep \"^!someone@example\\.org!$\" commandline1\n@@ -1929,7 +1929,7 @@ test_sendmail_aliases () {\n \t\tgit send-email \\\n \t\t\t--from=\"Example <nobody@example.com>\" \\\n \t\t\t--to=alice --to=bcgrp \\\n-\t\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\toutdir/0001-*.patch \\\n \t\t\t2>errors >out &&\n \t\tfor i in $expect\n@@ -1995,7 +1995,7 @@ test_expect_success $PREREQ 'alias support in To header' '\n \tgit format-patch --stdout -1 --to=sbd >aliased.patch &&\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\taliased.patch \\\n \t\t2>errors >out &&\n \tgrep \"^!someone@example\\.org!$\" commandline1\n@@ -2009,7 +2009,7 @@ test_expect_success $PREREQ 'alias support in Cc header' '\n \tgit format-patch --stdout -1 --cc=sbd >aliased.patch &&\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\taliased.patch \\\n \t\t2>errors >out &&\n \tgrep \"^!someone@example\\.org!$\" commandline1\n@@ -2025,7 +2025,7 @@ test_expect_success $PREREQ 'tocmd works with aliases' '\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to-cmd=./tocmd-sed \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\ttocmd.patch \\\n \t\t2>errors >out &&\n \tgrep \"^!someone@example\\.org!$\" commandline1\n@@ -2041,7 +2041,7 @@ test_expect_success $PREREQ 'cccmd works with aliases' '\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--cc-cmd=./cccmd-sed \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\tcccmd.patch \\\n \t\t2>errors >out &&\n \tgrep \"^!someone@example\\.org!$\" commandline1\n@@ -2053,7 +2053,7 @@ do_xmailer_test () {\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=someone@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t$params \\\n \t\t0001-*.patch \\\n \t\t2>errors >out &&\n@@ -2148,6 +2148,29 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '\n \ttest_cmp expected-list actual-list\n '\n \n+test_expect_success $PREREQ 'test using relative path with sendmailCommand' '\n+\tclean_fake_sendmail &&\n+\tPATH=\"$(pwd):$PATH\" \\\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"fake.sendmail\" \\\n+\t\tHEAD~2 &&\n+\ttest_path_is_file commandline1 &&\n+\ttest_path_is_file commandline2\n+'\n+\n+test_expect_success $PREREQ 'test using shell with sendmailCommand' '\n+\tclean_fake_sendmail &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"[ 1 -eq 1 ] && \\\"$(pwd)/fake.sendmail\\\"\" \\\n+\t\tHEAD~2 &&\n+\ttest_path_is_file commandline1 &&\n+\ttest_path_is_file commandline2\n+'\n+\n test_expect_success $PREREQ 'invoke hook' '\n \tmkdir -p .git/hooks &&\n \n@@ -2174,7 +2197,7 @@ test_expect_success $PREREQ 'invoke hook' '\n \t\tgit send-email \\\n \t\t\t--from=\"Example <nobody@example.com>\" \\\n \t\t\t--to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/../fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/../fake.sendmail\\\"\" \\\n \t\t\t../0001-add-main.patch &&\n \n \t\t# Verify error message when a patch is rejected by the hook\n@@ -2182,7 +2205,7 @@ test_expect_success $PREREQ 'invoke hook' '\n \t\ttest_must_fail git send-email \\\n \t\t\t--from=\"Example <nobody@example.com>\" \\\n \t\t\t--to=nobody@example.com \\\n-\t\t\t--smtp-server=\"$(pwd)/../fake.sendmail\" \\\n+\t\t\t--sendmail-cmd=\"\\\"$(pwd)/../fake.sendmail\\\"\" \\\n \t\t\t../another.patch 2>err &&\n \t\ttest_i18ngrep \"rejected by sendemail-validate hook\" err\n \t)\n@@ -2192,7 +2215,7 @@ test_expect_success $PREREQ 'test that send-email works outside a repo' '\n \tnongit git send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\t\"$(pwd)/0001-add-main.patch\"\n '\n \n@@ -2201,7 +2224,7 @@ test_expect_success $PREREQ 'test that sendmail config is rejected' '\n \ttest_must_fail git send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\tHEAD^ 2>err &&\n \ttest_i18ngrep \"found configuration options for '\"'\"sendmail\"'\"'\" err\n '\n@@ -2211,7 +2234,7 @@ test_expect_success $PREREQ 'test that sendmail config rejection is specific' '\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\tHEAD^\n '\n \n@@ -2221,7 +2244,7 @@ test_expect_success $PREREQ 'test forbidSendmailVariables behavior override' '\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n \t\tHEAD^\n '\n \n-- \n2.31.1.576.g12e560b5fe\n\n"},{"id":"424276","messageId":"xmqqh7j8h9cy.fsf@gitster.g","threadId":"55668","inReplyTo":"20210512033039.4022-1-greg@gpanders.com","subject":"Re: [PATCH] git-send-email: add sendmailCommand option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-05-12T04:19:41Z","receivedAt":"2021-05-12T04:19:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Gregory Anders <greg@gpanders.com> writes:\n\n> The sendemail.smtpServer option currently supports using a sendmail-like\n> program to send emails by specifying an absolute file path. However,\n\nThat is not wrong per-se, but it is not limited to the configuration\nvariable, but is a shared trait with --smtp-server command line\noption.  It is easier on the readers to mention both.\n\nOur problem description talks about the status quo in the present\ntense.  No noiseword \"currently \" necessary.  I.e. something along\nthis line:\n\n    The sendemail.smtpServer configuration variable (and the\n    \"--smtp-server\" command line option of \"git send-email\" command)\n    allows to name a command to run to send emails by specifying an\n    absolute path name.  However,\n\n> this is not ideal for the following reasons:\n>\n> 1. It overloads the meaning of smtpServer (now a program is being used\n>    for the server?)\n> 2. It doesn't allow for non-absolute paths, arguments, or arbitrary\n>    scripting.\n>\n> Requiring an absolute path is bad for portability, as the same\n> program may be in different locations on different systems. If I wish\n> to pass arguments to my program, I have to use the smtpServerOption\n> option, which is cumbersome (as it must be repeated for each option)\n> and doesn't adhere to normal git conventions.\n\nUp to here, nice explanation of the background and description of\nthe problem being solved.\n\n> This patch attempts to solve these problems by introducing a new\n> configuration option sendemail.sendmailCommand as well as a command line\n> option --sendmail-cmd. The value of this option is invoked with the\n> standard sendmail options passed as arguments.\n\nWhen presenting a potential solution, in the history of this\nproject, we'd talk as if we are giving an order to the codebase to\n\"be like so\".\n\n    Introduce a command line option '--sendmail-cmd' and a\n    configuration variable sendemail.sendmailCommand that can be\n    used to specify the command line (possibly including its command\n    line options) to send pieces of e-mail.  This is invoked while\n    honoring $PATH, so it does not have to be named with an absolute\n    path to the command.\n\n    Give it a higher precedence over --smtp-server (and\n    sendemail.smtpServer), as the new interface is more flexible.\n\n> sendmailCommand has precedence over smtpServer. If both options are\n> unspecified, the default is to search for 'sendmail' in /usr/sbin,\n> /usr/lib, and $PATH. If not found, smtpServer is set to localhost. This\n> mimics the current behavior when smtpServer is unspecified.\n\nI do not think \"If both options are unspecified\" and everything\nafter it is needed.\n\n> The option is passed to Perl's `exec()` function, which automatically\n> determines whether or not to invoke a shell. If shell metacharacters are\n> detected, then a shell is used; otherwise, the command is invoked\n> directly.\n\nI do not think this, and the two examples below (omitted), are\nrelevant, either.\n\nThe \"metacharacters make the command diverted to shell\" is a mere\noptimization and not of interest to the end users.  Even if\nsendemail.sendmailcommand is set to just a single word 'msmtp',\nwhich does not have any metacharacter, we _could_ spawn it via the\nshell and the observable end result would be the same as if the\nsingle word was directly executed without the shell.\n\n> This change deprecates the use of absolute paths in \n> sendemail.smtpServer, although support is kept for backward\n> compatibility.\n\nI am on the fence about saying this.  We may eventually want to\ndeprecate, but until we start issuing a warning when the\nabsolute-path form is used, I'd rather not to call it \"deprecated\"\nin either the proposed log message or in the documenation.\n\n> ---\n\nMissing sign-off.\n\n>\n> Note that this patch is incompatible with (and supersedes) the patch\n> discussed here: \n>\n>     https://public-inbox.org/git/YJs2RceLliGHI5TX@gpanders.com/T/#t\n\nThanks---such a note is very valuable.\n\n> diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\n> index 93708aefea..d9fe8cb7c0 100644\n> --- a/Documentation/git-send-email.txt\n> +++ b/Documentation/git-send-email.txt\n> @@ -159,13 +159,23 @@ Sending\n>  ~~~~~~~\n>  \n>  --envelope-sender=<address>::\n> -\tSpecify the envelope sender used to send the emails.\n> -\tThis is useful if your default address is not the address that is\n> -\tsubscribed to a list. In order to use the 'From' address, set the\n> -\tvalue to \"auto\". If you use the sendmail binary, you must have\n> -\tsuitable privileges for the -f parameter.  Default is the value of the\n> -\t`sendemail.envelopeSender` configuration variable; if that is\n> -\tunspecified, choosing the envelope sender is left to your MTA.\n> +\tSpecify the envelope sender used to send the emails.  This is\n> +\tuseful if your default address is not the address that is\n> +\tsubscribed to a list. In order to use the 'From' address, set\n> +\tthe value to \"auto\". If you use the sendmail binary, you must\n> +\thave suitable privileges for the -f parameter.  Default is the\n> +\tvalue of the `sendemail.envelopeSender` configuration variable;\n> +\tif that is unspecified, choosing the envelope sender is left to\n> +\tyour MTA.\n\nIs this a totally unwarranted rewrapping of an unrelated part of the\nsame document, or was there some words or phrases in this\ndescription of the envelope-sender option that needed to be adjusted\nfor the introduction of sendmail-cmd option?\n\n> +--sendmail-cmd=<command>::\n> +\tSpecify a command to run to send the email. The command should\n> +\tbe compatible with `sendmail` as the arguments are passed\n> +\tdirectly.  The command will be executed in the shell if\n> +\tnecessary.  Default is the value of `sendemail.sendmailCommand`.\n> +\tIf unspecified, and if --smtp-server is also unspecified,\n> +\tgit-send-email will search for `sendmail` in `/usr/sbin`,\n> +\t`/usr/lib` and $PATH if such a program is available.\n\nOK, but doesn't this also need to support '-i'?\n\n> @@ -211,13 +221,14 @@ a password is obtained using 'git-credential'.\n>  \n>  --smtp-server=<host>::\n>  \tIf set, specifies the outgoing SMTP server to use (e.g.\n> -\t`smtp.example.com` or a raw IP address).  Alternatively it can\n> -\tspecify a full pathname of a sendmail-like program instead;\n> -\tthe program must support the `-i` option.  Default value can\n> -\tbe specified by the `sendemail.smtpServer` configuration\n> -\toption; the built-in default is to search for `sendmail` in\n> -\t`/usr/sbin`, `/usr/lib` and $PATH if such program is\n> -\tavailable, falling back to `localhost` otherwise.\n> +\t`smtp.example.com` or a raw IP address).  If unspecified, and if\n> +\t`--sendmail-cmd` is also unspecified, the default is to search\n> +\tfor `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH if such a\n> +\tprogram is available, falling back to `localhost` otherwise.\n> +\n> +\tFor backward compatibility, this option can also specify a full\n> +\tpathname of a sendmail-like program instead; the program must\n> +\tsupport the `-i` option.  Prefer using `--sendmail-cmd` instead.\n\nDrop the last sentence, if we are not going to explain why.  Or\nperhaps:\n\n\t... an absolute path to a program that behaves like\n\t`sendmail` (among other things, it must support the `-i`\n\toption).  As you only can specify the path to the program\n\tand cannot give any leading arguments to it, consider using\n\t`--sendmail-cmd` instead.\n\n> @@ -1490,14 +1497,15 @@ sub send_message {\n>  \n>  \tunshift (@sendmail_parameters, @smtp_server_options);\n>  \n> +\tif (file_name_is_absolute($smtp_server)) {\n> +\t\t# Preserved for backward compatibility\n> +\t\t$sendmail_command ||= $smtp_server;\n> +\t}\n\nHmph, I wonder if this makes the intent more clear.\n\n\tif (!defined $sendmail_command && file_name_is_absolute($smtp_server)) {\n\t\t$sendmail_command = $smtp_server;\n\t}\n\nThat is, if the user gave us the command in newer form, we do not\neven have to bother checking if the server is given as an absolute\npathname.\n\n> @@ -1069,7 +1069,7 @@ test_expect_success $PREREQ 'utf8 Cc is rfc2047 encoded' '\n>  \tgit send-email \\\n>  \t--from=\"Example <nobody@example.com>\" \\\n>  \t--to=nobody@example.com \\\n> -\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n> +\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n>  \toutdir/*.patch &&\n>  \tgrep \"^\t\" msgtxt1 |\n>  \tgrep \"=?UTF-8?q?=C3=A0=C3=A9=C3=AC=C3=B6=C3=BA?= <utf8@example.com>\"\n\nYou seem to have replaced every smtp-server=\"$(pwd)/ mechanically\nwith sendmai-cmd=\\\"$(pwd)/, but please make sure that we have at\nleast one test left that passes an absolute path to --smtp-server to\nensure that the old mechanism keeps working.  A bonus point for\nmarking such a test that needs to be adjusted when the actual\ndeprecation happens (i.e. we'd likely to detect the use of absolute\npath and throw a warning, so the test should notice the warning\nmessage).\n\nAlso you would want to tweak some of the --sendmail-cmd variants to\nuse just the command name, with and without args, to ensure that (1)\ndiscovery on $PATH works, and (2) passing initial args works.\n\nThanks.\n"},{"id":"424298","messageId":"609b8a5a65826_6e0fc2084c@natae.notmuch","threadId":"55668","inReplyTo":"20210512033039.4022-1-greg@gpanders.com","subject":"RE: [PATCH] git-send-email: add sendmailCommand option","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2021-05-12T07:57:14Z","receivedAt":"2021-05-12T07:57:23Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Gregory Anders wrote:\n> --- a/Documentation/git-send-email.txt\n> +++ b/Documentation/git-send-email.txt\n> @@ -159,13 +159,23 @@ Sending\n>  ~~~~~~~\n>  \n>  --envelope-sender=<address>::\n> -\tSpecify the envelope sender used to send the emails.\n> -\tThis is useful if your default address is not the address that is\n> -\tsubscribed to a list. In order to use the 'From' address, set the\n> -\tvalue to \"auto\". If you use the sendmail binary, you must have\n> -\tsuitable privileges for the -f parameter.  Default is the value of the\n> -\t`sendemail.envelopeSender` configuration variable; if that is\n> -\tunspecified, choosing the envelope sender is left to your MTA.\n> +\tSpecify the envelope sender used to send the emails.  This is\n> +\tuseful if your default address is not the address that is\n> +\tsubscribed to a list. In order to use the 'From' address, set\n> +\tthe value to \"auto\". If you use the sendmail binary, you must\n> +\thave suitable privileges for the -f parameter.  Default is the\n> +\tvalue of the `sendemail.envelopeSender` configuration variable;\n> +\tif that is unspecified, choosing the envelope sender is left to\n> +\tyour MTA.\n\nI'm not against these kinds of changes but it took me one minute to\nfigure out all you did was change the format.\n\nThis belongs in a separate patch.\n\n> +--sendmail-cmd=<command>::\n\nOh no no no. Don't do shortcuts.\n\nIf you think --sendmail-command is too long, then address that problem\nhead on, don't try to hide it.\n\nI do think it's too long, which is why I suggested --command (especially\nsince it's obvious which command we are talking about), but I wouldn't\nsuggest --sdm-command, or something of that sort. We have to own our\ndecisions.\n\n  1. --command\n  2. --sendmail\n  3. --sendmail-command\n\nWe have to pick one. I suggest #1.\n\nTo try to make #3 shorter is just shoving the problem under the rug.\n\n> --- a/git-send-email.perl\n> +++ b/git-send-email.perl\n> @@ -70,6 +70,7 @@ sub usage {\n>  \n>    Sending:\n>      --envelope-sender       <str>  * Email envelope sender.\n> +    --sendmail-cmd          <str>  * Shell command to run to send email.\n>      --smtp-server       <str:int>  * Outgoing SMTP server to use. The port\n>                                       is optional. Default 'localhost'.\n>      --smtp-server-option    <str>  * Outgoing SMTP server option to use.\n> @@ -252,6 +253,7 @@ sub do_edit {\n>  my (@suppress_cc);\n>  my ($auto_8bit_encoding);\n>  my ($compose_encoding);\n> +my ($sendmail_command);\n>  # Variables with corresponding config settings & hardcoded defaults\n>  my ($debug_net_smtp) = 0;\t\t# Net::SMTP, see send_message()\n>  my $thread = 1;\n> @@ -299,6 +301,7 @@ sub do_edit {\n>      \"assume8bitencoding\" => \\$auto_8bit_encoding,\n>      \"composeencoding\" => \\$compose_encoding,\n>      \"transferencoding\" => \\$target_xfer_encoding,\n> +    \"sendmailcommand\" => \\$sendmail_command,\n>  );\n>  \n>  my %config_path_settings = (\n> @@ -432,6 +435,7 @@ sub read_config {\n>  \t\t    \"no-bcc\" => \\$no_bcc,\n>  \t\t    \"chain-reply-to!\" => \\$chain_reply_to,\n>  \t\t    \"no-chain-reply-to\" => sub {$chain_reply_to = 0},\n> +\t\t    \"sendmail-cmd=s\" => \\$sendmail_command,\n\nIsn't it interesting that to make the code readable you picked\n$sendmail_command, but you don't want users to type so much, even if\nit's more readable?\n\nOnce again: \"$command=s\" -> \\$command,\n\n> --- a/t/t9001-send-email.sh\n> +++ b/t/t9001-send-email.sh\n> @@ -57,7 +57,7 @@ test_no_confirm () {\n>  \t\tgit send-email \\\n>  \t\t--from=\"Example <from@example.com>\" \\\n>  \t\t--to=nobody@example.com \\\n> -\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n> +\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n\nPeople are already using --smpt-server=$cmd, we need to keep testing\nthat.\n\nYes, eventually we would want them to move to --sendmail-cmd (or\n--command, or whatever), but that won't happen tomorrow. Therefore our\nprimary tests need to be focused on --smtp-server.\n\nWe need new *additional* tests for --sendmail-cmd, but those should not\noverride the current tests. At least not right now.\n\nCheers.\n\n-- \nFelipe Contreras\n"},{"id":"424307","messageId":"87y2cks3lt.fsf@evledraar.gmail.com","threadId":"55668","inReplyTo":"20210512033039.4022-1-greg@gpanders.com","subject":"Re: [PATCH] git-send-email: add sendmailCommand option","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-05-12T09:04:59Z","receivedAt":"2021-05-12T09:28:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, May 11 2021, Gregory Anders wrote:\n\n> diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\n> index 93708aefea..d9fe8cb7c0 100644\n> --- a/Documentation/git-send-email.txt\n> +++ b/Documentation/git-send-email.txt\n> @@ -159,13 +159,23 @@ Sending\n>  ~~~~~~~\n>  \n>  --envelope-sender=<address>::\n> -\tSpecify the envelope sender used to send the emails.\n> -\tThis is useful if your default address is not the address that is\n> -\tsubscribed to a list. In order to use the 'From' address, set the\n> -\tvalue to \"auto\". If you use the sendmail binary, you must have\n> -\tsuitable privileges for the -f parameter.  Default is the value of the\n> -\t`sendemail.envelopeSender` configuration variable; if that is\n> -\tunspecified, choosing the envelope sender is left to your MTA.\n> +\tSpecify the envelope sender used to send the emails.  This is\n> +\tuseful if your default address is not the address that is\n> +\tsubscribed to a list. In order to use the 'From' address, set\n> +\tthe value to \"auto\". If you use the sendmail binary, you must\n> +\thave suitable privileges for the -f parameter.  Default is the\n> +\tvalue of the `sendemail.envelopeSender` configuration variable;\n> +\tif that is unspecified, choosing the envelope sender is left to\n> +\tyour MTA.\n\nPlease don't include word-wrapping for unrelated changes in the main\npatch.\n\n> -\t$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*\n> +\n> +\tif (!defined $sendmail_command) {\n> +\t\t$smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*\n> +\t}\n>  }\n\nThis \"let's not accept a 0\" change seems unrelated & should be split\ninto a prep cleanup / refactoring patch. On the one hand it's sensible,\non the other nobody cares about having a command named \"0\" in their path\n(or a hostname), so I think it's fine to have the ||= Perl idiom leak\nout here.\n\nBut also, this just seems like confusing logic. Per your docs \"your\nsendmailCommand has precedence over smtpServer.\".\n\nWhy not make this \"if not $sendmail_command\" part of the top-level check\nhere (the if this one is nested under), which is only done if\n$smtp_sever is not defined, if $sendmail_command is defined we don't\ncare about $smtp_server later on, no?\n\n>  if ($compose && $compose > 0) {\n> @@ -1490,14 +1497,15 @@ sub send_message {\n>  \n>  \tunshift (@sendmail_parameters, @smtp_server_options);\n>  \n> +\tif (file_name_is_absolute($smtp_server)) {\n> +\t\t# Preserved for backward compatibility\n> +\t\t$sendmail_command ||= $smtp_server;\n> +\t}\n> +\n>  \tif ($dry_run) {\n>  \t\t# We don't want to send the email.\n> -\t} elsif (file_name_is_absolute($smtp_server)) {\n> -\t\tmy $pid = open my $sm, '|-';\n> -\t\tdefined $pid or die $!;\n> -\t\tif (!$pid) {\n> -\t\t\texec($smtp_server, @sendmail_parameters) or die $!;\n> -\t\t}\n> +\t} elsif (defined $sendmail_command) {\n> +\t\topen my $sm, '|-', \"$sendmail_command @sendmail_parameters\";\n\nCan we really not avoid moving from exec-as-list so Perl quotes\neverything, to doing our own interpolation here? It looks like the tests\ndon't check arguments with whitespace (which should fail with this\nchange).\n\n>  \t\tprint $sm \"$header\\n$message\";\n>  \t\tclose $sm or die $!;\n>  \t} else {\n\nI've just skimmed the previous thread, so forgive me if this was brought\nup.\n\nI for one would be fine with just using --smtp-server and not adding an\n--sendmail-command, and doing this by simply doing an exec() on whatever\nthe user specifies.\n\nIf it's an absolute path and an executable command, OK. If it's a\ncommand name we find in $PATH, OK, or other valid shell whatever. You\ncan use $? to distinguish between a failed and nonexisting command.\n\nIf not exec() will return and we continue resolving it as a hostname/IP\naddress/whatever. We'll have a conflict if someone has a command in\ntheir $PATH called gmail.com or whatever, but really. Who does that?\n\nMaybe it's way too nasty. This design is also fine, just a suggestion.\n\n> @@ -1592,14 +1600,14 @@ sub send_message {\n>  \t\tprintf($dry_run ? __(\"Dry-Sent %s\\n\") : __(\"Sent %s\\n\"), $subject);\n>  \t} else {\n>  \t\tprint($dry_run ? __(\"Dry-OK. Log says:\\n\") : __(\"OK. Log says:\\n\"));\n> -\t\tif (!file_name_is_absolute($smtp_server)) {\n> +\t\tif (defined $sendmail_command) {\n> +\t\t\tprint \"Sendmail: $sendmail_command \".join(' ',@sendmail_parameters).\"\\n\";\n> +\t\t} else {\n>  \t\t\tprint \"Server: $smtp_server\\n\";\n>  \t\t\tprint \"MAIL FROM:<$raw_from>\\n\";\n>  \t\t\tforeach my $entry (@recipients) {\n>  \t\t\t    print \"RCPT TO:<$entry>\\n\";\n>  \t\t\t}\n> -\t\t} else {\n> -\t\t\tprint \"Sendmail: $smtp_server \".join(' ',@sendmail_parameters).\"\\n\";\n>  \t\t}\n>  \t\tprint $header, \"\\n\";\n>  \t\tif ($smtp) {\n\nMinor nit: Let's just continue to use \"if (!\" here to keep the diff\nminimal or split up such refactoring into another change...\n"},{"id":"424325","messageId":"YJvSJ3/2RWFJVmoq@gpanders.com","threadId":"55668","inReplyTo":"xmqqh7j8h9cy.fsf@gitster.g","subject":"Re: [PATCH] git-send-email: add sendmailCommand option","fromName":"Gregory Anders","fromEmail":"greg@gpanders.com","sentAt":"2021-05-12T13:03:35Z","receivedAt":"2021-05-12T13:03:43Z","isPatch":true,"sender":{"key":"greg@gpanders.com","avatar":"https://avatars.githubusercontent.com/u/8965202?v=4"},"body":"On Wed, 12 May 2021 13:19 +0900, Junio C Hamano wrote:\n>Is this a totally unwarranted rewrapping of an unrelated part of the\n>same document, or was there some words or phrases in this\n>description of the envelope-sender option that needed to be adjusted\n>for the introduction of sendmail-cmd option?\n\nYes it's just a rewrapping that I did while adding my new paragraph. The \nother reviewers pointed this out as well. My mistake, I will remove this \nfrom the next patch revision.\n\n>> +--sendmail-cmd=<command>::\n>> +\tSpecify a command to run to send the email. The command should\n>> +\tbe compatible with `sendmail` as the arguments are passed\n>> +\tdirectly.  The command will be executed in the shell if\n>> +\tnecessary.  Default is the value of `sendemail.sendmailCommand`.\n>> +\tIf unspecified, and if --smtp-server is also unspecified,\n>> +\tgit-send-email will search for `sendmail` in `/usr/sbin`,\n>> +\t`/usr/lib` and $PATH if such a program is available.\n\n>OK, but doesn't this also need to support '-i'?\n\n'The command should be compatible with `sendmail`' was meant to imply\nthis, though I can make this more explicit.\n\n>> @@ -211,13 +221,14 @@ a password is obtained using 'git-credential'.\n>>\n>>  --smtp-server=<host>::\n>>  \tIf set, specifies the outgoing SMTP server to use (e.g.\n>> -\t`smtp.example.com` or a raw IP address).  Alternatively it can\n>> -\tspecify a full pathname of a sendmail-like program instead;\n>> -\tthe program must support the `-i` option.  Default value can\n>> -\tbe specified by the `sendemail.smtpServer` configuration\n>> -\toption; the built-in default is to search for `sendmail` in\n>> -\t`/usr/sbin`, `/usr/lib` and $PATH if such program is\n>> -\tavailable, falling back to `localhost` otherwise.\n>> +\t`smtp.example.com` or a raw IP address).  If unspecified, and if\n>> +\t`--sendmail-cmd` is also unspecified, the default is to search\n>> +\tfor `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH if such a\n>> +\tprogram is available, falling back to `localhost` otherwise.\n>> +\n>> +\tFor backward compatibility, this option can also specify a full\n>> +\tpathname of a sendmail-like program instead; the program must\n>> +\tsupport the `-i` option.  Prefer using `--sendmail-cmd` instead.\n\n>Drop the last sentence, if we are not going to explain why.\n\nI do think nudging users to use the \"correct\" option is valuable, so I \nwill add some why text. Though I think adhering to the \"--smtp-server \nshould specify a host and --sendmail-cmd specifies a command\" dichotomy \nis a good reason in and of itself.\n\n>> @@ -1490,14 +1497,15 @@ sub send_message {\n>>\n>>  \tunshift (@sendmail_parameters, @smtp_server_options);\n>>\n>> +\tif (file_name_is_absolute($smtp_server)) {\n>> +\t\t# Preserved for backward compatibility\n>> +\t\t$sendmail_command ||= $smtp_server;\n>> +\t}\n>\n>Hmph, I wonder if this makes the intent more clear.\n>\n>\tif (!defined $sendmail_command && file_name_is_absolute($smtp_server)) {\n>\t\t$sendmail_command = $smtp_server;\n>\t}\n>\n>That is, if the user gave us the command in newer form, we do not\n>even have to bother checking if the server is given as an absolute\n>pathname.\n\nYes I think you're right, I'll make this change.\n\n>You seem to have replaced every smtp-server=\"$(pwd)/ mechanically\n>with sendmai-cmd=\\\"$(pwd)/, but please make sure that we have at\n>least one test left that passes an absolute path to --smtp-server to\n>ensure that the old mechanism keeps working.  A bonus point for\n>marking such a test that needs to be adjusted when the actual\n>deprecation happens (i.e. we'd likely to detect the use of absolute\n>path and throw a warning, so the test should notice the warning\n>message).\n\nNoted, I'll add a test for this case.\n\n>Also you would want to tweak some of the --sendmail-cmd variants to\n>use just the command name, with and without args, to ensure that (1)\n>discovery on $PATH works, and (2) passing initial args works.\n\nI did add two such tests:\n\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 65b3035371..82a3efb987 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -2148,6 +2148,29 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '\n         test_cmp expected-list actual-list\n  '\n\n+test_expect_success $PREREQ 'test using relative path with sendmailCommand' '\n+       clean_fake_sendmail &&\n+       PATH=\"$(pwd):$PATH\" \\\n+       git send-email \\\n+               --from=\"Example <nobody@example.com>\" \\\n+               --to=nobody@example.com \\\n+               --sendmail-cmd=\"fake.sendmail\" \\\n+               HEAD~2 &&\n+       test_path_is_file commandline1 &&\n+       test_path_is_file commandline2\n+'\n+\n+test_expect_success $PREREQ 'test using shell with sendmailCommand' '\n+       clean_fake_sendmail &&\n+       git send-email \\\n+               --from=\"Example <nobody@example.com>\" \\\n+               --to=nobody@example.com \\\n+               --sendmail-cmd=\"[ 1 -eq 1 ] && \\\"$(pwd)/fake.sendmail\\\"\" \\\n+               HEAD~2 &&\n+       test_path_is_file commandline1 &&\n+       test_path_is_file commandline2\n+'\n+\n  test_expect_success $PREREQ 'invoke hook' '\n         mkdir -p .git/hooks &&\n\n\nGranted, the second test tests for some generic shell expression, not \npassing arguments, but I think if the former works the latter ought to \nas well.\n\nThanks for your feedback.\n"},{"id":"424327","messageId":"YJvUMTAVKJqPZF2t@gpanders.com","threadId":"55668","inReplyTo":"609b8a5a65826_6e0fc2084c@natae.notmuch","subject":"Re: [PATCH] git-send-email: add sendmailCommand option","fromName":"Gregory Anders","fromEmail":"greg@gpanders.com","sentAt":"2021-05-12T13:12:17Z","receivedAt":"2021-05-12T13:12:25Z","isPatch":true,"sender":{"key":"greg@gpanders.com","avatar":"https://avatars.githubusercontent.com/u/8965202?v=4"},"body":"On Wed, 12 May 2021 02:57 -0500, Felipe Contreras wrote:\n>Gregory Anders wrote:\n>I'm not against these kinds of changes but it took me one minute to\n>figure out all you did was change the format.\n>\n>This belongs in a separate patch.\n\nYes this was pointed out by the other reviewers as well, I'll omit it in \nsubsequent revisions.\n\n>\n>> +--sendmail-cmd=<command>::\n>\n>Oh no no no. Don't do shortcuts.\n>\n>If you think --sendmail-command is too long, then address that problem\n>head on, don't try to hide it.\n>\n>I do think it's too long, which is why I suggested --command (especially\n>since it's obvious which command we are talking about), but I wouldn't\n>suggest --sdm-command, or something of that sort. We have to own our\n>decisions.\n>\n>  1. --command\n>  2. --sendmail\n>  3. --sendmail-command\n>\n>We have to pick one. I suggest #1.\n>\n>To try to make #3 shorter is just shoving the problem under the rug.\n\nThe intention behind `--sendmail-cmd` was consistency with `--to-cmd` \nand `--cc-cmd`. Though both of those options also use the condensed \n'cmd' form in their configuration options as well, so I suppose I should \nalso change this one to 'sendemail.sendmailcmd'.\n\nI'm not opposed to just '--sendmail' and 'sendemail.sendmail' either. I \npersonally believe --sendmail-cmd is the clearest, even if it's verbose, \nbut I'll concede to whatever consensus we arrive at.\n\n>\n>> --- a/git-send-email.perl\n>> +++ b/git-send-email.perl\n>> @@ -70,6 +70,7 @@ sub usage {\n>>\n>>    Sending:\n>>      --envelope-sender       <str>  * Email envelope sender.\n>> +    --sendmail-cmd          <str>  * Shell command to run to send email.\n>>      --smtp-server       <str:int>  * Outgoing SMTP server to use. The port\n>>                                       is optional. Default 'localhost'.\n>>      --smtp-server-option    <str>  * Outgoing SMTP server option to use.\n>> @@ -252,6 +253,7 @@ sub do_edit {\n>>  my (@suppress_cc);\n>>  my ($auto_8bit_encoding);\n>>  my ($compose_encoding);\n>> +my ($sendmail_command);\n>>  # Variables with corresponding config settings & hardcoded defaults\n>>  my ($debug_net_smtp) = 0;\t\t# Net::SMTP, see send_message()\n>>  my $thread = 1;\n>> @@ -299,6 +301,7 @@ sub do_edit {\n>>      \"assume8bitencoding\" => \\$auto_8bit_encoding,\n>>      \"composeencoding\" => \\$compose_encoding,\n>>      \"transferencoding\" => \\$target_xfer_encoding,\n>> +    \"sendmailcommand\" => \\$sendmail_command,\n>>  );\n>>\n>>  my %config_path_settings = (\n>> @@ -432,6 +435,7 @@ sub read_config {\n>>  \t\t    \"no-bcc\" => \\$no_bcc,\n>>  \t\t    \"chain-reply-to!\" => \\$chain_reply_to,\n>>  \t\t    \"no-chain-reply-to\" => sub {$chain_reply_to = 0},\n>> +\t\t    \"sendmail-cmd=s\" => \\$sendmail_command,\n>\n>Isn't it interesting that to make the code readable you picked\n>$sendmail_command, but you don't want users to type so much, even if\n>it's more readable?\n\nSee my note above.\n\n>\n>> --- a/t/t9001-send-email.sh\n>> +++ b/t/t9001-send-email.sh\n>> @@ -57,7 +57,7 @@ test_no_confirm () {\n>>  \t\tgit send-email \\\n>>  \t\t--from=\"Example <from@example.com>\" \\\n>>  \t\t--to=nobody@example.com \\\n>> -\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n>> +\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n>\n>People are already using --smpt-server=$cmd, we need to keep testing\n>that.\n>\n>Yes, eventually we would want them to move to --sendmail-cmd (or\n>--command, or whatever), but that won't happen tomorrow. Therefore our\n>primary tests need to be focused on --smtp-server.\n>\n>We need new *additional* tests for --sendmail-cmd, but those should not\n>override the current tests. At least not right now.\n\nI will add a test case for the absolute path form of --smtp-server; \nhowever, if we are introducing an option for specifying a sendmail-like \ncommand, surely that is the one to use when using \"fake.sendmail\", no?\n\nIf we leave the test cases as-is for now, we introduce a split that \nsomeone will eventually need to come back and update anyway. Instead of \nkicking that can down the road, I thought it best to go ahead and do it \nnow.\n\nThanks for your feedback.\n\nGreg\n"},{"id":"424328","messageId":"YJvVjLTFsES2i8a0@gpanders.com","threadId":"55668","inReplyTo":"87y2cks3lt.fsf@evledraar.gmail.com","subject":"Re: [PATCH] git-send-email: add sendmailCommand option","fromName":"Gregory Anders","fromEmail":"greg@gpanders.com","sentAt":"2021-05-12T13:18:04Z","receivedAt":"2021-05-12T13:18:11Z","isPatch":true,"sender":{"key":"greg@gpanders.com","avatar":"https://avatars.githubusercontent.com/u/8965202?v=4"},"body":"On Wed, 12 May 2021 11:04 +0200, Ævar Arnfjörð Bjarmason wrote:\n>\n>On Tue, May 11 2021, Gregory Anders wrote:\n>\n>> diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\n>> index 93708aefea..d9fe8cb7c0 100644\n>> --- a/Documentation/git-send-email.txt\n>> +++ b/Documentation/git-send-email.txt\n>> @@ -159,13 +159,23 @@ Sending\n>>  ~~~~~~~\n>>\n>>  --envelope-sender=<address>::\n>> -\tSpecify the envelope sender used to send the emails.\n>> -\tThis is useful if your default address is not the address that is\n>> -\tsubscribed to a list. In order to use the 'From' address, set the\n>> -\tvalue to \"auto\". If you use the sendmail binary, you must have\n>> -\tsuitable privileges for the -f parameter.  Default is the value of the\n>> -\t`sendemail.envelopeSender` configuration variable; if that is\n>> -\tunspecified, choosing the envelope sender is left to your MTA.\n>> +\tSpecify the envelope sender used to send the emails.  This is\n>> +\tuseful if your default address is not the address that is\n>> +\tsubscribed to a list. In order to use the 'From' address, set\n>> +\tthe value to \"auto\". If you use the sendmail binary, you must\n>> +\thave suitable privileges for the -f parameter.  Default is the\n>> +\tvalue of the `sendemail.envelopeSender` configuration variable;\n>> +\tif that is unspecified, choosing the envelope sender is left to\n>> +\tyour MTA.\n>\n>Please don't include word-wrapping for unrelated changes in the main\n>patch.\n\nMy mistake, this has been pointed out to me multiple times now. I'll \nremove it in the next revision and I'll be sure to avoid this in the \nfuture.\n\n>\n>> -\t$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*\n>> +\n>> +\tif (!defined $sendmail_command) {\n>> +\t\t$smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*\n>> +\t}\n>>  }\n>\n>This \"let's not accept a 0\" change seems unrelated & should be split\n>into a prep cleanup / refactoring patch. On the one hand it's sensible,\n>on the other nobody cares about having a command named \"0\" in their path\n>(or a hostname), so I think it's fine to have the ||= Perl idiom leak\n>out here.\n>\n>But also, this just seems like confusing logic. Per your docs \"your\n>sendmailCommand has precedence over smtpServer.\".\n>\n>Why not make this \"if not $sendmail_command\" part of the top-level check\n>here (the if this one is nested under), which is only done if\n>$smtp_sever is not defined, if $sendmail_command is defined we don't\n>care about $smtp_server later on, no?\n\nI mostly left this the way it is to minimize the diff, as this is the \nstyle the code was already written in. I agree that explicitly checking \nwhether sendmail_command is undefined is probably clearer to the reader.\n\n>\n>>  if ($compose && $compose > 0) {\n>> @@ -1490,14 +1497,15 @@ sub send_message {\n>>\n>>  \tunshift (@sendmail_parameters, @smtp_server_options);\n>>\n>> +\tif (file_name_is_absolute($smtp_server)) {\n>> +\t\t# Preserved for backward compatibility\n>> +\t\t$sendmail_command ||= $smtp_server;\n>> +\t}\n>> +\n>>  \tif ($dry_run) {\n>>  \t\t# We don't want to send the email.\n>> -\t} elsif (file_name_is_absolute($smtp_server)) {\n>> -\t\tmy $pid = open my $sm, '|-';\n>> -\t\tdefined $pid or die $!;\n>> -\t\tif (!$pid) {\n>> -\t\t\texec($smtp_server, @sendmail_parameters) or die $!;\n>> -\t\t}\n>> +\t} elsif (defined $sendmail_command) {\n>> +\t\topen my $sm, '|-', \"$sendmail_command @sendmail_parameters\";\n>\n>Can we really not avoid moving from exec-as-list so Perl quotes\n>everything, to doing our own interpolation here? It looks like the tests\n>don't check arguments with whitespace (which should fail with this\n>change).\n>\n\nShell interpolation in this case is considered a feature, not a bug, \ni.e. we want to provide users the ability to use arbitrary shell \nexpressions (as they do in e.g. aliases) or pass arguments. I also \nmodeled this after the implementation for --to-cmd and --cc-cmd, which \nalso run their respective commands in the shell just like this.\n\nAlso, this *did* cause the tests to fail since the tests write output to \na path with a space in it. You'll notice that in the diff for the tests \nI had to wrap '$(pwd)/fake.sendmail' in additional quotes to resolve \nthis.\n\n>> @@ -1592,14 +1600,14 @@ sub send_message {\n>>  \t\tprintf($dry_run ? __(\"Dry-Sent %s\\n\") : __(\"Sent %s\\n\"), $subject);\n>>  \t} else {\n>>  \t\tprint($dry_run ? __(\"Dry-OK. Log says:\\n\") : __(\"OK. Log says:\\n\"));\n>> -\t\tif (!file_name_is_absolute($smtp_server)) {\n>> +\t\tif (defined $sendmail_command) {\n>> +\t\t\tprint \"Sendmail: $sendmail_command \".join(' ',@sendmail_parameters).\"\\n\";\n>> +\t\t} else {\n>>  \t\t\tprint \"Server: $smtp_server\\n\";\n>>  \t\t\tprint \"MAIL FROM:<$raw_from>\\n\";\n>>  \t\t\tforeach my $entry (@recipients) {\n>>  \t\t\t    print \"RCPT TO:<$entry>\\n\";\n>>  \t\t\t}\n>> -\t\t} else {\n>> -\t\t\tprint \"Sendmail: $smtp_server \".join(' ',@sendmail_parameters).\"\\n\";\n>>  \t\t}\n>>  \t\tprint $header, \"\\n\";\n>>  \t\tif ($smtp) {\n>\n>Minor nit: Let's just continue to use \"if (!\" here to keep the diff\n>minimal or split up such refactoring into another change...\n\nSure, I can do that.\n\nThanks for your feedback.\n"},{"id":"424352","messageId":"609c0eaca8d28_71bd120878@natae.notmuch","threadId":"55668","inReplyTo":"YJvUMTAVKJqPZF2t@gpanders.com","subject":"Re: [PATCH] git-send-email: add sendmailCommand option","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2021-05-12T17:21:48Z","receivedAt":"2021-05-12T17:55:35Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Gregory Anders wrote:\n> >> +--sendmail-cmd=<command>::\n> >\n> >Oh no no no. Don't do shortcuts.\n> >\n> >If you think --sendmail-command is too long, then address that problem\n> >head on, don't try to hide it.\n> >\n> >I do think it's too long, which is why I suggested --command (especially\n> >since it's obvious which command we are talking about), but I wouldn't\n> >suggest --sdm-command, or something of that sort. We have to own our\n> >decisions.\n> >\n> >  1. --command\n> >  2. --sendmail\n> >  3. --sendmail-command\n> >\n> >We have to pick one. I suggest #1.\n> >\n> >To try to make #3 shorter is just shoving the problem under the rug.\n> \n> The intention behind `--sendmail-cmd` was consistency with `--to-cmd` \n> and `--cc-cmd`. Though both of those options also use the condensed \n> 'cmd' form in their configuration options as well, so I suppose I should \n> also change this one to 'sendemail.sendmailcmd'.\n\nI see. In that case that might make sense. I still prefer #1.\n\n> >> --- a/t/t9001-send-email.sh\n> >> +++ b/t/t9001-send-email.sh\n> >> @@ -57,7 +57,7 @@ test_no_confirm () {\n> >>  \t\tgit send-email \\\n> >>  \t\t--from=\"Example <from@example.com>\" \\\n> >>  \t\t--to=nobody@example.com \\\n> >> -\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n> >> +\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\"\" \\\n> >\n> >People are already using --smpt-server=$cmd, we need to keep testing\n> >that.\n> >\n> >Yes, eventually we would want them to move to --sendmail-cmd (or\n> >--command, or whatever), but that won't happen tomorrow. Therefore our\n> >primary tests need to be focused on --smtp-server.\n> >\n> >We need new *additional* tests for --sendmail-cmd, but those should not\n> >override the current tests. At least not right now.\n> \n> I will add a test case for the absolute path form of --smtp-server; \n> however, if we are introducing an option for specifying a sendmail-like \n> command, surely that is the one to use when using \"fake.sendmail\", no?\n> \n> If we leave the test cases as-is for now, we introduce a split that \n> someone will eventually need to come back and update anyway. Instead of \n> kicking that can down the road, I thought it best to go ahead and do it \n> now.\n\nThe sole purpose of software is that it's useful to users. Software that\nworks today but not tomorrow is bad software.\n\nThe primary purpose of the testing framework is to ensure that doesn't\nhappen; that git keeps working in the same way today than it did\nyesterday.\n\nThat's why it's more important that tests excercise the options people\nwere using yesterday.\n\nIn addition we also want to be testing new functionality, but that's *in\naddition*.\n\nMaybe at some point in the future more people will be using\n--sendmail-cmd, but right now that's not the case. Right now we need to\nbe testing the option people are using *today*.\n\nCheers.\n\n-- \nFelipe Contreras\n"},{"id":"424367","messageId":"YJwZFpxKLTch/N6O@gpanders.com","threadId":"55668","inReplyTo":"609c0eaca8d28_71bd120878@natae.notmuch","subject":"Re: [PATCH] git-send-email: add sendmailCommand option","fromName":"Gregory Anders","fromEmail":"greg@gpanders.com","sentAt":"2021-05-12T18:06:14Z","receivedAt":"2021-05-12T20:36:40Z","isPatch":true,"sender":{"key":"greg@gpanders.com","avatar":"https://avatars.githubusercontent.com/u/8965202?v=4"},"body":"On Wed, 12 May 2021 12:21 -0500, Felipe Contreras wrote:\n>The sole purpose of software is that it's useful to users. Software \n>that works today but not tomorrow is bad software.\n>\n>The primary purpose of the testing framework is to ensure that doesn't\n>happen; that git keeps working in the same way today than it did\n>yesterday.\n>\n>That's why it's more important that tests excercise the options people\n>were using yesterday.\n>\n>In addition we also want to be testing new functionality, but that's *in\n>addition*.\n>\n>Maybe at some point in the future more people will be using\n>--sendmail-cmd, but right now that's not the case. Right now we need to\n>be testing the option people are using *today*.\n\nI agree with this completely. Is this requirement satisfied with the \naddition of a test that checks the usage of an absolute path with \n--smtp-server (the behavior that people were using yesterday), while all \nof the existing tests are still converted to the new option? I have such \na test written (along with a few others) in the forthcoming v2 patch:\n\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 65b3035371..45bc3c0c4c 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -2148,6 +2148,55 @@ test_expect_success $PREREQ 'leading and trailing \nwhitespaces are removed' '\n  \ttest_cmp expected-list actual-list\n  '\n  \n+test_expect_success $PREREQ 'test using absolute path for --smtp-server' '\n+\tclean_fake_sendmail &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n+test_expect_success $PREREQ 'arguments not supported with --smtp-server' '\n+\ttest_expect_code 127 git send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail -f nobody@example.com\" \\\n+\t\tHEAD^\n+'\n+\n+test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tPATH=\"$(pwd):$PATH\" \\\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"fake.sendmail\" \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n+test_expect_success $PREREQ 'test using arguments with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\" -f nobody@example.com\" \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n+test_expect_success $PREREQ 'test shell expression with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"[ 1 -eq 1 ] && \\\"$(pwd)/fake.sendmail\\\"\" \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n  test_expect_success $PREREQ 'invoke hook' '\n         mkdir -p .git/hooks &&\n"},{"id":"424369","messageId":"609c2d652d592_71bd120824@natae.notmuch","threadId":"55668","inReplyTo":"YJwZFpxKLTch/N6O@gpanders.com","subject":"Re: [PATCH] git-send-email: add sendmailCommand option","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2021-05-12T19:32:53Z","receivedAt":"2021-05-12T20:36:41Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Gregory Anders wrote:\n> On Wed, 12 May 2021 12:21 -0500, Felipe Contreras wrote:\n> >The sole purpose of software is that it's useful to users. Software \n> >that works today but not tomorrow is bad software.\n> >\n> >The primary purpose of the testing framework is to ensure that doesn't\n> >happen; that git keeps working in the same way today than it did\n> >yesterday.\n> >\n> >That's why it's more important that tests excercise the options people\n> >were using yesterday.\n> >\n> >In addition we also want to be testing new functionality, but that's *in\n> >addition*.\n> >\n> >Maybe at some point in the future more people will be using\n> >--sendmail-cmd, but right now that's not the case. Right now we need to\n> >be testing the option people are using *today*.\n> \n> I agree with this completely. Is this requirement satisfied with the \n> addition of a test that checks the usage of an absolute path with \n> --smtp-server (the behavior that people were using yesterday), while all \n> of the existing tests are still converted to the new option? I have such \n> a test written (along with a few others) in the forthcoming v2 patch:\n\nI still insist the current tests should not be converted. But ultimately\nit's Junio's call.\n\nCheers.\n\n-- \nFelipe Contreras\n"},{"id":"424407","messageId":"20210513023212.72221-1-greg@gpanders.com","threadId":"55668","inReplyTo":"20210512033039.4022-1-greg@gpanders.com","subject":"[PATCH v2] git-send-email: add option to specify sendmail command","fromName":"Gregory Anders","fromEmail":"greg@gpanders.com","sentAt":"2021-05-13T02:32:11Z","receivedAt":"2021-05-13T02:32:52Z","isPatch":true,"sender":{"key":"greg@gpanders.com","avatar":"https://avatars.githubusercontent.com/u/8965202?v=4"},"body":"The sendemail.smtpServer configuration option and --smtp-server command\nline option both support using a sendmail-like program to send emails by\nspecifying an absolute file path. However, this is not ideal for the\nfollowing reasons:\n\n1. It overloads the meaning of smtpServer (now a program is being used\n   for the server?)\n2. It doesn't allow for non-absolute paths, arguments, or arbitrary\n   scripting\n\nRequiring an absolute path is bad for portability, as the same program\nmay be in different locations on different systems. If a user wishes to\npass arguments to their program, they have to use the smtpServerOption\noption, which is cumbersome (as it must be repeated for each option) and\ndoesn't adhere to normal git conventions.\n\nIntroduce a new configuration option sendemail.sendmailCmd as well as a\ncommand line option --sendmail-cmd that can be used to specify a command\n(with or without arguments) or shell expression to run to send email.\nThe name of this option is consistent with --to-cmd and --cc-cmd. This\ninvocation honors the user's $PATH so that absolute paths are not\nnecessary. Arbitrary shell expressions are also supported, allowing\nusers to do basic scripting.\n\nGive this option a higher precedence over --smtp-server and\nsendemail.smtpServer, as the new interface is more flexible. For\nbackward compatibility, continue to support absolute paths in\n--smtp-server and sendemail.smtpServer.\n\nSigned-off-by: Gregory Anders <greg@gpanders.com>\n---\n Documentation/git-send-email.txt | 26 +++++++++++++++++++-------\n git-send-email.perl              | 29 ++++++++++++++++++++++-------\n t/t9001-send-email.sh            | 31 +++++++++++++++++++++++++++++++\n 3 files changed, 72 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\nindex 93708aefea..f1e685a52c 100644\n--- a/Documentation/git-send-email.txt\n+++ b/Documentation/git-send-email.txt\n@@ -167,6 +167,15 @@ Sending\n \t`sendemail.envelopeSender` configuration variable; if that is\n \tunspecified, choosing the envelope sender is left to your MTA.\n \n+--sendmail-cmd=<command>::\n+\tSpecify a command to run to send the email. The command should\n+\tbe compatible with `sendmail` (specifically, it should support\n+\tthe `-i` option).  The command will be executed in the shell if\n+\tnecessary.  Default is the value of `sendemail.sendmailcmd`.  If\n+\tunspecified, and if --smtp-server is also unspecified,\n+\tgit-send-email will search for `sendmail` in `/usr/sbin`,\n+\t`/usr/lib` and $PATH.\n+\n --smtp-encryption=<encryption>::\n \tSpecify the encryption to use, either 'ssl' or 'tls'.  Any other\n \tvalue reverts to plain SMTP.  Default is the value of\n@@ -211,13 +220,16 @@ a password is obtained using 'git-credential'.\n \n --smtp-server=<host>::\n \tIf set, specifies the outgoing SMTP server to use (e.g.\n-\t`smtp.example.com` or a raw IP address).  Alternatively it can\n-\tspecify a full pathname of a sendmail-like program instead;\n-\tthe program must support the `-i` option.  Default value can\n-\tbe specified by the `sendemail.smtpServer` configuration\n-\toption; the built-in default is to search for `sendmail` in\n-\t`/usr/sbin`, `/usr/lib` and $PATH if such program is\n-\tavailable, falling back to `localhost` otherwise.\n+\t`smtp.example.com` or a raw IP address).  If unspecified, and if\n+\t`--sendmail-cmd` is also unspecified, the default is to search\n+\tfor `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH if such a\n+\tprogram is available, falling back to `localhost` otherwise.\n+\n+\tFor backward compatibility, this option can also specify a full\n+\tpathname of a sendmail-like program instead; the program must\n+\tsupport the `-i` option.  This method does not support passing\n+\targuments or using plain command names.  For those use cases,\n+\tconsider using `--sendmail-cmd` instead.\n \n --smtp-server-port=<port>::\n \tSpecifies a port different from the default port (SMTP\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 175da07d94..cbd9f89060 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -70,6 +70,7 @@ sub usage {\n \n   Sending:\n     --envelope-sender       <str>  * Email envelope sender.\n+    --sendmail-cmd          <str>  * Command to run to send email.\n     --smtp-server       <str:int>  * Outgoing SMTP server to use. The port\n                                      is optional. Default 'localhost'.\n     --smtp-server-option    <str>  * Outgoing SMTP server option to use.\n@@ -252,6 +253,7 @@ sub do_edit {\n my (@suppress_cc);\n my ($auto_8bit_encoding);\n my ($compose_encoding);\n+my ($sendmail_cmd);\n # Variables with corresponding config settings & hardcoded defaults\n my ($debug_net_smtp) = 0;\t\t# Net::SMTP, see send_message()\n my $thread = 1;\n@@ -299,6 +301,7 @@ sub do_edit {\n     \"assume8bitencoding\" => \\$auto_8bit_encoding,\n     \"composeencoding\" => \\$compose_encoding,\n     \"transferencoding\" => \\$target_xfer_encoding,\n+    \"sendmailcmd\" => \\$sendmail_cmd,\n );\n \n my %config_path_settings = (\n@@ -432,6 +435,7 @@ sub read_config {\n \t\t    \"no-bcc\" => \\$no_bcc,\n \t\t    \"chain-reply-to!\" => \\$chain_reply_to,\n \t\t    \"no-chain-reply-to\" => sub {$chain_reply_to = 0},\n+\t\t    \"sendmail-cmd=s\" => \\$sendmail_cmd,\n \t\t    \"smtp-server=s\" => \\$smtp_server,\n \t\t    \"smtp-server-option=s\" => \\@smtp_server_options,\n \t\t    \"smtp-server-port=s\" => \\$smtp_server_port,\n@@ -1003,16 +1007,19 @@ sub expand_one_alias {\n \t$reply_to = sanitize_address($reply_to);\n }\n \n-if (!defined $smtp_server) {\n+if (!defined $sendmail_cmd && !defined $smtp_server) {\n \tmy @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );\n \tpush @sendmail_paths, map {\"$_/sendmail\"} split /:/, $ENV{PATH};\n \tforeach (@sendmail_paths) {\n \t\tif (-x $_) {\n-\t\t\t$smtp_server = $_;\n+\t\t\t$sendmail_cmd = $_;\n \t\t\tlast;\n \t\t}\n \t}\n-\t$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*\n+\n+\tif (!defined $sendmail_cmd) {\n+\t\t$smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*\n+\t}\n }\n \n if ($compose && $compose > 0) {\n@@ -1492,11 +1499,15 @@ sub send_message {\n \n \tif ($dry_run) {\n \t\t# We don't want to send the email.\n-\t} elsif (file_name_is_absolute($smtp_server)) {\n+\t} elsif (defined $sendmail_cmd || file_name_is_absolute($smtp_server)) {\n \t\tmy $pid = open my $sm, '|-';\n \t\tdefined $pid or die $!;\n \t\tif (!$pid) {\n-\t\t\texec($smtp_server, @sendmail_parameters) or die $!;\n+\t\t\tif (defined $sendmail_cmd) {\n+\t\t\t\texec \"$sendmail_cmd @sendmail_parameters\" or die $!;\n+\t\t\t} else {\n+\t\t\t\texec ($smtp_server, @sendmail_parameters) or die $!;\n+\t\t\t}\n \t\t}\n \t\tprint $sm \"$header\\n$message\";\n \t\tclose $sm or die $!;\n@@ -1592,14 +1603,18 @@ sub send_message {\n \t\tprintf($dry_run ? __(\"Dry-Sent %s\\n\") : __(\"Sent %s\\n\"), $subject);\n \t} else {\n \t\tprint($dry_run ? __(\"Dry-OK. Log says:\\n\") : __(\"OK. Log says:\\n\"));\n-\t\tif (!file_name_is_absolute($smtp_server)) {\n+\t\tif (!defined $sendmail_cmd && !file_name_is_absolute($smtp_server)) {\n \t\t\tprint \"Server: $smtp_server\\n\";\n \t\t\tprint \"MAIL FROM:<$raw_from>\\n\";\n \t\t\tforeach my $entry (@recipients) {\n \t\t\t    print \"RCPT TO:<$entry>\\n\";\n \t\t\t}\n \t\t} else {\n-\t\t\tprint \"Sendmail: $smtp_server \".join(' ',@sendmail_parameters).\"\\n\";\n+\t\t\tif (!defined $sendmail_cmd) {\n+\t\t\t\t$sendmail_cmd = $smtp_server;\n+\t\t\t}\n+\n+\t\t\tprint \"Sendmail: $sendmail_cmd \".join(' ',@sendmail_parameters).\"\\n\";\n \t\t}\n \t\tprint $header, \"\\n\";\n \t\tif ($smtp) {\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 65b3035371..583fbba410 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -2148,6 +2148,37 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '\n \ttest_cmp expected-list actual-list\n '\n \n+test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tPATH=\"$(pwd):$PATH\" \\\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"fake.sendmail\" \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n+test_expect_success $PREREQ 'test using arguments with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\" -f nobody@example.com\" \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n+test_expect_success $PREREQ 'test shell expression with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"f() { \\\"$(pwd)/fake.sendmail\\\" \\\"\\$@\\\"; };f\" \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n test_expect_success $PREREQ 'invoke hook' '\n \tmkdir -p .git/hooks &&\n \n-- \n2.31.1\n\n"},{"id":"424412","messageId":"xmqq8s4jcmj7.fsf@gitster.g","threadId":"55668","inReplyTo":"20210513023212.72221-1-greg@gpanders.com","subject":"Re: [PATCH v2] git-send-email: add option to specify sendmail command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-05-13T03:58:36Z","receivedAt":"2021-05-13T03:58:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Gregory Anders <greg@gpanders.com> writes:\n\n> The sendemail.smtpServer configuration option and --smtp-server command\n> line option both support using a sendmail-like program to send emails by\n> specifying an absolute file path. However, this is not ideal for the\n> following reasons:\n>\n> 1. It overloads the meaning of smtpServer (now a program is being used\n>    for the server?)\n> 2. It doesn't allow for non-absolute paths, arguments, or arbitrary\n>    scripting\n>\n> Requiring an absolute path is bad for portability, as the same program\n> may be in different locations on different systems. If a user wishes to\n> pass arguments to their program, they have to use the smtpServerOption\n> option, which is cumbersome (as it must be repeated for each option) and\n> doesn't adhere to normal git conventions.\n>\n> Introduce a new configuration option sendemail.sendmailCmd as well as a\n> command line option --sendmail-cmd that can be used to specify a command\n> (with or without arguments) or shell expression to run to send email.\n> The name of this option is consistent with --to-cmd and --cc-cmd. This\n> invocation honors the user's $PATH so that absolute paths are not\n> necessary. Arbitrary shell expressions are also supported, allowing\n> users to do basic scripting.\n>\n> Give this option a higher precedence over --smtp-server and\n> sendemail.smtpServer, as the new interface is more flexible. For\n> backward compatibility, continue to support absolute paths in\n> --smtp-server and sendemail.smtpServer.\n>\n> Signed-off-by: Gregory Anders <greg@gpanders.com>\n> ---\n\nQuite well explained.\n\n> diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\n> index 93708aefea..f1e685a52c 100644\n> --- a/Documentation/git-send-email.txt\n> +++ b/Documentation/git-send-email.txt\n> @@ -167,6 +167,15 @@ Sending\n>  \t`sendemail.envelopeSender` configuration variable; if that is\n>  \tunspecified, choosing the envelope sender is left to your MTA.\n>  \n> +--sendmail-cmd=<command>::\n> +\tSpecify a command to run to send the email. The command should\n> +\tbe compatible with `sendmail` (specifically, it should support\n> +\tthe `-i` option).  The command will be executed in the shell if\n> +\tnecessary.  Default is the value of `sendemail.sendmailcmd`.  If\n> +\tunspecified, and if --smtp-server is also unspecified,\n> +\tgit-send-email will search for `sendmail` in `/usr/sbin`,\n> +\t`/usr/lib` and $PATH.\n\nOK.\n\n>  --smtp-encryption=<encryption>::\n>  \tSpecify the encryption to use, either 'ssl' or 'tls'.  Any other\n>  \tvalue reverts to plain SMTP.  Default is the value of\n> @@ -211,13 +220,16 @@ a password is obtained using 'git-credential'.\n>  \n>  --smtp-server=<host>::\n>  \tIf set, specifies the outgoing SMTP server to use (e.g.\n> -\t`smtp.example.com` or a raw IP address).  Alternatively it can\n> -\tspecify a full pathname of a sendmail-like program instead;\n> -\tthe program must support the `-i` option.  Default value can\n> -\tbe specified by the `sendemail.smtpServer` configuration\n> -\toption; the built-in default is to search for `sendmail` in\n> -\t`/usr/sbin`, `/usr/lib` and $PATH if such program is\n> -\tavailable, falling back to `localhost` otherwise.\n> +\t`smtp.example.com` or a raw IP address).  If unspecified, and if\n> +\t`--sendmail-cmd` is also unspecified, the default is to search\n> +\tfor `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH if such a\n> +\tprogram is available, falling back to `localhost` otherwise.\n> +\n> +\tFor backward compatibility, this option can also specify a full\n> +\tpathname of a sendmail-like program instead; the program must\n> +\tsupport the `-i` option.  This method does not support passing\n> +\targuments or using plain command names.  For those use cases,\n> +\tconsider using `--sendmail-cmd` instead.\n\nTwo comments here:\n\n - The paragraph would probably not render well, unless you replace\n   the blank \"paragraph break\" line before it with a line that\n   consists of a sole '+', and dedent the paragraph body.\n\n - The way the \"-i\" option is mentioned is different from the one we saw\n   earlier for `--sendmail-cmd` and might risk puzzling the users if\n   the requirement is subtly different.\n\n> diff --git a/git-send-email.perl b/git-send-email.perl\n> index 175da07d94..cbd9f89060 100755\n> --- a/git-send-email.perl\n> +++ b/git-send-email.perl\n> ...\n> @@ -1492,11 +1499,15 @@ sub send_message {\n>  \n>  \tif ($dry_run) {\n>  \t\t# We don't want to send the email.\n> -\t} elsif (file_name_is_absolute($smtp_server)) {\n> +\t} elsif (defined $sendmail_cmd || file_name_is_absolute($smtp_server)) {\n>  \t\tmy $pid = open my $sm, '|-';\n>  \t\tdefined $pid or die $!;\n>  \t\tif (!$pid) {\n> -\t\t\texec($smtp_server, @sendmail_parameters) or die $!;\n> +\t\t\tif (defined $sendmail_cmd) {\n> +\t\t\t\texec \"$sendmail_cmd @sendmail_parameters\" or die $!;\n\nThis looks problematic, as @sendmail_parameters is computed like\nthis:\n\n\tmy @sendmail_parameters = ('-i', @recipients);\n\t...\n\t$raw_from = extract_valid_address($raw_from);\n\tunshift (@sendmail_parameters,\n\t\t\t'-f', $raw_from) if(defined $envelope_sender);\n\t...\n       \tunshift (@sendmail_parameters, @smtp_server_options);\n\nNotice that nothing quotes its elements for the shell, and it is\nnatural if we think about the original use of this array---it is to\nbe fed to the array form of exec($cmd, @args).\n\n@recipients, and $raw_from come from extract_valid_address(), which\ngives 'add@ress' for \"Human readable name <add@ress>\", and it may be\nrare (but possible) to have a problematic characer in them.  But the\nelements of @smtp_server_options can be anything, and because the\nvalues the end users already have in their configuration files are\ndesigned to be used in the original \"exec ($smtp_server,\n@sendmail_parameters)\" codepath, they would not be quoted for the\nshell, and they should not be treated differently in the new codepath.\n\nIn short, it is far from sufficient to just \"$concatenate @variables\"\nto form a single string.  $sendmail_cmd should be left as-is (after\nall, we do want the shell to split it at $IFS whitespace into tokens),\nbut each element of @sendmail_parameters should be protected from\nthe shell (both word splitting and $interpolation rules).  Perhaps\nsomething along the lines of this instead?\n\n    exec (\"sh\", \"-c\", \"$sendmail_cmd \\\"\\$\\@\\\"\", \"-\", @sendmail_parameters);\n\n> +\t\t\t} else {\n> +\t\t\t\texec ($smtp_server, @sendmail_parameters) or die $!;\n> +\t\t\t}\n\nOther than that, looking good.\n\nThanks.\n"},{"id":"424471","messageId":"YJ0qMro2oP1Q5Ohw@gpanders.com","threadId":"55668","inReplyTo":"xmqq8s4jcmj7.fsf@gitster.g","subject":"Re: [PATCH v2] git-send-email: add option to specify sendmail command","fromName":"Gregory Anders","fromEmail":"greg@gpanders.com","sentAt":"2021-05-13T13:31:30Z","receivedAt":"2021-05-13T13:31:46Z","isPatch":true,"sender":{"key":"greg@gpanders.com","avatar":"https://avatars.githubusercontent.com/u/8965202?v=4"},"body":"On Thu, 13 May 2021 12:58 +0900, Junio C Hamano wrote:\n>In short, it is far from sufficient to just \"$concatenate @variables\"\n>to form a single string.  $sendmail_cmd should be left as-is (after\n>all, we do want the shell to split it at $IFS whitespace into tokens),\n>but each element of @sendmail_parameters should be protected from\n>the shell (both word splitting and $interpolation rules).  Perhaps\n>something along the lines of this instead?\n>\n>    exec (\"sh\", \"-c\", \"$sendmail_cmd \\\"\\$\\@\\\"\", \"-\", @sendmail_parameters);\n\nDoes this pose a problem for platforms such as Windows that don't have a \n'sh' (not sure if there are any others)? Is git-send-email meant to \nsupport Windows?\n"},{"id":"424481","messageId":"20210513152329.22578-1-greg@gpanders.com","threadId":"55668","inReplyTo":"20210513023212.72221-1-greg@gpanders.com","subject":"[PATCH v3] git-send-email: add option to specify sendmail command","fromName":"Gregory Anders","fromEmail":"greg@gpanders.com","sentAt":"2021-05-13T15:23:29Z","receivedAt":"2021-05-13T15:23:50Z","isPatch":true,"sender":{"key":"greg@gpanders.com","avatar":"https://avatars.githubusercontent.com/u/8965202?v=4"},"body":"The sendemail.smtpServer configuration option and --smtp-server command\nline option both support using a sendmail-like program to send emails by\nspecifying an absolute file path. However, this is not ideal for the\nfollowing reasons:\n\n1. It overloads the meaning of smtpServer (now a program is being used\n   for the server?)\n2. It doesn't allow for non-absolute paths, arguments, or arbitrary\n   scripting\n\nRequiring an absolute path is bad for portability, as the same program\nmay be in different locations on different systems. If a user wishes to\npass arguments to their program, they have to use the smtpServerOption\noption, which is cumbersome (as it must be repeated for each option) and\ndoesn't adhere to normal git conventions.\n\nIntroduce a new configuration option sendemail.sendmailCmd as well as a\ncommand line option --sendmail-cmd that can be used to specify a command\n(with or without arguments) or shell expression to run to send email.\nThe name of this option is consistent with --to-cmd and --cc-cmd. This\ninvocation honors the user's $PATH so that absolute paths are not\nnecessary. Arbitrary shell expressions are also supported, allowing\nusers to do basic scripting.\n\nGive this option a higher precedence over --smtp-server and\nsendemail.smtpServer, as the new interface is more flexible. For\nbackward compatibility, continue to support absolute paths in\n--smtp-server and sendemail.smtpServer.\n\nSigned-off-by: Gregory Anders <greg@gpanders.com>\n---\n\nFix and reword the documentation to hopefully be more consistent between \n--sendmail-cmd and --smtp-server.\n\nUpdate the invocation of \"sendmail_cmd\" to ensure that parameters are \nnot expanded by the shell (the parameters may contain any number of \nspecial characters that are not intended to be interpreted by the \nshell).\n\nUse a block scoped variable to print the sendmail invocation at the end \nof the 'send_message' subroutine. Assigning directly to $sendmail_cmd \n(as in the v2 patch) causes some bizarre problems; namely, it seems to \naffect the value of $sendmail_cmd that is read at earlier points in the \nsame subroutine, which causes test invocations of the form\n\n    git send-email --smtp-server=\"$(pwd)/fake.sendmail\"\n\nto fail. The value passed to --smtp-server was assigned to $sendmail_cmd \nat the end of the 'send_message' subprocedure, but somehow this caused \nthe 'if (defined $sendmail_cmd)' condition earlier in the subproc to \nevaluate to true. This would fail because $sendmail_cmd is expanded in \nthe shell, and since $(pwd) contains a space the command was being \nsplit, resulting in a \"command not found\" error. I don't have enough \nPerl experience to explain what's happening in this case, but using a \nscoped variable resolves the issue.\n\n Documentation/git-send-email.txt | 25 ++++++++++++++++-------\n git-send-email.perl              | 34 +++++++++++++++++++++++++-------\n t/t9001-send-email.sh            | 31 +++++++++++++++++++++++++++++\n 3 files changed, 76 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\nindex 93708aefea..3db4eab4ba 100644\n--- a/Documentation/git-send-email.txt\n+++ b/Documentation/git-send-email.txt\n@@ -167,6 +167,14 @@ Sending\n \t`sendemail.envelopeSender` configuration variable; if that is\n \tunspecified, choosing the envelope sender is left to your MTA.\n \n+--sendmail-cmd=<command>::\n+\tSpecify a command to run to send the email. The command should\n+\tbe sendmail-like; specifically, it must support the `-i` option.\n+\tThe command will be executed in the shell if necessary.  Default\n+\tis the value of `sendemail.sendmailcmd`.  If unspecified, and if\n+\t--smtp-server is also unspecified, git-send-email will search\n+\tfor `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH.\n+\n --smtp-encryption=<encryption>::\n \tSpecify the encryption to use, either 'ssl' or 'tls'.  Any other\n \tvalue reverts to plain SMTP.  Default is the value of\n@@ -211,13 +219,16 @@ a password is obtained using 'git-credential'.\n \n --smtp-server=<host>::\n \tIf set, specifies the outgoing SMTP server to use (e.g.\n-\t`smtp.example.com` or a raw IP address).  Alternatively it can\n-\tspecify a full pathname of a sendmail-like program instead;\n-\tthe program must support the `-i` option.  Default value can\n-\tbe specified by the `sendemail.smtpServer` configuration\n-\toption; the built-in default is to search for `sendmail` in\n-\t`/usr/sbin`, `/usr/lib` and $PATH if such program is\n-\tavailable, falling back to `localhost` otherwise.\n+\t`smtp.example.com` or a raw IP address).  If unspecified, and if\n+\t`--sendmail-cmd` is also unspecified, the default is to search\n+\tfor `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH if such a\n+\tprogram is available, falling back to `localhost` otherwise.\n++\n+For backward compatibility, this option can also specify a full pathname\n+of a sendmail-like program instead; the program must support the `-i`\n+option.  This method does not support passing arguments or using plain\n+command names.  For those use cases, consider using `--sendmail-cmd`\n+instead.\n \n --smtp-server-port=<port>::\n \tSpecifies a port different from the default port (SMTP\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 175da07d94..dbb144aa11 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -70,6 +70,7 @@ sub usage {\n \n   Sending:\n     --envelope-sender       <str>  * Email envelope sender.\n+    --sendmail-cmd          <str>  * Command to run to send email.\n     --smtp-server       <str:int>  * Outgoing SMTP server to use. The port\n                                      is optional. Default 'localhost'.\n     --smtp-server-option    <str>  * Outgoing SMTP server option to use.\n@@ -252,6 +253,7 @@ sub do_edit {\n my (@suppress_cc);\n my ($auto_8bit_encoding);\n my ($compose_encoding);\n+my ($sendmail_cmd);\n # Variables with corresponding config settings & hardcoded defaults\n my ($debug_net_smtp) = 0;\t\t# Net::SMTP, see send_message()\n my $thread = 1;\n@@ -299,6 +301,7 @@ sub do_edit {\n     \"assume8bitencoding\" => \\$auto_8bit_encoding,\n     \"composeencoding\" => \\$compose_encoding,\n     \"transferencoding\" => \\$target_xfer_encoding,\n+    \"sendmailcmd\" => \\$sendmail_cmd,\n );\n \n my %config_path_settings = (\n@@ -432,6 +435,7 @@ sub read_config {\n \t\t    \"no-bcc\" => \\$no_bcc,\n \t\t    \"chain-reply-to!\" => \\$chain_reply_to,\n \t\t    \"no-chain-reply-to\" => sub {$chain_reply_to = 0},\n+\t\t    \"sendmail-cmd=s\" => \\$sendmail_cmd,\n \t\t    \"smtp-server=s\" => \\$smtp_server,\n \t\t    \"smtp-server-option=s\" => \\@smtp_server_options,\n \t\t    \"smtp-server-port=s\" => \\$smtp_server_port,\n@@ -1003,16 +1007,19 @@ sub expand_one_alias {\n \t$reply_to = sanitize_address($reply_to);\n }\n \n-if (!defined $smtp_server) {\n+if (!defined $sendmail_cmd && !defined $smtp_server) {\n \tmy @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );\n \tpush @sendmail_paths, map {\"$_/sendmail\"} split /:/, $ENV{PATH};\n \tforeach (@sendmail_paths) {\n \t\tif (-x $_) {\n-\t\t\t$smtp_server = $_;\n+\t\t\t$sendmail_cmd = $_;\n \t\t\tlast;\n \t\t}\n \t}\n-\t$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*\n+\n+\tif (!defined $sendmail_cmd) {\n+\t\t$smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*\n+\t}\n }\n \n if ($compose && $compose > 0) {\n@@ -1492,11 +1499,17 @@ sub send_message {\n \n \tif ($dry_run) {\n \t\t# We don't want to send the email.\n-\t} elsif (file_name_is_absolute($smtp_server)) {\n+\t} elsif (defined $sendmail_cmd || file_name_is_absolute($smtp_server)) {\n \t\tmy $pid = open my $sm, '|-';\n \t\tdefined $pid or die $!;\n \t\tif (!$pid) {\n-\t\t\texec($smtp_server, @sendmail_parameters) or die $!;\n+\t\t\tif (defined $sendmail_cmd) {\n+\t\t\t\texec (\"sh\", \"-c\", \"$sendmail_cmd \\\"\\$@\\\"\", \"-\", @sendmail_parameters)\n+\t\t\t\t\tor die $!;\n+\t\t\t} else {\n+\t\t\t\texec ($smtp_server, @sendmail_parameters)\n+\t\t\t\t\tor die $!;\n+\t\t\t}\n \t\t}\n \t\tprint $sm \"$header\\n$message\";\n \t\tclose $sm or die $!;\n@@ -1592,14 +1605,21 @@ sub send_message {\n \t\tprintf($dry_run ? __(\"Dry-Sent %s\\n\") : __(\"Sent %s\\n\"), $subject);\n \t} else {\n \t\tprint($dry_run ? __(\"Dry-OK. Log says:\\n\") : __(\"OK. Log says:\\n\"));\n-\t\tif (!file_name_is_absolute($smtp_server)) {\n+\t\tif (!defined $sendmail_cmd && !file_name_is_absolute($smtp_server)) {\n \t\t\tprint \"Server: $smtp_server\\n\";\n \t\t\tprint \"MAIL FROM:<$raw_from>\\n\";\n \t\t\tforeach my $entry (@recipients) {\n \t\t\t    print \"RCPT TO:<$entry>\\n\";\n \t\t\t}\n \t\t} else {\n-\t\t\tprint \"Sendmail: $smtp_server \".join(' ',@sendmail_parameters).\"\\n\";\n+\t\t\tmy $sm;\n+\t\t\tif (defined $sendmail_cmd) {\n+\t\t\t\t$sm = $sendmail_cmd;\n+\t\t\t} else {\n+\t\t\t\t$sm = $smtp_server;\n+\t\t\t}\n+\n+\t\t\tprint \"Sendmail: $sm \".join(' ',@sendmail_parameters).\"\\n\";\n \t\t}\n \t\tprint $header, \"\\n\";\n \t\tif ($smtp) {\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 65b3035371..583fbba410 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -2148,6 +2148,37 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '\n \ttest_cmp expected-list actual-list\n '\n \n+test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tPATH=\"$(pwd):$PATH\" \\\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"fake.sendmail\" \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n+test_expect_success $PREREQ 'test using arguments with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\" -f nobody@example.com\" \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n+test_expect_success $PREREQ 'test shell expression with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"f() { \\\"$(pwd)/fake.sendmail\\\" \\\"\\$@\\\"; };f\" \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n test_expect_success $PREREQ 'invoke hook' '\n \tmkdir -p .git/hooks &&\n \n-- \n2.31.1\n\n"},{"id":"424514","messageId":"xmqqfsyq9vok.fsf@gitster.g","threadId":"55668","inReplyTo":"YJ0qMro2oP1Q5Ohw@gpanders.com","subject":"Re: [PATCH v2] git-send-email: add option to specify sendmail command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-05-13T21:21:31Z","receivedAt":"2021-05-13T21:21:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Gregory Anders <greg@gpanders.com> writes:\n\n> On Thu, 13 May 2021 12:58 +0900, Junio C Hamano wrote:\n>>In short, it is far from sufficient to just \"$concatenate @variables\"\n>>to form a single string.  $sendmail_cmd should be left as-is (after\n>>all, we do want the shell to split it at $IFS whitespace into tokens),\n>>but each element of @sendmail_parameters should be protected from\n>>the shell (both word splitting and $interpolation rules).  Perhaps\n>>something along the lines of this instead?\n>>\n>>    exec (\"sh\", \"-c\", \"$sendmail_cmd \\\"\\$\\@\\\"\", \"-\", @sendmail_parameters);\n>\n> Does this pose a problem for platforms such as Windows that don't have\n> a 'sh' (not sure if there are any others)? Is git-send-email meant to \n> support Windows?\n\nSeeing what run-command.c::prepare_shell_cmd() does under\nGIT_WINDOWS_NATIVE (or on other platforms), I doubt the construct\nwould be a problem.  Our Windows experts would certainly chime in\nif it is.\n\nThanks.\n\n\n"},{"id":"424540","messageId":"xmqq7dk27xi2.fsf@gitster.g","threadId":"55668","inReplyTo":"20210513152329.22578-1-greg@gpanders.com","subject":"Re: [PATCH v3] git-send-email: add option to specify sendmail command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-05-14T04:25:09Z","receivedAt":"2021-05-14T04:25:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Gregory Anders <greg@gpanders.com> writes:\n\n> Use a block scoped variable to print the sendmail invocation at the end \n> of the 'send_message' subroutine. Assigning directly to $sendmail_cmd \n> (as in the v2 patch) causes some bizarre problems; namely, it seems to \n> affect the value of $sendmail_cmd that is read at earlier points in the \n> same subroutine, which causes test invocations of the form\n>\n>     git send-email --smtp-server=\"$(pwd)/fake.sendmail\"\n>\n> to fail. The value passed to --smtp-server was assigned to $sendmail_cmd \n> at the end of the 'send_message' subprocedure, but somehow this caused \n> the 'if (defined $sendmail_cmd)' condition earlier in the subproc to \n> evaluate to true.\n\nAre you talking about the use of $sm that is local to the debug\noutput?  I think leaving $sendmail_cmd intact by using a separate\nvariable is the right choice.  Isn't the problem you observed a\nconsequence of send_message() getting called once for each message,\nso assigning to $sendmail_cmd in the function for the first\ninvocation of the function would change its value for the second\ninvocation?\n\nAlso, if we have been using\n\n\t--smtp-server=$(pwd)/fake.sendmail\n\nwe cannot expect to use the same value like this:\n\n\t--sendmail-cmd=$(pwd)/fake.sendmail\n\nbecause we deliberately add a space in the $(pwd) by choosing the\nname of the test directory to be \"trash directory.something\".  We'd\nneed to do something like\n\n\t--sendmail-cmd='$(pwd)/fake.sendmail'\n\nso that the shell sees '$(pwd)/fake.sendmail' literally and runs pwd\nto find out what the path to the program is, I would think.\n\n> diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\n> index 65b3035371..583fbba410 100755\n> --- a/t/t9001-send-email.sh\n> +++ b/t/t9001-send-email.sh\n> @@ -2148,6 +2148,37 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '\n>  \ttest_cmp expected-list actual-list\n>  '\n>  \n> +test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '\n> +\tclean_fake_sendmail &&\n> +\tPATH=\"$(pwd):$PATH\" \\\n> +\tgit send-email \\\n> +\t\t--from=\"Example <nobody@example.com>\" \\\n> +\t\t--to=nobody@example.com \\\n> +\t\t--sendmail-cmd=\"fake.sendmail\" \\\n> +\t\tHEAD^ &&\n> +\ttest_path_is_file commandline1\n> +'\n\nNice demonstration of the \"we no longer need an absolute pathname\"\nfeature.\n\n> +test_expect_success $PREREQ 'test using arguments with --sendmail-cmd' '\n> +\tclean_fake_sendmail &&\n> +\tgit send-email \\\n> +\t\t--from=\"Example <nobody@example.com>\" \\\n> +\t\t--to=nobody@example.com \\\n> +\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\" -f nobody@example.com\" \\\n> +\t\tHEAD^ &&\n> +\ttest_path_is_file commandline1\n> +'\n\nHmph, if $(pwd) has a double quote character in it, this may not\nwork as expected, as the shell that is expanding the command line\narguments for \"git send-email\" would see $(pwd), expand it and our\nprogram will see\n\n    \"/path/with/d\"quote/git/t/trash directory.9001/fake.sendmail\" -f nobody@e.c\n\nas the value of --sendmail-cmd, which would not interpolate well,\nno?\n\nWe want the shell that eats the command line of 'git send-email' to see\n\n\t--sendmail-cmd='$(pwd)/fake.sendmail'\\\" -f nobody@example.com\"\n\nand because this is inside a sq pair, it would become\n\n\t--sendmail-cmd='\\''$(pwd)/fake.sendmail'\\''\\\" -f nobody@example.com\"\n\nafter we replace each sq with '\\'', or something like that, perhaps?\n\n> +test_expect_success $PREREQ 'test shell expression with --sendmail-cmd' '\n> +\tclean_fake_sendmail &&\n> +\tgit send-email \\\n> +\t\t--from=\"Example <nobody@example.com>\" \\\n> +\t\t--to=nobody@example.com \\\n> +\t\t--sendmail-cmd=\"f() { \\\"$(pwd)/fake.sendmail\\\" \\\"\\$@\\\"; };f\" \\\n> +\t\tHEAD^ &&\n> +\ttest_path_is_file commandline1\n> +'\n\nNice demonstration of how a bit of scripting can be used.\n\n>  test_expect_success $PREREQ 'invoke hook' '\n>  \tmkdir -p .git/hooks &&\n\nThanks.\n"},{"id":"424541","messageId":"xmqq1ra999o5.fsf@gitster.g","threadId":"55668","inReplyTo":"xmqq7dk27xi2.fsf@gitster.g","subject":"Re: [PATCH v3] git-send-email: add option to specify sendmail command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-05-14T05:16:58Z","receivedAt":"2021-05-14T05:17:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> We want the shell that eats the command line of 'git send-email' to see\n>\n> \t--sendmail-cmd='$(pwd)/fake.sendmail'\\\" -f nobody@example.com\"\n\nEh, sorry, but this is wrong.  It would have to be something like\n\n\t--sendmail-cmd='\"$(pwd)/fake.sendmail\" -f nobody@example.com'\n\nThe point is that the outer shell (i.e. the one that is eval'ing the\nbody of the test_expect_success) should just see and treat the path\nto the sendmail-like program as \"$(pwd)/fake.sendmail\" as a literal\nstring including the surrounding double quotes and pass it down to\n\"git send-email\", and the shell started by our \"exec('sh','-c',...)\"\nthing will see what $(pwd) expands to, appends /fake.sendmail to it,\nand treat the whole thing as a single \"path to the program\", that is\nfollowed by two args, i.e. '-f' and 'nobody@example.com'.\n\nAnd inside test_expect_success whose body is surrounded by a pair of\nsq, we'd express a sq as '\\'', so it becomes\n\n\t--sendmail-cmd='\\''\"$(pwd)/fake.sendmail\" -f nobody@example.com'\\''\n\nin the test script, I would think.\n"},{"id":"424584","messageId":"YJ6FYDBdRsl3PCcc@gpanders.com","threadId":"55668","inReplyTo":"xmqq7dk27xi2.fsf@gitster.g","subject":"Re: [PATCH v3] git-send-email: add option to specify sendmail command","fromName":"Gregory Anders","fromEmail":"greg@gpanders.com","sentAt":"2021-05-14T14:12:48Z","receivedAt":"2021-05-14T14:12:54Z","isPatch":true,"sender":{"key":"greg@gpanders.com","avatar":"https://avatars.githubusercontent.com/u/8965202?v=4"},"body":"On Fri, 14 May 2021 13:25 +0900, Junio C Hamano wrote:\n>Are you talking about the use of $sm that is local to the debug\n>output?  I think leaving $sendmail_cmd intact by using a separate\n>variable is the right choice.  Isn't the problem you observed a\n>consequence of send_message() getting called once for each message,\n>so assigning to $sendmail_cmd in the function for the first\n>invocation of the function would change its value for the second\n>invocation?\n\nYes that is right. That makes sense. I didn't realize the subprocess was \ncalled twice, though that is such an obvious explanation I don't know \nwhy I didn't think of it.\n\n>Also, if we have been using\n>\n>\t--smtp-server=$(pwd)/fake.sendmail\n>\n>we cannot expect to use the same value like this:\n>\n>\t--sendmail-cmd=$(pwd)/fake.sendmail\n>\n>because we deliberately add a space in the $(pwd) by choosing the\n>name of the test directory to be \"trash directory.something\".  We'd\n>need to do something like\n>\n>\t--sendmail-cmd='$(pwd)/fake.sendmail'\n>\n>so that the shell sees '$(pwd)/fake.sendmail' literally and runs pwd\n>to find out what the path to the program is, I would think.\n\nIndeed, in prior versions of this patch I had replaced the uses of \n`--smtp-server` in the test suite with `--sendmail-cmd` which included \nthose extra quotes (I reverted back to using --smtp-server after \nfeedback from other reviewers in lieu of simply adding new test cases \nfor --sendmail-cmd).\n\n>> +test_expect_success $PREREQ 'test using arguments with \n>> --sendmail-cmd' '\n>> +\tclean_fake_sendmail &&\n>> +\tgit send-email \\\n>> +\t\t--from=\"Example <nobody@example.com>\" \\\n>> +\t\t--to=nobody@example.com \\\n>> +\t\t--sendmail-cmd=\"\\\"$(pwd)/fake.sendmail\\\" -f nobody@example.com\" \\\n>> +\t\tHEAD^ &&\n>> +\ttest_path_is_file commandline1\n>> +'\n>\n>Hmph, if $(pwd) has a double quote character in it, this may not\n>work as expected, as the shell that is expanding the command line\n>arguments for \"git send-email\" would see $(pwd), expand it and our\n>program will see\n>\n>    \"/path/with/d\"quote/git/t/trash directory.9001/fake.sendmail\" -f nobody@e.c\n>\n>as the value of --sendmail-cmd, which would not interpolate well,\n>no?\n>\n>We want the shell that eats the command line of 'git send-email' to see\n>\n>\t--sendmail-cmd='$(pwd)/fake.sendmail'\\\" -f nobody@example.com\"\n>\n>and because this is inside a sq pair, it would become\n>\n>\t--sendmail-cmd='\\''$(pwd)/fake.sendmail'\\''\\\" -f nobody@example.com\"\n>\n>after we replace each sq with '\\'', or something like that, perhaps?\n\nI'll take a look at this (as well as your followup email) and send a new \nversion.\n\nThanks,\n\nGreg\n"},{"id":"424586","messageId":"20210514151553.42938-1-greg@gpanders.com","threadId":"55668","inReplyTo":"20210513152329.22578-1-greg@gpanders.com","subject":"[PATCH v4] git-send-email: add option to specify sendmail command","fromName":"Gregory Anders","fromEmail":"greg@gpanders.com","sentAt":"2021-05-14T15:15:53Z","receivedAt":"2021-05-14T15:16:19Z","isPatch":true,"sender":{"key":"greg@gpanders.com","avatar":"https://avatars.githubusercontent.com/u/8965202?v=4"},"body":"The sendemail.smtpServer configuration option and --smtp-server command\nline option both support using a sendmail-like program to send emails by\nspecifying an absolute file path. However, this is not ideal for the\nfollowing reasons:\n\n1. It overloads the meaning of smtpServer (now a program is being used\n   for the server?)\n2. It doesn't allow for non-absolute paths, arguments, or arbitrary\n   scripting\n\nRequiring an absolute path is bad for portability, as the same program\nmay be in different locations on different systems. If a user wishes to\npass arguments to their program, they have to use the smtpServerOption\noption, which is cumbersome (as it must be repeated for each option) and\ndoesn't adhere to normal git conventions.\n\nIntroduce a new configuration option sendemail.sendmailCmd as well as a\ncommand line option --sendmail-cmd that can be used to specify a command\n(with or without arguments) or shell expression to run to send email.\nThe name of this option is consistent with --to-cmd and --cc-cmd. This\ninvocation honors the user's $PATH so that absolute paths are not\nnecessary. Arbitrary shell expressions are also supported, allowing\nusers to do basic scripting.\n\nGive this option a higher precedence over --smtp-server and\nsendemail.smtpServer, as the new interface is more flexible. For\nbackward compatibility, continue to support absolute paths in\n--smtp-server and sendemail.smtpServer.\n\nSigned-off-by: Gregory Anders <greg@gpanders.com>\n---\n Documentation/git-send-email.txt | 25 ++++++++++++++++-------\n git-send-email.perl              | 34 +++++++++++++++++++++++++-------\n t/t9001-send-email.sh            | 31 +++++++++++++++++++++++++++++\n 3 files changed, 76 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\nindex 93708aefea..3db4eab4ba 100644\n--- a/Documentation/git-send-email.txt\n+++ b/Documentation/git-send-email.txt\n@@ -167,6 +167,14 @@ Sending\n \t`sendemail.envelopeSender` configuration variable; if that is\n \tunspecified, choosing the envelope sender is left to your MTA.\n \n+--sendmail-cmd=<command>::\n+\tSpecify a command to run to send the email. The command should\n+\tbe sendmail-like; specifically, it must support the `-i` option.\n+\tThe command will be executed in the shell if necessary.  Default\n+\tis the value of `sendemail.sendmailcmd`.  If unspecified, and if\n+\t--smtp-server is also unspecified, git-send-email will search\n+\tfor `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH.\n+\n --smtp-encryption=<encryption>::\n \tSpecify the encryption to use, either 'ssl' or 'tls'.  Any other\n \tvalue reverts to plain SMTP.  Default is the value of\n@@ -211,13 +219,16 @@ a password is obtained using 'git-credential'.\n \n --smtp-server=<host>::\n \tIf set, specifies the outgoing SMTP server to use (e.g.\n-\t`smtp.example.com` or a raw IP address).  Alternatively it can\n-\tspecify a full pathname of a sendmail-like program instead;\n-\tthe program must support the `-i` option.  Default value can\n-\tbe specified by the `sendemail.smtpServer` configuration\n-\toption; the built-in default is to search for `sendmail` in\n-\t`/usr/sbin`, `/usr/lib` and $PATH if such program is\n-\tavailable, falling back to `localhost` otherwise.\n+\t`smtp.example.com` or a raw IP address).  If unspecified, and if\n+\t`--sendmail-cmd` is also unspecified, the default is to search\n+\tfor `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH if such a\n+\tprogram is available, falling back to `localhost` otherwise.\n++\n+For backward compatibility, this option can also specify a full pathname\n+of a sendmail-like program instead; the program must support the `-i`\n+option.  This method does not support passing arguments or using plain\n+command names.  For those use cases, consider using `--sendmail-cmd`\n+instead.\n \n --smtp-server-port=<port>::\n \tSpecifies a port different from the default port (SMTP\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 175da07d94..dbb144aa11 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -70,6 +70,7 @@ sub usage {\n \n   Sending:\n     --envelope-sender       <str>  * Email envelope sender.\n+    --sendmail-cmd          <str>  * Command to run to send email.\n     --smtp-server       <str:int>  * Outgoing SMTP server to use. The port\n                                      is optional. Default 'localhost'.\n     --smtp-server-option    <str>  * Outgoing SMTP server option to use.\n@@ -252,6 +253,7 @@ sub do_edit {\n my (@suppress_cc);\n my ($auto_8bit_encoding);\n my ($compose_encoding);\n+my ($sendmail_cmd);\n # Variables with corresponding config settings & hardcoded defaults\n my ($debug_net_smtp) = 0;\t\t# Net::SMTP, see send_message()\n my $thread = 1;\n@@ -299,6 +301,7 @@ sub do_edit {\n     \"assume8bitencoding\" => \\$auto_8bit_encoding,\n     \"composeencoding\" => \\$compose_encoding,\n     \"transferencoding\" => \\$target_xfer_encoding,\n+    \"sendmailcmd\" => \\$sendmail_cmd,\n );\n \n my %config_path_settings = (\n@@ -432,6 +435,7 @@ sub read_config {\n \t\t    \"no-bcc\" => \\$no_bcc,\n \t\t    \"chain-reply-to!\" => \\$chain_reply_to,\n \t\t    \"no-chain-reply-to\" => sub {$chain_reply_to = 0},\n+\t\t    \"sendmail-cmd=s\" => \\$sendmail_cmd,\n \t\t    \"smtp-server=s\" => \\$smtp_server,\n \t\t    \"smtp-server-option=s\" => \\@smtp_server_options,\n \t\t    \"smtp-server-port=s\" => \\$smtp_server_port,\n@@ -1003,16 +1007,19 @@ sub expand_one_alias {\n \t$reply_to = sanitize_address($reply_to);\n }\n \n-if (!defined $smtp_server) {\n+if (!defined $sendmail_cmd && !defined $smtp_server) {\n \tmy @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );\n \tpush @sendmail_paths, map {\"$_/sendmail\"} split /:/, $ENV{PATH};\n \tforeach (@sendmail_paths) {\n \t\tif (-x $_) {\n-\t\t\t$smtp_server = $_;\n+\t\t\t$sendmail_cmd = $_;\n \t\t\tlast;\n \t\t}\n \t}\n-\t$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*\n+\n+\tif (!defined $sendmail_cmd) {\n+\t\t$smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*\n+\t}\n }\n \n if ($compose && $compose > 0) {\n@@ -1492,11 +1499,17 @@ sub send_message {\n \n \tif ($dry_run) {\n \t\t# We don't want to send the email.\n-\t} elsif (file_name_is_absolute($smtp_server)) {\n+\t} elsif (defined $sendmail_cmd || file_name_is_absolute($smtp_server)) {\n \t\tmy $pid = open my $sm, '|-';\n \t\tdefined $pid or die $!;\n \t\tif (!$pid) {\n-\t\t\texec($smtp_server, @sendmail_parameters) or die $!;\n+\t\t\tif (defined $sendmail_cmd) {\n+\t\t\t\texec (\"sh\", \"-c\", \"$sendmail_cmd \\\"\\$@\\\"\", \"-\", @sendmail_parameters)\n+\t\t\t\t\tor die $!;\n+\t\t\t} else {\n+\t\t\t\texec ($smtp_server, @sendmail_parameters)\n+\t\t\t\t\tor die $!;\n+\t\t\t}\n \t\t}\n \t\tprint $sm \"$header\\n$message\";\n \t\tclose $sm or die $!;\n@@ -1592,14 +1605,21 @@ sub send_message {\n \t\tprintf($dry_run ? __(\"Dry-Sent %s\\n\") : __(\"Sent %s\\n\"), $subject);\n \t} else {\n \t\tprint($dry_run ? __(\"Dry-OK. Log says:\\n\") : __(\"OK. Log says:\\n\"));\n-\t\tif (!file_name_is_absolute($smtp_server)) {\n+\t\tif (!defined $sendmail_cmd && !file_name_is_absolute($smtp_server)) {\n \t\t\tprint \"Server: $smtp_server\\n\";\n \t\t\tprint \"MAIL FROM:<$raw_from>\\n\";\n \t\t\tforeach my $entry (@recipients) {\n \t\t\t    print \"RCPT TO:<$entry>\\n\";\n \t\t\t}\n \t\t} else {\n-\t\t\tprint \"Sendmail: $smtp_server \".join(' ',@sendmail_parameters).\"\\n\";\n+\t\t\tmy $sm;\n+\t\t\tif (defined $sendmail_cmd) {\n+\t\t\t\t$sm = $sendmail_cmd;\n+\t\t\t} else {\n+\t\t\t\t$sm = $smtp_server;\n+\t\t\t}\n+\n+\t\t\tprint \"Sendmail: $sm \".join(' ',@sendmail_parameters).\"\\n\";\n \t\t}\n \t\tprint $header, \"\\n\";\n \t\tif ($smtp) {\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 65b3035371..d771eb9297 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -2148,6 +2148,37 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '\n \ttest_cmp expected-list actual-list\n '\n \n+test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tPATH=\"$(pwd):$PATH\" \\\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd=\"fake.sendmail\" \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n+test_expect_success $PREREQ 'test using arguments with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd='\\''\"$(pwd)/fake.sendmail\" -f nobody@example.com'\\'' \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n+test_expect_success $PREREQ 'test shell expression with --sendmail-cmd' '\n+\tclean_fake_sendmail &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--sendmail-cmd='\\''f() { \"$(pwd)/fake.sendmail\" \"$@\"; };f'\\'' \\\n+\t\tHEAD^ &&\n+\ttest_path_is_file commandline1\n+'\n+\n test_expect_success $PREREQ 'invoke hook' '\n \tmkdir -p .git/hooks &&\n \n-- \n2.31.1.576.g1878d50f81\n\n"}]}