Skip to content

Commit 2374f1d

Browse files
committed
Merge branch 'pb/send-email-te'
"git send-email" learned "--transfer-encoding" option to force a non-fault Content-Transfer-Encoding header (e.g. base64). * pb/send-email-te: git-send-email: add --transfer-encoding option git-send-email: delay creation of MIME headers
2 parents fa7f51d + 8d81408 commit 2374f1d

5 files changed

Lines changed: 227 additions & 6 deletions

File tree

Documentation/config.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2318,6 +2318,7 @@ sendemail.smtpserverport::
23182318
sendemail.smtpserveroption::
23192319
sendemail.smtpuser::
23202320
sendemail.thread::
2321+
sendemail.transferencoding::
23212322
sendemail.validate::
23222323
See linkgit:git-send-email[1] for description.
23232324

Documentation/git-send-email.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,16 @@ Note that no attempts whatsoever are made to validate the encoding.
131131
Specify encoding of compose message. Default is the value of the
132132
'sendemail.composeencoding'; if that is unspecified, UTF-8 is assumed.
133133

134+
--transfer-encoding=(7bit|8bit|quoted-printable|base64)::
135+
Specify the transfer encoding to be used to send the message over SMTP.
136+
7bit will fail upon encountering a non-ASCII message. quoted-printable
137+
can be useful when the repository contains files that contain carriage
138+
returns, but makes the raw patch email file (as saved from a MUA) much
139+
harder to inspect manually. base64 is even more fool proof, but also
140+
even more opaque. Default is the value of the 'sendemail.transferEncoding'
141+
configuration value; if that is unspecified, git will use 8bit and not
142+
add a Content-Transfer-Encoding header.
143+
134144

135145
Sending
136146
~~~~~~~

contrib/completion/git-completion.bash

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,6 +1875,10 @@ _git_config ()
18751875
__gitcomp "$__git_send_email_suppresscc_options"
18761876
return
18771877
;;
1878+
sendemail.transferencoding)
1879+
__gitcomp "7bit 8bit quoted-printable base64"
1880+
return
1881+
;;
18781882
--get|--get-all|--unset|--unset-all)
18791883
__gitcomp_nl "$(__git_config_get_set_variables)"
18801884
return

