Skip to content

Commit ba92106

Browse files
apteryksgitster
authored andcommitted
send-email: add --header-cmd, --no-header-cmd options
Sometimes, adding a header different than CC or TO is desirable; for example, when using Debbugs, it is best to use 'X-Debbugs-Cc' headers to keep people in CC; this is an example use case enabled by the new '--header-cmd' option. The header unfolding logic is extracted to a subroutine so that it can be reused; a test is added for coverage. Signed-off-by: Maxim Cournoyer <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 03056ce commit ba92106

File tree

4 files changed

+107
-14
lines changed

4 files changed

+107
-14
lines changed

Documentation/config/sendemail.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ sendemail.ccCmd::
6161
sendemail.chainReplyTo::
6262
sendemail.envelopeSender::
6363
sendemail.from::
64+
sendemail.headerCmd::
6465
sendemail.signedoffbycc::
6566
sendemail.smtpPass::
6667
sendemail.suppresscc::

Documentation/git-send-email.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,17 @@ Automating
320320
Output of this command must be single email address per line.
321321
Default is the value of `sendemail.ccCmd` configuration value.
322322

323+
--header-cmd=<command>::
324+
Specify a command that is executed once per outgoing message
325+
and output RFC 2822 style header lines to be inserted into
326+
them. When the `sendemail.headerCmd` configuration variable is
327+
set, its value is always used. When --header-cmd is provided
328+
at the command line, its value takes precedence over the
329+
`sendemail.headerCmd` configuration variable.
330+
331+
--no-header-cmd::
332+
Disable any header command in use.
333+
323334
--[no-]chain-reply-to::
324335
If this is set, each email will be sent as a reply to the previous
325336
email sent. If disabled with "--no-chain-reply-to", all emails after

