Volume XXII, number 279Tuesday, October 6, 2026Latest message 44 minutes ago

The Git List

News and archive of git@vger.kernel.org, since April 2005

patchimap-send: add --draft to set IMAP \Draft flag

7 messages between Sep 2, 2026 and Sep 3, 2026, from Wolfgang Faust, Junio C Hamano, Aditya Garg.

Plain Markdown or JSON for tools and agents. Diffs are folded; open one to read it.

Wolfgang FaustSep 2, 2026, 00:13 UTC on lore

The documented purpose of imap-send is to upload draft emails for sending later, but it did not have any way to mark the messages as \Draft, so some email clients presented the result as an un-editable, un-sendable email even if it happened to be in a "Drafts" folder.

Signed-off-by: Wolfgang Faust <contrib-git@wolfgangfaust.com>
---
 Documentation/git-imap-send.adoc |  9 ++++++++-
 git-curl-compat.h                |  8 ++++++++
 imap-send.c                      | 15 +++++++++++++--
 3 files changed, 29 insertions(+), 3 deletions(-)
Show changes to 3 files +29 −3

Documentation/git-imap-send.adoc, git-curl-compat.h, imap-send.c

diff --git a/Documentation/git-imap-send.adoc b/Documentation/git-imap-send.adoc
index 1814d94491..cf415df45a 100644
--- a/Documentation/git-imap-send.adoc
+++ b/Documentation/git-imap-send.adoc
@@ -9,7 +9,7 @@ git-imap-send - Send a collection of patches from stdin to an IMAP folder
 SYNOPSIS
 --------
 [synopsis]
-git imap-send [-v] [-q] [--[no-]curl] [(--folder|-f) <folder>]
+git imap-send [-v] [-q] [--[no-]curl] [--[no-]draft] [(--folder|-f) <folder>]
 git imap-send --list
 
 
@@ -55,6 +55,13 @@ OPTIONS
 	using libcurl.  Ignored if Git was built with the NO_OPENSSL option
 	set.
 
+`--draft`::
+`--no-draft`::
+	Mark uploaded messages with the IMAP `\Draft` flag. The default is `--no-draft`.
++
+With libcurl, `--draft` requires version 8.13.0 or later.
+Older libcurl still uploads the message but cannot set the flag.
+
 `--list`::
 	Run the IMAP LIST command to output a list of all the folders present.
 
diff --git a/git-curl-compat.h b/git-curl-compat.h
index dccdd4d6e5..032aaf7126 100644
--- a/git-curl-compat.h
+++ b/git-curl-compat.h
@@ -67,4 +67,12 @@
 #define GIT_CURL_HAVE_CURLOPT_TCP_KEEPCNT
 #endif
 
+/**
+ * CURLOPT_UPLOAD_FLAGS and CURLULFLAG_* were added in 8.13.0,
+ * released in April 2025.
+ */
+#if LIBCURL_VERSION_NUM >= 0x080D00
+#define GIT_CURL_HAVE_CURLOPT_UPLOAD_FLAGS
+#endif
+
 #endif
diff --git a/imap-send.c b/imap-send.c
index 0d16d02029..bf1d2cf74d 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -35,6 +35,7 @@
 #include "setup.h"
 #include "strbuf.h"
 #ifdef USE_CURL_FOR_IMAP_SEND
+#include "git-curl-compat.h"
 #include "http.h"
 #endif
 
@@ -49,10 +50,11 @@
 static int verbosity;
 static int list_folders;
 static int use_curl = USE_CURL_DEFAULT;
+static int opt_draft;
 static char *opt_folder;
 
 static char const * const imap_send_usage[] = {
-	N_("git imap-send [-v] [-q] [--[no-]curl] [(--folder|-f) <folder>] < <mbox>"),
+	N_("git imap-send [-v] [-q] [--[no-]curl] [--[no-]draft] [(--folder|-f) <folder>] < <mbox>"),
 	"git imap-send --list",
 	NULL
 };
