From 609d2a88349963d1b355062eec97506ec0e69f65 Mon Sep 17 00:00:00 2001 From: Wolfgang Faust Date: Tue, 1 Sep 2026 17:13:21 -0700 Subject: [PATCH] imap-send: add --draft to set IMAP \Draft flag 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 Signed-off-by: Junio C Hamano --- 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 538b91afc0..fab3d82e02 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) ] +git imap-send [-v] [-q] [--[no-]curl] [--[no-]draft] [(--folder|-f) ] 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 cfd6a5120c..7a50f9e5ab 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) ] < "), + N_("git imap-send [-v] [-q] [--[no-]curl] [--[no-]draft] [(--folder|-f) ] < "), "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) {