git-send-email.perl

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@ sub usage {
8787
8888
Automating:
8989
--identity <str> * Use the sendemail.<id> options.
90-
--to-cmd <str> * Email To: via `<str> \$patch_path`
91-
--cc-cmd <str> * Email Cc: via `<str> \$patch_path`
90+
--to-cmd <str> * Email To: via `<str> \$patch_path`.
91+
--cc-cmd <str> * Email Cc: via `<str> \$patch_path`.
92+
--header-cmd <str> * Add headers via `<str> \$patch_path`.
93+
--no-header-cmd * Disable any header command in use.
9294
--suppress-cc <str> * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.
9395
--[no-]cc-cover * Email Cc: addresses in the cover letter.
9496
--[no-]to-cover * Email To: addresses in the cover letter.
@@ -202,7 +204,7 @@ sub format_2822_time {
202204
$author,$sender,$smtp_authpass,$annotate,$compose,$time);
203205
# Things we either get from config, *or* are overridden on the
204206
# command-line.
205-
my ($no_cc, $no_to, $no_bcc, $no_identity);
207+
my ($no_cc, $no_to, $no_bcc, $no_identity, $no_header_cmd);
206208
my (@config_to, @getopt_to);
207209
my (@config_cc, @getopt_cc);
208210
my (@config_bcc, @getopt_bcc);
@@ -269,7 +271,7 @@ sub do_edit {
269271
# Variables with corresponding config settings
270272
my ($suppress_from, $signed_off_by_cc);
271273
my ($cover_cc, $cover_to);
272-
my ($to_cmd, $cc_cmd);
274+
my ($to_cmd, $cc_cmd, $header_cmd);
273275
my ($smtp_server, $smtp_server_port, @smtp_server_options);
274276
my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
275277
my ($batch_size, $relogin_delay);
@@ -318,6 +320,7 @@ sub do_edit {
318320
"tocmd" => \$to_cmd,
319321
"cc" => \@config_cc,
320322
"cccmd" => \$cc_cmd,
323+
"headercmd" => \$header_cmd,
321324
"aliasfiletype" => \$aliasfiletype,
322325
"bcc" => \@config_bcc,
323326
"suppresscc" => \@suppress_cc,
@@ -519,6 +522,8 @@ sub config_regexp {
519522
"compose" => \$compose,
520523
"quiet" => \$quiet,
521524
"cc-cmd=s" => \$cc_cmd,
525+
"header-cmd=s" => \$header_cmd,
526+
"no-header-cmd" => \$no_header_cmd,
522527
"suppress-from!" => \$suppress_from,
523528
"no-suppress-from" => sub {$suppress_from = 0},
524529
"suppress-cc=s" => \@suppress_cc,
@@ -1780,16 +1785,16 @@ sub process_file {
17801785
$subject = $initial_subject;
17811786
$message = "";
17821787
$message_num++;
1783-
# First unfold multiline header fields
1788+
# Retrieve and unfold header fields.
1789+
my @header_lines = ();
17841790
while(<$fh>) {
17851791
last if /^\s*$/;
1786-
if (/^\s+\S/ and @header) {
1787-
chomp($header[$#header]);
1788-
s/^\s+/ /;
1789-
$header[$#header] .= $_;
1790-
} else {
1791-
push(@header, $_);
1792-
}
1792+
push(@header_lines, $_);
1793+
}
1794+
@header = unfold_headers(@header_lines);
1795+
# Add computed headers, if applicable.
1796+
unless ($no_header_cmd || ! $header_cmd) {
1797+
push @header, invoke_header_cmd($header_cmd, $t);
17931798
}
17941799
# Now parse the header
17951800
foreach(@header) {
@@ -2036,6 +2041,32 @@ sub execute_cmd {
20362041
return @lines;
20372042
}
20382043

2044+
# Process headers lines, unfolding multiline headers as defined by RFC
2045+
# 2822.
2046+
sub unfold_headers {
2047+
my @headers;
2048+
foreach(@_) {
2049+
last if /^\s*$/;
2050+
if (/^\s+\S/ and @headers) {
2051+
chomp($headers[$#headers]);
2052+
s/^\s+/ /;
2053+
$headers[$#headers] .= $_;
2054+
} else {
2055+
push(@headers, $_);
2056+
}
2057+
}
2058+
return @headers;
2059+
}
2060+
2061+
# Invoke the provided CMD with FILE as an argument, which should
2062+
# output RFC 2822 email headers. Fold multiline headers and return the
2063+
# headers as an array.
2064+
sub invoke_header_cmd {
2065+
my ($cmd, $file) = @_;
2066+
my @lines = execute_cmd("header-cmd", $header_cmd, $file);
2067+
return unfold_headers(@lines);
2068+
}
2069+
20392070
# Execute a command (e.g. $to_cmd) to get a list of email addresses
20402071
# and return a results array
20412072
sub recipients_cmd {

t/t9001-send-email.sh

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,13 +374,16 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email'
374374
)
375375
'
376376

377-
test_expect_success $PREREQ 'setup tocmd and cccmd scripts' '
377+
test_expect_success $PREREQ 'setup cmd scripts' '
378378
write_script tocmd-sed <<-\EOF &&
379379
sed -n -e "s/^tocmd--//p" "$1"
380380
EOF
381-
write_script cccmd-sed <<-\EOF
381+
write_script cccmd-sed <<-\EOF &&
382382
sed -n -e "s/^cccmd--//p" "$1"
383383
EOF
384+
write_script headercmd-sed <<-\EOF
385+
sed -n -e "s/^headercmd--//p" "$1"
386+
EOF
384387
'
385388

386389
test_expect_success $PREREQ 'tocmd works' '
@@ -410,6 +413,53 @@ test_expect_success $PREREQ 'cccmd works' '
410413
grep "^ [email protected]" msgtxt1
411414
'
412415

416+
test_expect_success $PREREQ 'headercmd works' '
417+
clean_fake_sendmail &&
418+
cp $patches headercmd.patch &&
419+
echo "headercmd--X-Debbugs-CC: [email protected]" >>headercmd.patch &&
420+
git send-email \
421+
--from="Example <[email protected]>" \
422+
423+
--header-cmd=./headercmd-sed \
424+
--smtp-server="$(pwd)/fake.sendmail" \
425+
headercmd.patch \
426+
&&
427+
grep "^X-Debbugs-CC: [email protected]" msgtxt1
428+
'
429+
430+
test_expect_success $PREREQ '--no-header-cmd works' '
431+
clean_fake_sendmail &&
432+
cp $patches headercmd.patch &&
433+
echo "headercmd--X-Debbugs-CC: [email protected]" >>headercmd.patch &&
434+
git send-email \
435+
--from="Example <[email protected]>" \
436+
437+
--header-cmd=./headercmd-sed \
438+
--no-header-cmd \
439+
--smtp-server="$(pwd)/fake.sendmail" \
440+
headercmd.patch \
441+
&&
442+
! grep "^X-Debbugs-CC: [email protected]" msgtxt1
443+
'
444+
445+
test_expect_success $PREREQ 'multiline fields are correctly unfolded' '
446+
clean_fake_sendmail &&
447+
cp $patches headercmd.patch &&
448+
write_script headercmd-multiline <<-\EOF &&
449+
echo "X-Debbugs-CC: [email protected]
450+
FoldedField: This is a tale
451+
best told using
452+
multiple lines."
453+
EOF
454+
git send-email \
455+
--from="Example <[email protected]>" \
456+
457+
--header-cmd=./headercmd-multiline \
458+
--smtp-server="$(pwd)/fake.sendmail" \
459+
headercmd.patch &&
460+
grep "^FoldedField: This is a tale best told using multiple lines.$" msgtxt1
461+
'
462+
413463
test_expect_success $PREREQ 'reject long lines' '
414464
z8=zzzzzzzz &&
415465
z64=$z8$z8$z8$z8$z8$z8$z8$z8 &&

0 commit comments

Comments
 (0)