[PATCH v3] send-email: add ability to send a copy of sent emails to an IMAP folder
From: Aditya Garg <hidden>
Date: 2025-07-22 11:14:21
Subsystem:
documentation, the rest · Maintainers:
Jonathan Corbet, Linus Torvalds
Some email providers like Apple iCloud Mail do not support sending a copy of sent emails to the "Sent" folder if SMTP server is used. As a workaround, various email clients like Thunderbird which rely on SMTP, use IMAP to send a copy of sent emails to the "Sent" folder. Something similar can be done if sending emails via `git send-email`, by using the `git imap-send` command to send a copy of the sent email to an IMAP folder specified by the user. Add this functionality to `git send-email` by introducing a new configuration variable `sendemail.imapfolder` and command line option `--imap-folder` which specifies the IMAP folder to send a copy of the sent emails to. If specified, a copy of the sent emails will be sent by piping the emails to `git imap-send` command, after the all emails are sent via SMTP and the SMTP server has been closed. Signed-off-by: Aditya Garg <redacted> --- v2 - Fix indentation in patch for imap-send.c - Minor edits to commit message v3 - Rename imap folder to imap sent folder - Make an error message shorter by removing unecessary details Documentation/config/sendemail.adoc | 1 + Documentation/git-send-email.adoc | 12 +++++++++++ git-send-email.perl | 31 ++++++++++++++++++++++++++++- imap-send.c | 26 ++++++++++++++++-------- 4 files changed, 61 insertions(+), 9 deletions(-)
diff --git a/Documentation/config/sendemail.adoc b/Documentation/config/sendemail.adoc
index 4722334657..dd2dbc87a0 100644
--- a/Documentation/config/sendemail.adoc
+++ b/Documentation/config/sendemail.adoc@@ -88,6 +88,7 @@ sendemail.smtpServer:: sendemail.smtpServerPort:: sendemail.smtpServerOption:: sendemail.smtpUser:: +sendemail.imapSentFolder:: sendemail.thread:: sendemail.transferEncoding:: sendemail.validate::
diff --git a/Documentation/git-send-email.adoc b/Documentation/git-send-email.adoc
index 5335502d68..82a65fd47f 100644
--- a/Documentation/git-send-email.adoc
+++ b/Documentation/git-send-email.adoc@@ -299,6 +299,18 @@ must be used for each option. commands and replies will be printed. Useful to debug TLS connection and authentication problems. +--imap-sent-folder=<folder>:: + Some email providers (e.g. iCloud) do not send a copy of the emails sent + using SMTP to the `Sent` folder or similar in your mailbox. Use this option + to use `git imap-send` to send a copy of the emails to the folder specified + using this option. You can run `git imap-send --list` to get a list of + valid folder names, including the correct name of the `Sent` folder in + your mailbox. You can also use this option to send emails to a dedicated + IMAP folder of your choice. ++ +This feature requires setting up `git imap-send`. See linkgit:git-imap-send[1] +to get instructions for the same. + --batch-size=<num>:: Some email servers (e.g. 'smtp.163.com') limit the number of emails to be sent per session (connection) and this will lead to a failure when
diff --git a/git-send-email.perl b/git-send-email.perl
index 437f8ac46a..5aafe8cdf3 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl@@ -73,6 +73,8 @@ sub usage { --no-smtp-auth * Disable SMTP authentication. Shorthand for `--smtp-auth=none` --smtp-debug <0|1> * Disable, enable Net::SMTP debug. + --imap-sent-folder <str> * IMAP folder where a copy of the emails should be sent. + Make sure `git imap-send` is setup to use this feature. --batch-size <int> * send max <int> message per connection. --relogin-delay <int> * delay <int> seconds between two successive login.
@@ -200,7 +202,7 @@ sub format_2822_time { # Variables we fill in automatically, or via prompting: my (@to,@cc,@xh,$envelope_sender, - $initial_in_reply_to,$reply_to,$initial_subject,@files, + $initial_in_reply_to,$reply_to,$initial_subject,@files,@imap_copy, $author,$sender,$smtp_authpass,$annotate,$compose,$time); # Things we either get from config, *or* are overridden on the # command-line.
@@ -277,6 +279,7 @@ sub do_edit { my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path); my ($batch_size, $relogin_delay); my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth); +my ($imap_sent_folder); my ($confirm); my (@suppress_cc); my ($auto_8bit_encoding);
@@ -322,6 +325,7 @@ sub do_edit { "smtpauth" => \$smtp_auth, "smtpbatchsize" => \$batch_size, "smtprelogindelay" => \$relogin_delay, + "imapsentfolder" => \$imap_sent_folder, "to" => \@config_to, "tocmd" => \$to_cmd, "cc" => \@config_cc,
@@ -527,6 +531,7 @@ sub config_regexp { "smtp-domain:s" => \$smtp_domain, "smtp-auth=s" => \$smtp_auth, "no-smtp-auth" => sub {$smtp_auth = 'none'}, + "imap-sent-folder=s" => \$imap_sent_folder, "annotate!" => \$annotate, "compose" => \$compose, "quiet" => \$quiet,
@@ -1829,6 +1834,17 @@ sub send_message { print "\n"; } + if ($imap_sent_folder) { + my $imap_header = $header; + if (@initial_bcc) { + # Bcc is not a part of $header, so we add it here. + # This is only for the IMAP copy, not for the actual email + # sent to the recipients. + $imap_header .= "Bcc: " . join(", ", @initial_bcc) . "\n"; + } + push @imap_copy, "From git-send-email\n$imap_header\n$message"; + } + return 1; }
@@ -2223,6 +2239,19 @@ sub cleanup_compose_files { $smtp->quit if $smtp; +if ($imap_sent_folder && @imap_copy) { + my $imap_input = join("\n", @imap_copy); + eval { + print "\nStarting git imap-send...\n"; + my ($fh, $ctx) = Git::command_input_pipe(['imap-send', '-f', $imap_sent_folder]); + print $fh $imap_input; + Git::command_close_pipe($fh, $ctx); + 1; + } or do { + warn "Warning: failed to send messages to IMAP folder $imap_sent_folder: $@"; + }; +} + sub apply_transfer_encoding { my $message = shift; my $from = shift;
diff --git a/imap-send.c b/imap-send.c
index f5a656ac71..44de0c5a77 100644
--- a/imap-send.c
+++ b/imap-send.c@@ -1441,14 +1441,24 @@ static int count_messages(struct strbuf *all_msgs) while (1) { if (starts_with(p, "From ")) { - p = strstr(p+5, "\nFrom: "); - if (!p) break; - p = strstr(p+7, "\nDate: "); - if (!p) break; - p = strstr(p+7, "\nSubject: "); - if (!p) break; - p += 10; - count++; + if (starts_with(p, "From git-send-email")) { + p = strstr(p+5, "\nFrom: "); + if (!p) break; + p += 7; + p = strstr(p, "\nTo: "); + if (!p) break; + p += 5; + count++; + } else { + p = strstr(p+5, "\nFrom: "); + if (!p) break; + p = strstr(p+7, "\nDate: "); + if (!p) break; + p = strstr(p+7, "\nSubject: "); + if (!p) break; + p += 10; + count++; + } } p = strstr(p+5, "\nFrom "); if (!p)
Range-diff against v2:
1: 01084f57f9 ! 1: da7cee769f send-email: add ability to send a copy of sent emails to an IMAP folder
@@ Documentation/config/sendemail.adoc: sendemail.smtpServer::
sendemail.smtpServerPort::
sendemail.smtpServerOption::
sendemail.smtpUser::
-+sendemail.imapfolder::
++sendemail.imapSentFolder::
sendemail.thread::
sendemail.transferEncoding::
sendemail.validate::
@@ Documentation/git-send-email.adoc: must be used for each option.
commands and replies will be printed. Useful to debug TLS
connection and authentication problems.
-+--imap-folder=<folder>::
++--imap-sent-folder=<folder>::
+ Some email providers (e.g. iCloud) do not send a copy of the emails sent
+ using SMTP to the `Sent` folder or similar in your mailbox. Use this option
+ to use `git imap-send` to send a copy of the emails to the folder specified
@@ git-send-email.perl: sub usage {
--no-smtp-auth * Disable SMTP authentication. Shorthand for
`--smtp-auth=none`
--smtp-debug <0|1> * Disable, enable Net::SMTP debug.
-+ --imap-folder <str> * IMAP folder where a copy of the emails should be sent.
++ --imap-sent-folder <str> * IMAP folder where a copy of the emails should be sent.
+ Make sure `git imap-send` is setup to use this feature.
--batch-size <int> * send max <int> message per connection.
@@ git-send-email.perl: sub do_edit {
my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
my ($batch_size, $relogin_delay);
my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
-+my ($imap_folder);
++my ($imap_sent_folder);
my ($confirm);
my (@suppress_cc);
my ($auto_8bit_encoding);
@@ git-send-email.perl: sub do_edit {
"smtpauth" => \$smtp_auth,
"smtpbatchsize" => \$batch_size,
"smtprelogindelay" => \$relogin_delay,
-+ "imapfolder" => \$imap_folder,
++ "imapsentfolder" => \$imap_sent_folder,
"to" => \@config_to,
"tocmd" => \$to_cmd,
"cc" => \@config_cc,
@@ git-send-email.perl: sub config_regexp {
"smtp-domain:s" => \$smtp_domain,
"smtp-auth=s" => \$smtp_auth,
"no-smtp-auth" => sub {$smtp_auth = 'none'},
-+ "imap-folder=s" => \$imap_folder,
++ "imap-sent-folder=s" => \$imap_sent_folder,
"annotate!" => \$annotate,
"compose" => \$compose,
"quiet" => \$quiet,
@@ git-send-email.perl: sub send_message {
print "\n";
}
-+ if ($imap_folder) {
++ if ($imap_sent_folder) {
+ my $imap_header = $header;
+ if (@initial_bcc) {
+ # Bcc is not a part of $header, so we add it here.
@@ git-send-email.perl: sub cleanup_compose_files {
$smtp->quit if $smtp;
-+if ($imap_folder && @imap_copy) {
++if ($imap_sent_folder && @imap_copy) {
+ my $imap_input = join("\n", @imap_copy);
+ eval {
+ print "\nStarting git imap-send...\n";
-+ my ($fh, $ctx) = Git::command_input_pipe(['imap-send', '-f', $imap_folder]);
++ my ($fh, $ctx) = Git::command_input_pipe(['imap-send', '-f', $imap_sent_folder]);
+ print $fh $imap_input;
+ Git::command_close_pipe($fh, $ctx);
+ 1;
+ } or do {
-+ warn "Warning: failed to send messages to IMAP folder $imap_folder via imap-send pipe: $@";
++ warn "Warning: failed to send messages to IMAP folder $imap_sent_folder: $@";
+ };
+}
+
--
2.50.1.319.gda7cee769f