@@ -60,6 +62,7 @@ static char const * const imap_send_usage[] = {
 static struct option imap_send_options[] = {
 	OPT__VERBOSITY(&verbosity),
 	OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
+	OPT_BOOL(0, "draft", &opt_draft, "mark uploaded messages with the IMAP \\Draft flag"),
 	OPT_STRING('f', "folder", &opt_folder, "folder", "specify the IMAP folder"),
 	OPT_BOOL(0, "list", &list_folders, "list all folders on the IMAP server"),
 	OPT_END()
@@ -1416,7 +1419,8 @@ static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg)
 
 	box = ctx->name;
 	prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
-	ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" ", prefix, box);
+	ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" %s", prefix, box,
+			  opt_draft ? "(\\Draft) " : "");
 	imap->caps = imap->rcaps;
 	if (ret != DRV_OK)
 		return ret;
@@ -1718,6 +1722,13 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,
 
 	curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);
 
+	if (opt_draft) {
+#ifdef GIT_CURL_HAVE_CURLOPT_UPLOAD_FLAGS
+		curl_easy_setopt(curl, CURLOPT_UPLOAD_FLAGS, CURLULFLAG_DRAFT);
+#else
+		warning("--draft requires libcurl 8.13.0 or later");
+#endif
+	}
 	fprintf(stderr, "Sending %d message%s to %s folder...\n",
 		total, (total != 1) ? "s" : "", server->folder);
 	while (1) {
-- 
2.52.0
Junio C HamanoSep 2, 2026, 03:25 UTC in reply to Wolfgang Faust on lore

Re: [PATCH] imap-send: add --draft to set IMAP \Draft flag

"Wolfgang Faust" <contrib-git@wolfgangfaust.com> writes:
> The documented purpose of imap-send is to upload draft emails for sending
> later, but it did not have any way to mark the messages as \Draft, so some
> email clients presented the result as an un-editable, un-sendable email
> even if it happened to be in a "Drafts" folder.

I agree that defaulting to '--no-draft' is a sensible design choice to avoid breaking clients that have been working fine.

It would be helpful to know if e-mail clients that send messages from the Drafts folder without the '\Draft' flag would misbehave if they encounter messages marked as such. Knowing this would help us decide whether to flip the default to '--draft', while keeping '--no-draft' as an escape hatch nobody is expected to use.

Show 6 quoted lines
> +`--draft`::
> +`--no-draft`::
> +	Mark uploaded messages with the IMAP `\Draft` flag. The default is `--no-draft`.
> ++
> +With libcurl, `--draft` requires version 8.13.0 or later.
> +Older libcurl still uploads the message but cannot set the flag.

When compiled with older libcurl, would the command error out when run with '--draft', or would it silently ignore the option? I have a mild preference for the former over the latter. Issuing a warning without erroring out is better than nothing, but people tend to overlook warning messages.

Also you might want to consider adding a configuration variable, perhaps? I dunno.

Thanks.
Wolfgang FaustSep 2, 2026, 04:28 UTC in reply to Junio C Hamano on lore

Re: [PATCH] imap-send: add --draft to set IMAP \Draft flag

On Tue, Sep 1, 2026, at 8:25 PM, Junio C Hamano wrote:
Show 9 quoted lines
> "Wolfgang Faust" <contrib-git@wolfgangfaust.com> writes:
>
>> The documented purpose of imap-send is to upload draft emails for sending
>> later, but it did not have any way to mark the messages as \Draft, so some
>> email clients presented the result as an un-editable, un-sendable email
>> even if it happened to be in a "Drafts" folder.
>
> I agree that defaulting to '--no-draft' is a sensible design choice
> to avoid breaking clients that have been working fine.
Definite agree; I elaborate further below.
> It would be helpful to know if e-mail clients that send messages
> from the Drafts folder without the '\Draft' flag would misbehave if
> they encounter messages marked as such.

Not sure how to find this out without doing a complete survey of every possible email client, but I think it's unlikely to be a major issue: any such client would already be incompatible with other standards- compliant clients using the same IMAP account. However:

> Knowing this would help us
> decide whether to flip the default to '--draft', while keeping
> '--no-draft' as an escape hatch nobody is expected to use.
I think the default should probably be --no-draft anyway.
First, imap-send is also used for cases like `git send-email
--imap-sent-folder`, which would need to be taught *not* to mark the
email as a draft, as in this case it has already been sent and should
not be editable. We can change `send-email` to set that flag but this
does not help any external tooling that might be relying on this
behavior.
 
Second, as `--draft` requires a relatively recent version of curl, or a
(non-default) `--no-curl` flag, trying to turn it on would cause most
current systems to continue *not* updating the flag, so in practice
the behavior would change depending on the user's system libraries,
which seems very unusual. (Or, if we changed the curl version check
from warning to error, the command would default to being broken unless
you pass `--no-draft`.)
Show 12 quoted lines
>> +`--draft`::
>> +`--no-draft`::
>> +	Mark uploaded messages with the IMAP `\Draft` flag. The default is `--no-draft`.
>> ++
>> +With libcurl, `--draft` requires version 8.13.0 or later.
>> +Older libcurl still uploads the message but cannot set the flag.
>
> When compiled with older libcurl, would the command error out when
> run with '--draft', or would it silently ignore the option?  I have
> a mild preference for the former over the latter.  Issuing a warning
> without erroring out is better than nothing, but people tend to
> overlook warning messages.

Right now it issues a warning. I don't think I had any particular reason for that decision and changing to an error seems fine.

> Also you might want to consider adding a configuration variable,
> perhaps?  I dunno.

I assume you mean something like `git config imap.draft true`? This has all the same problems as changing the default (in particular the `--imap-sent-folder` case), though I guess at least it would be opt-in.

I also read in some past thread (I forget which) that we generally want to start by adding a flag, and only introduce a configuration if there is demand for it after the flag has proven itself.

> Thanks.
Junio C HamanoSep 2, 2026, 14:37 UTC in reply to Wolfgang Faust on lore

Re: [PATCH] imap-send: add --draft to set IMAP \Draft flag

"Wolfgang Faust" <contrib-git@wolfgangfaust.com> writes:
> I also read in some past thread (I forget which) that we generally want
> to start by adding a flag, and only introduce a configuration if there
> is demand for it after the flag has proven itself.

That indeed is a strong personal prefference of mine. Sadly, nobody seems to have followed it in their topics---you are the first ;-).

