Merge branch 'js/maint-send-email' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 11 Mar 2009 21:01:24 +0000 (14:01 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 11 Mar 2009 21:01:24 +0000 (14:01 -0700)
* js/maint-send-email:
send-email: don't create temporary compose file until it is needed
send-email: --suppress-cc improvements
send-email: handle multiple Cc addresses when reading mbox message
send-email: allow send-email to run outside a repo

Documentation/git-send-email.txt
git-send-email.perl
t/t9001-send-email.sh
index 66bf3b2fcdccda9cb29d66756b3c20e5a1545d46..fc0a4ab441d0ee55f44450d2722187e975f84f44 100644 (file)
@@ -177,14 +177,25 @@ Automating
 
 --suppress-cc::
        Specify an additional category of recipients to suppress the
-       auto-cc of.  'self' will avoid including the sender, 'author' will
-       avoid including the patch author, 'cc' will avoid including anyone
-       mentioned in Cc lines in the patch, 'sob' will avoid including
-       anyone mentioned in Signed-off-by lines, and 'cccmd' will avoid
-       running the --cc-cmd.  'all' will suppress all auto cc values.
-       Default is the value of 'sendemail.suppresscc' configuration value;
-       if that is unspecified, default to 'self' if --suppress-from is
-       specified, as well as 'sob' if --no-signed-off-cc is specified.
+       auto-cc of:
++
+--
+- 'author' will avoid including the patch author
+- 'self' will avoid including the sender
+- 'cc' will avoid including anyone mentioned in Cc lines in the patch header
+  except for self (use 'self' for that).
+- 'ccbody' will avoid including anyone mentioned in Cc lines in the
+  patch body (commit message) except for self (use 'self' for that).
+- 'sob' will avoid including anyone mentioned in Signed-off-by lines except
+   for self (use 'self' for that).
+- 'cccmd' will avoid running the --cc-cmd.
+- 'body' is equivalent to 'sob' + 'ccbody'
+- 'all' will suppress all auto cc values.
+--
++
+Default is the value of 'sendemail.suppresscc' configuration value; if
+that is unspecified, default to 'self' if --suppress-from is
+specified, as well as 'body' if --no-signed-off-cc is specified.
 
 --[no-]suppress-from::
        If this is set, do not add the From: address to the cc: list.
index 77ca8fe8803f102b877c4d63ed1ffa41920cbd54..adf7ecb5c35a978bad5a15463cb9cf54665b9860 100755 (executable)
@@ -23,7 +23,7 @@
 use Text::ParseWords;
 use Data::Dumper;
 use Term::ANSIColor;
-use File::Temp qw/ tempdir /;
+use File::Temp qw/ tempdir tempfile /;
 use Error qw(:try);
 use Git;
 
@@ -68,9 +68,8 @@ sub usage {
   Automating:
     --identity              <str>  * Use the sendemail.<id> options.
     --cc-cmd                <str>  * Email Cc: via `<str> \$patch_path`
-    --suppress-cc           <str>  * author, self, sob, cccmd, all.
-    --[no-]signed-off-by-cc        * Send to Cc: and Signed-off-by:
-                                     addresses. Default on.
+    --suppress-cc           <str>  * author, self, sob, cc, cccmd, body, bodycc, all.
+    --[no-]signed-off-by-cc        * Send to Signed-off-by: addresses. Default on.
     --[no-]suppress-from           * Send to self. Default off.
     --[no-]chain-reply-to          * Chain In-Reply-To: fields. Default on.
     --[no-]thread                  * Use In-Reply-To: field. Default on.
@@ -126,6 +125,7 @@ sub format_2822_time {
 }
 
 my $have_email_valid = eval { require Email::Valid; 1 };
+my $have_mail_address = eval { require Mail::Address; 1 };
 my $smtp;
 my $auth;
 
@@ -156,7 +156,7 @@ sub format_2822_time {
 # Behavior modification variables
 my ($quiet, $dry_run) = (0, 0);
 my $format_patch;
-my $compose_filename = $repo->repo_path() . "/.gitsendemail.msg.$$";
+my $compose_filename;
 
 # Handle interactive edition of files.
 my $multiedit;
@@ -219,11 +219,13 @@ sub signal_handler {
        system "stty echo";
 
        # tmp files from --compose
-       if (-e $compose_filename) {
-               print "'$compose_filename' contains an intermediate version of the email you were composing.\n";
-       }
-       if (-e ($compose_filename . ".final")) {
-               print "'$compose_filename.final' contains the composed email.\n"
+       if (defined $compose_filename) {
+               if (-e $compose_filename) {
+                       print "'$compose_filename' contains an intermediate version of the email you were composing.\n";
+               }
+               if (-e ($compose_filename . ".final")) {
+                       print "'$compose_filename.final' contains the composed email.\n"
+               }
        }
 
        exit;
@@ -267,6 +269,9 @@ sub signal_handler {
     usage();
 }
 
+die "Cannot run git format-patch from outside a repository\n"
+       if $format_patch and not $repo;
+
 # Now, let's fill any that aren't set in with defaults:
 
 sub read_config {
@@ -318,13 +323,13 @@ sub read_config {
 if (@suppress_cc) {
        foreach my $entry (@suppress_cc) {
                die "Unknown --suppress-cc field: '$entry'\n"
-                       unless $entry =~ /^(all|cccmd|cc|author|self|sob)$/;
+                       unless $entry =~ /^(all|cccmd|cc|author|self|sob|body|bodycc)$/;
                $suppress_cc{$entry} = 1;
        }
 }
 
 if ($suppress_cc{'all'}) {
-       foreach my $entry (qw (ccmd cc author self sob)) {
+       foreach my $entry (qw (ccmd cc author self sob body bodycc)) {
                $suppress_cc{$entry} = 1;
        }
        delete $suppress_cc{'all'};
@@ -334,6 +339,13 @@ sub read_config {
 $suppress_cc{'self'} = $suppress_from if defined $suppress_from;
 $suppress_cc{'sob'} = !$signed_off_by_cc if defined $signed_off_by_cc;
 
+if ($suppress_cc{'body'}) {
+       foreach my $entry (qw (sob bodycc)) {
+               $suppress_cc{$entry} = 1;
+       }
+       delete $suppress_cc{'body'};
+}
+
 # Debugging, print out the suppressions.
 if (0) {
        print "suppressions:\n";
@@ -360,6 +372,14 @@ sub read_config {
        die "Comma in --bcclist entry: $entry'\n" unless $entry !~ m/,/;
 }
 
+sub parse_address_line {
+       if ($have_mail_address) {
+               return map { $_->format } Mail::Address->parse($_[0]);
+       } else {
+               return split_addrs($_[0]);
+       }
+}
+
 sub split_addrs {
        return quotewords('\s*,\s*', 1, @_);
 }
@@ -404,6 +424,7 @@ sub split_addrs {
 
 # returns 1 if the conflict must be solved using it as a format-patch argument
 sub check_file_rev_conflict($) {
+       return unless $repo;
        my $f = shift;
        try {
                $repo->command('rev-parse', '--verify', '--quiet', $f);
@@ -445,6 +466,8 @@ ($)
 }
 
 if (@rev_list_opts) {
+       die "Cannot run git format-patch from outside a repository\n"
+               unless $repo;
        push @files, $repo->command('format-patch', '-o', tempdir(CLEANUP => 1), @rev_list_opts);
 }
 
@@ -481,6 +504,9 @@ ($)
 if ($compose) {
        # Note that this does not need to be secure, but we will make a small
        # effort to have it be unique
+       $compose_filename = ($repo ?
+               tempfile(".gitsendemail.msg.XXXXXX", DIR => $repo->repo_path()) :
+               tempfile(".gitsendemail.msg.XXXXXX", DIR => "."))[1];
        open(C,">",$compose_filename)
                or die "Failed to open for writing $compose_filename: $!";
 
@@ -593,7 +619,7 @@ ($)
        }
 
        my $to = $_;
-       push @to, split_addrs($to);
+       push @to, parse_address_line($to);
        $prompting++;
 }
 
@@ -920,88 +946,102 @@ sub send_message
        @cc = @initial_cc;
        @xh = ();
        my $input_format = undef;
-       my $header_done = 0;
+       my @header = ();
        $message = "";
+       # First unfold multiline header fields
        while(<F>) {
-               if (!$header_done) {
-                       if (/^From /) {
-                               $input_format = 'mbox';
-                               next;
+               last if /^\s*$/;
+               if (/^\s+\S/ and @header) {
+                       chomp($header[$#header]);
+                       s/^\s+/ /;
+                       $header[$#header] .= $_;
+           } else {
+                       push(@header, $_);
+               }
+       }
+       # Now parse the header
+       foreach(@header) {
+               if (/^From /) {
+                       $input_format = 'mbox';
+                       next;
+               }
+               chomp;
+               if (!defined $input_format && /^[-A-Za-z]+:\s/) {
+                       $input_format = 'mbox';
+               }
+
+               if (defined $input_format && $input_format eq 'mbox') {
+                       if (/^Subject:\s+(.*)$/) {
+                               $subject = $1;
                        }
-                       chomp;
-                       if (!defined $input_format && /^[-A-Za-z]+:\s/) {
-                               $input_format = 'mbox';
+                       elsif (/^From:\s+(.*)$/) {
+                               ($author, $author_encoding) = unquote_rfc2047($1);
+                               next if $suppress_cc{'author'};
+                               next if $suppress_cc{'self'} and $author eq $sender;
+                               printf("(mbox) Adding cc: %s from line '%s'\n",
+                                       $1, $_) unless $quiet;
+                               push @cc, $1;
                        }
-
-                       if (defined $input_format && $input_format eq 'mbox') {
-                               if (/^Subject:\s+(.*)$/) {
-                                       $subject = $1;
-
-                               } elsif (/^(Cc|From):\s+(.*)$/) {
-                                       if (unquote_rfc2047($2) eq $sender) {
+                       elsif (/^Cc:\s+(.*)$/) {
+                               foreach my $addr (parse_address_line($1)) {
+                                       if (unquote_rfc2047($addr) eq $sender) {
                                                next if ($suppress_cc{'self'});
-                                       }
-                                       elsif ($1 eq 'From') {
-                                               ($author, $author_encoding)
-                                                 = unquote_rfc2047($2);
-                                               next if ($suppress_cc{'author'});
                                        } else {
                                                next if ($suppress_cc{'cc'});
                                        }
                                        printf("(mbox) Adding cc: %s from line '%s'\n",
-                                               $2, $_) unless $quiet;
-                                       push @cc, $2;
-                               }
-                               elsif (/^Content-type:/i) {
-                                       $has_content_type = 1;
-                                       if (/charset="?([^ "]+)/) {
-                                               $body_encoding = $1;
-                                       }
-                                       push @xh, $_;
-                               }
-                               elsif (/^Message-Id: (.*)/i) {
-                                       $message_id = $1;
+                                               $addr, $_) unless $quiet;
+                                       push @cc, $addr;
                                }
-                               elsif (!/^Date:\s/ && /^[-A-Za-z]+:\s+\S/) {
-                                       push @xh, $_;
-                               }
-
-                       } else {
-                               # In the traditional
-                               # "send lots of email" format,
-                               # line 1 = cc
-                               # line 2 = subject
-                               # So let's support that, too.
-                               $input_format = 'lots';
-                               if (@cc == 0 && !$suppress_cc{'cc'}) {
-                                       printf("(non-mbox) Adding cc: %s from line '%s'\n",
-                                               $_, $_) unless $quiet;
-
-                                       push @cc, $_;
-
-                               } elsif (!defined $subject) {
-                                       $subject = $_;
+                       }
+                       elsif (/^Content-type:/i) {
+                               $has_content_type = 1;
+                               if (/charset="?([^ "]+)/) {
+                                       $body_encoding = $1;
                                }
+                               push @xh, $_;
                        }
-
-                       # A whitespace line will terminate the headers
-                       if (m/^\s*$/) {
-                               $header_done = 1;
+                       elsif (/^Message-Id: (.*)/i) {
+                               $message_id = $1;
                        }
+                       elsif (!/^Date:\s/ && /^[-A-Za-z]+:\s+\S/) {
+                               push @xh, $_;
+                       }
+
                } else {
-                       $message .=  $_;
-                       if (/^(Signed-off-by|Cc): (.*)$/i) {
-                               next if ($suppress_cc{'sob'});
-                               chomp;
-                               my $c = $2;
-                               chomp $c;
-                               next if ($c eq $sender and $suppress_cc{'self'});
-                               push @cc, $c;
-                               printf("(sob) Adding cc: %s from line '%s'\n",
-                                       $c, $_) unless $quiet;
+                       # In the traditional
+                       # "send lots of email" format,
+                       # line 1 = cc
+                       # line 2 = subject
+                       # So let's support that, too.
+                       $input_format = 'lots';
+                       if (@cc == 0 && !$suppress_cc{'cc'}) {
+                               printf("(non-mbox) Adding cc: %s from line '%s'\n",
+                                       $_, $_) unless $quiet;
+                               push @cc, $_;
+                       } elsif (!defined $subject) {
+                               $subject = $_;
                        }
                }
        }
+       # Now parse the message body
+       while(<F>) {
+               $message .=  $_;
+               if (/^(Signed-off-by|Cc): (.*)$/i) {
+                       chomp;
+                       my ($what, $c) = ($1, $2);
+                       chomp $c;
+                       if ($c eq $sender) {
+                               next if ($suppress_cc{'self'});
+                       } else {
+                               next if $suppress_cc{'sob'} and $what =~ /Signed-off-by/i;
+                               next if $suppress_cc{'bodycc'} and $what =~ /Cc/i;
+                       }
+                       push @cc, $c;
+                       printf("(body) Adding cc: %s from line '%s'\n",
+                               $c, $_) unless $quiet;
+               }
+       }
        close F;
 
        if (defined $cc_cmd && !$suppress_cc{'cccmd'}) {
@@ -1020,7 +1060,7 @@ sub send_message
                        or die "(cc-cmd) failed to close pipe to '$cc_cmd'";
        }
 
-       if (defined $author) {
+       if (defined $author and $author ne $sender) {
                $message = "From: $author\n\n$message";
                if (defined $author_encoding) {
                        if ($has_content_type) {
index cb3d1837709fbce30fc508e339ce671c55eb9a1b..4df4f965cb0f2220ea9acf769c4fabf1248ab9a1 100755 (executable)
@@ -32,16 +32,18 @@ clean_fake_sendmail() {
 }
 
 test_expect_success 'Extract patches' '
-    patches=`git format-patch -n HEAD^1`
+    patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
 '
 
 test_expect_success 'Send patches' '
-     git send-email --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+     git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
 '
 
 cat >expected <<\EOF
 !nobody@example.com!
 !author@example.com!
+!one@example.com!
+!two@example.com!
 EOF
 test_expect_success \
     'Verify commandline' \
@@ -50,13 +52,15 @@ test_expect_success \
 cat >expected-show-all-headers <<\EOF
 0001-Second.patch
 (mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
+(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
+(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
 Dry-OK. Log says:
 Server: relay.example.com
 MAIL FROM:<from@example.com>
-RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<bcc@example.com>
+RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<bcc@example.com>
 From: Example <from@example.com>
 To: to@example.com
-Cc: cc@example.com, A <author@example.com>
+Cc: cc@example.com, A <author@example.com>, One <one@example.com>, two@example.com
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
 Message-Id: MESSAGE-ID-STRING
@@ -70,6 +74,7 @@ EOF
 test_expect_success 'Show all headers' '
        git send-email \
                --dry-run \
+               --suppress-cc=sob \
                --from="Example <from@example.com>" \
                --to=to@example.com \
                --cc=cc@example.com \
@@ -104,6 +109,28 @@ test_expect_success 'no patch was sent' '
        ! test -e commandline1
 '
 
+test_expect_success 'Author From: in message body' '
+       clean_fake_sendmail &&
+       git send-email \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               $patches &&
+       sed "1,/^$/d" < msgtxt1 > msgbody1
+       grep "From: A <author@example.com>" msgbody1
+'
+
+test_expect_success 'Author From: not in message body' '
+       clean_fake_sendmail &&
+       git send-email \
+               --from="A <author@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               $patches &&
+       sed "1,/^$/d" < msgtxt1 > msgbody1
+       ! grep "From: A <author@example.com>" msgbody1
+'
+
 test_expect_success 'allow long lines with --no-validate' '
        git send-email \
                --from="Example <nobody@example.com>" \
@@ -167,16 +194,18 @@ test_expect_success 'second message is patch' '
        grep "Subject:.*Second" msgtxt2
 '
 
-cat >expected-show-all-headers <<\EOF
+cat >expected-suppress-sob <<\EOF
 0001-Second.patch
 (mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
+(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
+(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
 Dry-OK. Log says:
 Server: relay.example.com
 MAIL FROM:<from@example.com>
-RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>
+RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
 From: Example <from@example.com>
 To: to@example.com
-Cc: cc@example.com, A <author@example.com>
+Cc: cc@example.com, A <author@example.com>, One <one@example.com>, two@example.com
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
 Message-Id: MESSAGE-ID-STRING
@@ -185,10 +214,10 @@ X-Mailer: X-MAILER-STRING
 Result: OK
 EOF
 
-test_expect_success 'sendemail.cc set' '
-       git config sendemail.cc cc@example.com &&
+test_suppression () {
        git send-email \
                --dry-run \
+               --suppress-cc=$1 \
                --from="Example <from@example.com>" \
                --to=to@example.com \
                --smtp-server relay.example.com \
@@ -196,20 +225,27 @@ test_expect_success 'sendemail.cc set' '
        sed     -e "s/^\(Date:\).*/\1 DATE-STRING/" \
                -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
                -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
-               >actual-show-all-headers &&
-       test_cmp expected-show-all-headers actual-show-all-headers
+               >actual-suppress-$1 &&
+       test_cmp expected-suppress-$1 actual-suppress-$1
+}
+
+test_expect_success 'sendemail.cc set' '
+       git config sendemail.cc cc@example.com &&
+       test_suppression sob
 '
 
-cat >expected-show-all-headers <<\EOF
+cat >expected-suppress-sob <<\EOF
 0001-Second.patch
 (mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
+(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
+(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
 Dry-OK. Log says:
 Server: relay.example.com
 MAIL FROM:<from@example.com>
-RCPT TO:<to@example.com>,<author@example.com>
+RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
 From: Example <from@example.com>
 To: to@example.com
-Cc: A <author@example.com>
+Cc: A <author@example.com>, One <one@example.com>, two@example.com
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
 Message-Id: MESSAGE-ID-STRING
@@ -220,17 +256,123 @@ EOF
 
 test_expect_success 'sendemail.cc unset' '
        git config --unset sendemail.cc &&
-       git send-email \
-               --dry-run \
-               --from="Example <from@example.com>" \
-               --to=to@example.com \
-               --smtp-server relay.example.com \
-               $patches |
-       sed     -e "s/^\(Date:\).*/\1 DATE-STRING/" \
-               -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
-               -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
-               >actual-show-all-headers &&
-       test_cmp expected-show-all-headers actual-show-all-headers
+       test_suppression sob
+'
+
+cat >expected-suppress-all <<\EOF
+0001-Second.patch
+Dry-OK. Log says:
+Server: relay.example.com
+MAIL FROM:<from@example.com>
+RCPT TO:<to@example.com>
+From: Example <from@example.com>
+To: to@example.com
+Subject: [PATCH 1/1] Second.
+Date: DATE-STRING
+Message-Id: MESSAGE-ID-STRING
+X-Mailer: X-MAILER-STRING
+
+Result: OK
+EOF
+
+test_expect_success '--suppress-cc=all' '
+       test_suppression all
+'
+
+cat >expected-suppress-body <<\EOF
+0001-Second.patch
+(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
+(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
+(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
+Dry-OK. Log says:
+Server: relay.example.com
+MAIL FROM:<from@example.com>
+RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
+From: Example <from@example.com>
+To: to@example.com
+Cc: A <author@example.com>, One <one@example.com>, two@example.com
+Subject: [PATCH 1/1] Second.
+Date: DATE-STRING
+Message-Id: MESSAGE-ID-STRING
+X-Mailer: X-MAILER-STRING
+
+Result: OK
+EOF
+
+test_expect_success '--suppress-cc=body' '
+       test_suppression body
+'
+
+cat >expected-suppress-sob <<\EOF
+0001-Second.patch
+(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
+(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
+(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
+Dry-OK. Log says:
+Server: relay.example.com
+MAIL FROM:<from@example.com>
+RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
+From: Example <from@example.com>
+To: to@example.com
+Cc: A <author@example.com>, One <one@example.com>, two@example.com
+Subject: [PATCH 1/1] Second.
+Date: DATE-STRING
+Message-Id: MESSAGE-ID-STRING
+X-Mailer: X-MAILER-STRING
+
+Result: OK
+EOF
+
+test_expect_success '--suppress-cc=sob' '
+       test_suppression sob
+'
+
+cat >expected-suppress-bodycc <<\EOF
+0001-Second.patch
+(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
+(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
+(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
+(body) Adding cc: C O Mitter <committer@example.com> from line 'Signed-off-by: C O Mitter <committer@example.com>'
+Dry-OK. Log says:
+Server: relay.example.com
+MAIL FROM:<from@example.com>
+RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<committer@example.com>
+From: Example <from@example.com>
+To: to@example.com
+Cc: A <author@example.com>, One <one@example.com>, two@example.com, C O Mitter <committer@example.com>
+Subject: [PATCH 1/1] Second.
+Date: DATE-STRING
+Message-Id: MESSAGE-ID-STRING
+X-Mailer: X-MAILER-STRING
+
+Result: OK
+EOF
+
+test_expect_success '--suppress-cc=bodycc' '
+       test_suppression bodycc
+'
+
+cat >expected-suppress-cc <<\EOF
+0001-Second.patch
+(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
+(body) Adding cc: C O Mitter <committer@example.com> from line 'Signed-off-by: C O Mitter <committer@example.com>'
+Dry-OK. Log says:
+Server: relay.example.com
+MAIL FROM:<from@example.com>
+RCPT TO:<to@example.com>,<author@example.com>,<committer@example.com>
+From: Example <from@example.com>
+To: to@example.com
+Cc: A <author@example.com>, C O Mitter <committer@example.com>
+Subject: [PATCH 1/1] Second.
+Date: DATE-STRING
+Message-Id: MESSAGE-ID-STRING
+X-Mailer: X-MAILER-STRING
+
+Result: OK
+EOF
+
+test_expect_success '--suppress-cc=cc' '
+       test_suppression cc
 '
 
 test_expect_success '--compose adds MIME for utf8 body' '