git-send-email.perl

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ sub usage {
5858
--compose * Open an editor for introduction.
5959
--compose-encoding <str> * Encoding to assume for introduction.
6060
--8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
61+
--transfer-encoding <str> * Transfer encoding to use (quoted-printable, 8bit, base64)
6162
6263
Sending:
6364
--envelope-sender <str> * Email envelope sender.
@@ -206,6 +207,7 @@ sub do_edit {
206207
my (@suppress_cc);
207208
my ($auto_8bit_encoding);
208209
my ($compose_encoding);
210+
my ($target_xfer_encoding);
209211

210212
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
211213

@@ -242,6 +244,7 @@ sub do_edit {
242244
"from" => \$sender,
243245
"assume8bitencoding" => \$auto_8bit_encoding,
244246
"composeencoding" => \$compose_encoding,
247+
"transferencoding" => \$target_xfer_encoding,
245248
);
246249

247250
my %config_path_settings = (
@@ -314,6 +317,7 @@ sub signal_handler {
314317
"envelope-sender=s" => \$envelope_sender,
315318
"thread!" => \$thread,
316319
"validate!" => \$validate,
320+
"transfer-encoding=s" => \$target_xfer_encoding,
317321
"format-patch!" => \$format_patch,
318322
"8bit-encoding=s" => \$auto_8bit_encoding,
319323
"compose-encoding=s" => \$compose_encoding,
@@ -1324,6 +1328,8 @@ sub send_message {
13241328
my $author_encoding;
13251329
my $has_content_type;
13261330
my $body_encoding;
1331+
my $xfer_encoding;
1332+
my $has_mime_version;
13271333
@to = ();
13281334
@cc = ();
13291335
@xh = ();
@@ -1394,9 +1400,16 @@ sub send_message {
13941400
}
13951401
push @xh, $_;
13961402
}
1403+
elsif (/^MIME-Version/i) {
1404+
$has_mime_version = 1;
1405+
push @xh, $_;
1406+
}
13971407
elsif (/^Message-Id: (.*)/i) {
13981408
$message_id = $1;
13991409
}
1410+
elsif (/^Content-Transfer-Encoding: (.*)/i) {
1411+
$xfer_encoding = $1 if not defined $xfer_encoding;
1412+
}
14001413
elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
14011414
push @xh, $_;
14021415
}
@@ -1444,10 +1457,9 @@ sub send_message {
14441457
if defined $cc_cmd && !$suppress_cc{'cccmd'};
14451458

14461459
if ($broken_encoding{$t} && !$has_content_type) {
1460+
$xfer_encoding = '8bit' if not defined $xfer_encoding;
14471461
$has_content_type = 1;
1448-
push @xh, "MIME-Version: 1.0",
1449-
"Content-Type: text/plain; charset=$auto_8bit_encoding",
1450-
"Content-Transfer-Encoding: 8bit";
1462+
push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding";
14511463
$body_encoding = $auto_8bit_encoding;
14521464
}
14531465

@@ -1467,14 +1479,25 @@ sub send_message {
14671479
}
14681480
}
14691481
else {
1482+
$xfer_encoding = '8bit' if not defined $xfer_encoding;
14701483
$has_content_type = 1;
14711484
push @xh,
1472-
'MIME-Version: 1.0',
1473-
"Content-Type: text/plain; charset=$author_encoding",
1474-
'Content-Transfer-Encoding: 8bit';
1485+
"Content-Type: text/plain; charset=$author_encoding";
14751486
}
14761487
}
14771488
}
1489+
if (defined $target_xfer_encoding) {
1490+
$xfer_encoding = '8bit' if not defined $xfer_encoding;
1491+
$message = apply_transfer_encoding(
1492+
$message, $xfer_encoding, $target_xfer_encoding);
1493+
$xfer_encoding = $target_xfer_encoding;
1494+
}
1495+
if (defined $xfer_encoding) {
1496+
push @xh, "Content-Transfer-Encoding: $xfer_encoding";
1497+
}
1498+
if (defined $xfer_encoding or $has_content_type) {
1499+
unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
1500+
}
14781501

14791502
$needs_confirm = (
14801503
$confirm eq "always" or
@@ -1543,6 +1566,32 @@ sub cleanup_compose_files {
15431566

15441567
$smtp->quit if $smtp;
15451568

1569+
sub apply_transfer_encoding {
1570+
my $message = shift;
1571+
my $from = shift;
1572+
my $to = shift;
1573+
1574+
return $message if ($from eq $to and $from ne '7bit');
1575+
1576+
require MIME::QuotedPrint;
1577+
require MIME::Base64;
1578+
1579+
$message = MIME::QuotedPrint::decode($message)
1580+
if ($from eq 'quoted-printable');
1581+
$message = MIME::Base64::decode($message)
1582+
if ($from eq 'base64');
1583+
1584+
die "cannot send message as 7bit"
1585+
if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
1586+
return $message
1587+
if ($to eq '7bit' or $to eq '8bit');
1588+
return MIME::QuotedPrint::encode($message, "\n", 0)
1589+
if ($to eq 'quoted-printable');
1590+
return MIME::Base64::encode($message, "\n")
1591+
if ($to eq 'base64');
1592+
die "invalid transfer encoding";
1593+
}
1594+
15461595
sub unique_email_list {
15471596
my %seen;
15481597
my @emails;

t/t9001-send-email.sh

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,163 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
12981298
test_cmp expected actual
12991299
'
13001300

1301+
test_expect_success $PREREQ 'setup expect' '
1302+
cat >email-using-8bit <<EOF
1303+
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
1304+
Message-Id: <bogus-message-id@example.com>
1305+
From: A U Thor <author@example.com>
1306+
Date: Sat, 12 Jun 2010 15:53:58 +0200
1307+
Content-Type: text/plain; charset=UTF-8
1308+
Subject: Nothing to see here.
1309+
1310+
Dieser Betreff enthält auch einen Umlaut!
1311+
EOF
1312+
'
1313+
1314+
test_expect_success $PREREQ 'sendemail.transferencoding=7bit fails on 8bit data' '
1315+
clean_fake_sendmail &&
1316+
git config sendemail.transferEncoding 7bit &&
1317+
test_must_fail git send-email \
1318+
--transfer-encoding=7bit \
1319+
--smtp-server="$(pwd)/fake.sendmail" \
1320+
email-using-8bit \
1321+
2>errors >out &&
1322+
grep "cannot send message as 7bit" errors &&
1323+
test -z "$(ls msgtxt*)"
1324+
'
1325+
1326+
test_expect_success $PREREQ '--transfer-encoding overrides sendemail.transferEncoding' '
1327+
clean_fake_sendmail &&
1328+
git config sendemail.transferEncoding 8bit
1329+
test_must_fail git send-email \
1330+
--transfer-encoding=7bit \
1331+
--smtp-server="$(pwd)/fake.sendmail" \
1332+
email-using-8bit \
1333+
2>errors >out &&
1334+
grep "cannot send message as 7bit" errors &&
1335+
test -z "$(ls msgtxt*)"
1336+
'
1337+
1338+
test_expect_success $PREREQ 'sendemail.transferencoding=8bit' '
1339+
clean_fake_sendmail &&
1340+
git send-email \
1341+
--transfer-encoding=8bit \
1342+
--smtp-server="$(pwd)/fake.sendmail" \
1343+
email-using-8bit \
1344+
2>errors >out &&
1345+
sed '1,/^$/d' msgtxt1 >actual &&
1346+
sed '1,/^$/d' email-using-8bit >expected &&
1347+
test_cmp expected actual
1348+
'
1349+
1350+
test_expect_success $PREREQ 'setup expect' '
1351+
cat >expected <<EOF
1352+
Dieser Betreff enth=C3=A4lt auch einen Umlaut!
1353+
EOF
1354+
'
1355+
1356+
test_expect_success $PREREQ '8-bit and sendemail.transferencoding=quoted-printable' '
1357+
clean_fake_sendmail &&
1358+
git send-email \
1359+
--transfer-encoding=quoted-printable \
1360+
--smtp-server="$(pwd)/fake.sendmail" \
1361+
email-using-8bit \
1362+
2>errors >out &&
1363+
sed '1,/^$/d' msgtxt1 >actual &&
1364+
test_cmp expected actual
1365+
'
1366+
1367+
test_expect_success $PREREQ 'setup expect' '
1368+
cat >expected <<EOF
1369+
RGllc2VyIEJldHJlZmYgZW50aMOkbHQgYXVjaCBlaW5lbiBVbWxhdXQhCg==
1370+
EOF
1371+
'
1372+
1373+
test_expect_success $PREREQ '8-bit and sendemail.transferencoding=base64' '
1374+
clean_fake_sendmail &&
1375+
git send-email \
1376+
--transfer-encoding=base64 \
1377+
--smtp-server="$(pwd)/fake.sendmail" \
1378+
email-using-8bit \
1379+
2>errors >out &&
1380+
sed '1,/^$/d' msgtxt1 >actual &&
1381+
test_cmp expected actual
1382+
'
1383+
1384+
test_expect_success $PREREQ 'setup expect' '
1385+
cat >email-using-qp <<EOF
1386+
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
1387+
Message-Id: <bogus-message-id@example.com>
1388+
From: A U Thor <author@example.com>
1389+
Date: Sat, 12 Jun 2010 15:53:58 +0200
1390+
MIME-Version: 1.0
1391+
Content-Transfer-Encoding: quoted-printable
1392+
Content-Type: text/plain; charset=UTF-8
1393+
Subject: Nothing to see here.
1394+
1395+
Dieser Betreff enth=C3=A4lt auch einen Umlaut!
1396+
EOF
1397+
'
1398+
1399+
test_expect_success $PREREQ 'convert from quoted-printable to base64' '
1400+
clean_fake_sendmail &&
1401+
git send-email \
1402+
--transfer-encoding=base64 \
1403+
--smtp-server="$(pwd)/fake.sendmail" \
1404+
email-using-qp \
1405+
2>errors >out &&
1406+
sed '1,/^$/d' msgtxt1 >actual &&
1407+
test_cmp expected actual
1408+
'
1409+
1410+
test_expect_success $PREREQ 'setup expect' "
1411+
tr -d '\\015' | tr '%' '\\015' > email-using-crlf <<EOF
1412+
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
1413+
Message-Id: <bogus-message-id@example.com>
1414+
From: A U Thor <author@example.com>
1415+
Date: Sat, 12 Jun 2010 15:53:58 +0200
1416+
Content-Type: text/plain; charset=UTF-8
1417+
Subject: Nothing to see here.
1418+
1419+
Look, I have a CRLF and an = sign!%
1420+
EOF
1421+
"
1422+
1423+
test_expect_success $PREREQ 'setup expect' '
1424+
cat >expected <<EOF
1425+
Look, I have a CRLF and an =3D sign!=0D
1426+
EOF
1427+
'
1428+
1429+
test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=quoted-printable' '
1430+
clean_fake_sendmail &&
1431+
git send-email \
1432+
--transfer-encoding=quoted-printable \
1433+
--smtp-server="$(pwd)/fake.sendmail" \
1434+
email-using-crlf \
1435+
2>errors >out &&
1436+
sed '1,/^$/d' msgtxt1 >actual &&
1437+
test_cmp expected actual
1438+
'
1439+
1440+
test_expect_success $PREREQ 'setup expect' '
1441+
cat >expected <<EOF
1442+
TG9vaywgSSBoYXZlIGEgQ1JMRiBhbmQgYW4gPSBzaWduIQ0K
1443+
EOF
1444+
'
1445+
1446+
test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=base64' '
1447+
clean_fake_sendmail &&
1448+
git send-email \
1449+
--transfer-encoding=base64 \
1450+
--smtp-server="$(pwd)/fake.sendmail" \
1451+
email-using-crlf \
1452+
2>errors >out &&
1453+
sed '1,/^$/d' msgtxt1 >actual &&
1454+
test_cmp expected actual
1455+
'
1456+
1457+
13011458
# Note that the patches in this test are deliberately out of order; we
13021459
# want to make sure it works even if the cover-letter is not in the
13031460
# first mail.

0 commit comments

Comments
 (0)