Aditya GargSep 3, 2026, 05:42 UTC in reply to Wolfgang Faust on lore

Re: [PATCH] imap-send: add --draft to set IMAP \Draft flag

I'm not sure if its acceptable to use newer versions of curl.
This patch was rejected because of this reason: https://lore.kernel.org/git/7108764f437a25079c95a25c227eb79f9f4aee6a.1753273554.git.gargaditya08@live.com/
On 02/09/26 5:43 am, Wolfgang Faust wrote:
Show 113 quoted lines
> The documented purpose of imap-send is to upload draft emails for sending
> later, but it did not have any way to mark the messages as \Draft, so some
> email clients presented the result as an un-editable, un-sendable email
> even if it happened to be in a "Drafts" folder.
> 
> Signed-off-by: Wolfgang Faust <contrib-git@wolfgangfaust.com>
> ---
>  Documentation/git-imap-send.adoc |  9 ++++++++-
>  git-curl-compat.h                |  8 ++++++++
>  imap-send.c                      | 15 +++++++++++++--
>  3 files changed, 29 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/git-imap-send.adoc b/Documentation/git-imap-send.adoc
> index 1814d94491..cf415df45a 100644
> --- a/Documentation/git-imap-send.adoc
> +++ b/Documentation/git-imap-send.adoc
> @@ -9,7 +9,7 @@ git-imap-send - Send a collection of patches from stdin to an IMAP folder
>  SYNOPSIS
>  --------
>  [synopsis]
> -git imap-send [-v] [-q] [--[no-]curl] [(--folder|-f) <folder>]
> +git imap-send [-v] [-q] [--[no-]curl] [--[no-]draft] [(--folder|-f) <folder>]
>  git imap-send --list
>  
>  
> @@ -55,6 +55,13 @@ OPTIONS
>  	using libcurl.  Ignored if Git was built with the NO_OPENSSL option
>  	set.
>  
> +`--draft`::
> +`--no-draft`::
> +	Mark uploaded messages with the IMAP `\Draft` flag. The default is `--no-draft`.
> ++
> +With libcurl, `--draft` requires version 8.13.0 or later.
> +Older libcurl still uploads the message but cannot set the flag.
> +
>  `--list`::
>  	Run the IMAP LIST command to output a list of all the folders present.
>  
> diff --git a/git-curl-compat.h b/git-curl-compat.h
> index dccdd4d6e5..032aaf7126 100644
> --- a/git-curl-compat.h
> +++ b/git-curl-compat.h
> @@ -67,4 +67,12 @@
>  #define GIT_CURL_HAVE_CURLOPT_TCP_KEEPCNT
>  #endif
>  
> +/**
> + * CURLOPT_UPLOAD_FLAGS and CURLULFLAG_* were added in 8.13.0,
> + * released in April 2025.
> + */
> +#if LIBCURL_VERSION_NUM >= 0x080D00
> +#define GIT_CURL_HAVE_CURLOPT_UPLOAD_FLAGS
> +#endif
> +
>  #endif
> diff --git a/imap-send.c b/imap-send.c
> index 0d16d02029..bf1d2cf74d 100644
> --- a/imap-send.c
> +++ b/imap-send.c
> @@ -35,6 +35,7 @@
>  #include "setup.h"
>  #include "strbuf.h"
>  #ifdef USE_CURL_FOR_IMAP_SEND
> +#include "git-curl-compat.h"
>  #include "http.h"
>  #endif
>  
> @@ -49,10 +50,11 @@
>  static int verbosity;
>  static int list_folders;
>  static int use_curl = USE_CURL_DEFAULT;
> +static int opt_draft;
>  static char *opt_folder;
>  
>  static char const * const imap_send_usage[] = {
> -	N_("git imap-send [-v] [-q] [--[no-]curl] [(--folder|-f) <folder>] < <mbox>"),
> +	N_("git imap-send [-v] [-q] [--[no-]curl] [--[no-]draft] [(--folder|-f) <folder>] < <mbox>"),
>  	"git imap-send --list",
>  	NULL
>  };
> @@ -60,6 +62,7 @@ static char const * const imap_send_usage[] = {
>  static struct option imap_send_options[] = {
>  	OPT__VERBOSITY(&verbosity),
>  	OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
> +	OPT_BOOL(0, "draft", &opt_draft, "mark uploaded messages with the IMAP \\Draft flag"),
>  	OPT_STRING('f', "folder", &opt_folder, "folder", "specify the IMAP folder"),
>  	OPT_BOOL(0, "list", &list_folders, "list all folders on the IMAP server"),
>  	OPT_END()
> @@ -1416,7 +1419,8 @@ static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg)
>  
>  	box = ctx->name;
>  	prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
> -	ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" ", prefix, box);
> +	ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" %s", prefix, box,
> +			  opt_draft ? "(\\Draft) " : "");
>  	imap->caps = imap->rcaps;
>  	if (ret != DRV_OK)
>  		return ret;
> @@ -1718,6 +1722,13 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,
>  
>  	curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);
>  
> +	if (opt_draft) {
> +#ifdef GIT_CURL_HAVE_CURLOPT_UPLOAD_FLAGS
> +		curl_easy_setopt(curl, CURLOPT_UPLOAD_FLAGS, CURLULFLAG_DRAFT);
> +#else
> +		warning("--draft requires libcurl 8.13.0 or later");
> +#endif
> +	}
>  	fprintf(stderr, "Sending %d message%s to %s folder...\n",
>  		total, (total != 1) ? "s" : "", server->folder);
>  	while (1) {
Junio C HamanoSep 3, 2026, 13:42 UTC in reply to Aditya Garg on lore

Re: [PATCH] imap-send: add --draft to set IMAP \Draft flag

Aditya Garg <gargaditya08@live.com> writes:
> I'm not sure if its acceptable to use newer versions of curl.
>
> This patch was rejected because of this reason: https://lore.kernel.org/git/7108764f437a25079c95a25c227eb79f9f4aee6a.1753273554.git.gargaditya08@live.com/

A huge difference is that the patch in the thread you pointed at did not come any way to build with older versions. The patch in this thread is different, isn't it?

Aditya GargSep 3, 2026, 14:37 UTC in reply to Junio C Hamano on lore

Re: [PATCH] imap-send: add --draft to set IMAP \Draft flag

So we can still consider that patch if I add version checks right?
Show 11 quoted lines
> On 3 Sep 2026, at 7:12 PM, Junio C Hamano <gitster@pobox.com> wrote:
> 
> Aditya Garg <gargaditya08@live.com> writes:
> 
>> I'm not sure if its acceptable to use newer versions of curl.
>> 
>> This patch was rejected because of this reason: https://lore.kernel.org/git/7108764f437a25079c95a25c227eb79f9f4aee6a.1753273554.git.gargaditya08@live.com/
> 
> A huge difference is that the patch in the thread you pointed at did
> not come any way to build with older versions.  The patch in this
> thread is different, isn't it?

Back to recent threads