git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v5 0/4] docs: update email credential helpers and improve formatting

From
Aditya Garg <gargaditya08@live.com>
Date
May 28, 2025, 09:42 UTC
Message-ID
<PN3PR01MB95972C400AE59DAB2EB388A5B867A@PN3PR01MB9597.INDPRD01.PROD.OUTLOOK.COM>
In-Reply-To
<PN3PR01MB9597EBE360893FA638B17952B867A@PN3PR01MB9597.INDPRD01.PROD.OUTLOOK.COM>
On 28-05-2025 03:06 pm, Aditya Garg wrote:
Show 17 quoted lines
> 
> 
> On 28-05-2025 12:53 pm, Eric Sunshine wrote:
>> On Wed, May 28, 2025 at 3:05 AM Aditya Garg <gargaditya08@live.com> wrote:
>>> v5: Added a patch to make the purpose of using app password for Gmail
>>>     more clear in `send-email` documentation.
>>>
>>> Range-diff:
>>> -:  ---------- > 1:  2c47cc5396 docs: add credential helper for yahoo and link Google's sendgmail tool
>>> -:  ---------- > 2:  bc1d0471ca docs: improve formatting in git-send-email documentation
>>> -:  ---------- > 3:  b9e41e2492 docs: remove credential helper links for emails from gitcredentials
>>> -:  ---------- > 4:  a6ad7ac810 docs: make the purpose of using app password for Gmail more clear in send-email
>>
>> Strange range-diff.
> 
> I think because I used git version 2.43. When I compiled my branch with changes, git format-patch over there
> had a very different range-diff from this.
I get this range-diff with git 2.49
Range-diff:
-:  ---------- > 1:  4757d0305d imap-send: fix bug causing cfg->folder being set to NULL
1:  62edbcfc6e ! 2:  f5ad01abc5 imap-send: enable specifying the folder using the command line
    @@ Metadata
     Author: Aditya Garg <gargaditya08@live.com>
     
      ## Commit message ##
    -    imap-send: enable specifying the folder using the command line
    +    imap-send: add support for OAuth2.0 authentication
     
    -    Some users may very often want to imap-send messages to a folder
    -    other than the default set in the config. Add a command line
    -    argument for the same.
    +    OAuth2.0 is a new way of authentication supported by various email providers
    +    these days. OAUTHBEARER and XOAUTH2 are the two most common mechanisms used
    +    for OAuth2.0. OAUTHBEARER is described in RFC5801[1] and RFC7628[2], whereas
    +    XOAUTH2 is Google's proprietary mechanism (See [3]).
    +
    +    [1]: https://datatracker.ietf.org/doc/html/rfc5801
    +    [2]: https://datatracker.ietf.org/doc/html/rfc7628
    +    [3]: https://developers.google.com/workspace/gmail/imap/xoauth2-protocol#initial_client_response
     
         Signed-off-by: Aditya Garg <gargaditya08@live.com>
     
      ## Documentation/config/imap.adoc ##
    -@@
    - imap.folder::
    - 	The folder to drop the mails into, which is typically the Drafts
    --	folder. For example: "INBOX.Drafts", "INBOX/Drafts" or
    --	"[Gmail]/Drafts". Required.
    -+	folder. For example: 'INBOX.Drafts', 'INBOX/Drafts' or
    -+	'[Gmail]/Drafts'. Required if `--folder` argument is not used. If
    -+	set and `--folder` is also used, `--folder` will be preferred.
    - 
    - imap.tunnel::
    - 	Command used to set up a tunnel to the IMAP server through which
    +@@ Documentation/config/imap.adoc: imap.authMethod::
    + 	Specify the authentication method for authenticating with the IMAP server.
    + 	If Git was built with the NO_CURL option, or if your curl version is older
    + 	than 7.34.0, or if you're running git-imap-send with the `--no-curl`
    +-	option, the only supported method is 'CRAM-MD5'. If this is not set
    +-	then 'git imap-send' uses the basic IMAP plaintext LOGIN command.
    ++	option, the only supported methods are 'CRAM-MD5', 'OAUTHBEARER' and
    ++	'XOAUTH2'. If this is not set then `git imap-send` uses the basic IMAP
    ++	plaintext LOGIN command.
     
      ## Documentation/git-imap-send.adoc ##
    -@@ Documentation/git-imap-send.adoc: OPTIONS
    - --quiet::
    - 	Be quiet.
    - 
    -+-f <folder>::
    -+--folder <folder>::
    -+	Specify the folder in which the emails have to saved.
    -+	For example: `--folder [Gmail]/Drafts` or `-f INBOX/Drafts`.
    -+
    - --curl::
    - 	Use libcurl to communicate with the IMAP server, unless tunneling
    - 	into it.  Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND
    +@@ Documentation/git-imap-send.adoc: Using Gmail's IMAP interface:
    + 
    + ---------
    + [imap]
    +-	folder = "[Gmail]/Drafts"
    +-	host = imaps://imap.gmail.com
    +-	user = user@gmail.com
    +-	port = 993
    ++    folder = "[Gmail]/Drafts"
    ++    host = imaps://imap.gmail.com
    ++    user = user@gmail.com
    ++    port = 993
    + ---------
    + 
    ++Gmail does not allow using your account password for `git imap-send`.
    ++If you have multi-factor authentication set up on your Gmail account, you can generate
    ++an app-specific password for use with `git imap-send`.
    ++Visit https://security.google.com/settings/security/apppasswords to create it.
    ++If you do not want to enable multi-factor authentication, you can use OAuth2.0
    ++authentication as described below.
    ++
    + [NOTE]
    + You might need to instead use: `folder = "[Google Mail]/Drafts"` if you get an error
    + that the "Folder doesn't exist".
    +@@ Documentation/git-imap-send.adoc: that the "Folder doesn't exist".
    + If your Gmail account is set to another language than English, the name of the "Drafts"
    + folder will be localized.
    + 
    ++If you want to use OAuth2.0 based authentication, you can specify `OAUTHBEARER`
    ++or `XOAUTH2` mechanism in your config. In such a case you will have to use an
    ++OAuth2.0 access token in place of your password.
    ++
    ++---------
    ++[imap]
    ++    folder = "[Gmail]/Drafts"
    ++    host = imaps://imap.gmail.com
    ++    user = user@gmail.com
    ++    port = 993
    ++    authmethod = OAUTHBEARER
    ++---------
    ++
    ++Using Outlook's IMAP interface:
    ++
    ++Unlike Gmail, Outlook only supports OAuth2.0 based authentication. Also, it
    ++supports only `XOAUTH2` as the mechanism.
    ++
    ++---------
    ++[imap]
    ++    folder = "Drafts"
    ++    host = imaps://outlook.office365.com
    ++    user = user@outlook.com
    ++    port = 993
    ++    authmethod = XOAUTH2
    ++---------
    ++
    + Once the commits are ready to be sent, run the following command:
    + 
    +   $ git format-patch --cover-letter -M --stdout origin/master | git imap-send
    +@@ Documentation/git-imap-send.adoc: Just make sure to disable line wrapping in the email client (Gmail's web
    + interface will wrap lines no matter what, so you need to use a real
    + IMAP client).
    + 
    ++In case you are using OAuth2.0 authentication, it is easier to use credential
    ++helpers to generate tokens. Credential helpers suggested in
    ++linkgit:git-send-email[1] can be used for `git imap-send` as well.
    ++
    + CAUTION
    + -------
    + It is still your responsibility to make sure that the email message
     
      ## imap-send.c ##
    -@@
    +@@ imap-send.c: enum CAPABILITY {
    + 	LITERALPLUS,
    + 	NAMESPACE,
    + 	STARTTLS,
    +-	AUTH_CRAM_MD5
    ++	AUTH_CRAM_MD5,
    ++	AUTH_OAUTHBEARER,
    ++	AUTH_XOAUTH2
    + };
      
    - static int verbosity;
    - static int use_curl = USE_CURL_DEFAULT;
    -+static char *opt_folder = NULL;
    + static const char *cap_list[] = {
    +@@ imap-send.c: static const char *cap_list[] = {
    + 	"NAMESPACE",
    + 	"STARTTLS",
    + 	"AUTH=CRAM-MD5",
    ++	"AUTH=OAUTHBEARER",
    ++	"AUTH=XOAUTH2",
    + };
      
    - static const char * const imap_send_usage[] = { "git imap-send [-v] [-q] [--[no-]curl] < <mbox>", NULL };
    + #define RESP_OK    0
    +@@ imap-send.c: static char *cram(const char *challenge_64, const char *user, const char *pass)
    + 	return (char *)response_64;
    + }
      
    - static struct option imap_send_options[] = {
    - 	OPT__VERBOSITY(&verbosity),
    - 	OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
    -+	OPT_STRING('f', "folder", &opt_folder, "folder", "specify the IMAP folder"),
    - 	OPT_END()
    - };
    ++static char *oauthbearer_base64(const char *user, const char *access_token)
    ++{
    ++	int raw_len, b64_len;
    ++	char *raw, *b64;
    ++
    ++	/* Compose the OAUTHBEARER string
    ++	 *
    ++	 * "n,a=" {User} ",^Ahost=" {Host} "^Aport=" {Port} "^Aauth=Bearer " {Access Token} "^A^A
    ++	 *
    ++	 * The first part `n,a=" {User} ",` is the gs2 header described in RFC5801.
    ++	 * * gs2-cb-flag `n` -> client does not support CB
    ++	 * * gs2-authzid `a=" {User} "`
    ++	 *
    ++	 * The second part are key value pairs containing host, port and auth as
    ++	 * described in RFC7628.
    ++	 *
    ++	 * https://datatracker.ietf.org/doc/html/rfc5801
    ++	 * https://datatracker.ietf.org/doc/html/rfc7628
    ++	 */
    ++	raw_len = strlen(user) + strlen(access_token) + 20;
    ++	raw = xmallocz(raw_len + 1);
    ++	snprintf(raw, raw_len + 1, "n,a=%s,\001auth=Bearer %s\001\001", user, access_token);
    ++
    ++	/* Base64 encode */
    ++	b64 = xmallocz(ENCODED_SIZE(strlen(raw)));
    ++	b64_len = EVP_EncodeBlock((unsigned char *)b64, (unsigned char *)raw, strlen(raw));
    ++	free(raw);
    ++
    ++	if (b64_len < 0) {
    ++		free(b64);
    ++		return NULL;
    ++	}
    ++	return b64;
    ++}
    ++
    ++static char *xoauth2_base64(const char *user, const char *access_token)
    ++{
    ++	int raw_len, b64_len;
    ++	char *raw, *b64;
    ++
    ++	/* Compose the XOAUTH2 string
    ++	 * "user=" {User} "^Aauth=Bearer " {Access Token} "^A^A"
    ++	 * https://developers.google.com/workspace/gmail/imap/xoauth2-protocol#initial_client_response
    ++	 */
    ++	raw_len = strlen(user) + strlen(access_token) + 20;
    ++	raw = xmallocz(raw_len + 1);
    ++	snprintf(raw, raw_len + 1, "user=%s\001auth=Bearer %s\001\001", user, access_token);
    ++
    ++	/* Base64 encode */
    ++	b64 = xmallocz(ENCODED_SIZE(strlen(raw)));
    ++	b64_len = EVP_EncodeBlock((unsigned char *)b64, (unsigned char *)raw, strlen(raw));
    ++	free(raw);
    ++
    ++	if (b64_len < 0) {
    ++		free(b64);
    ++		return NULL;
    ++	}
    ++	return b64;
    ++}
    ++
    + #else
      
    -@@ imap-send.c: int cmd_main(int argc, const char **argv)
    + static char *cram(const char *challenge_64 UNUSED,
    +@@ imap-send.c: static char *cram(const char *challenge_64 UNUSED,
    + 	    "you have to build git-imap-send with OpenSSL library.");
    + }
      
    - 	argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0);
    ++static char *oauthbearer_base64(const char *user UNUSED,
    ++		  const char *access_token UNUSED)
    ++{
    ++	die("You are trying to use OAUTHBEARER authenticate method "
    ++	    "with OpenSSL library, but it's support has not been compiled in.");
    ++}
    ++
    ++static char *xoauth2_base64(const char *user UNUSED,
    ++		  const char *access_token UNUSED)
    ++{
    ++	die("You are trying to use XOAUTH2 authenticate method "
    ++	    "with OpenSSL library, but it's support has not been compiled in.");
    ++}
    ++
    + #endif
      
    -+	if (opt_folder) {
    -+		free(server.folder);
    -+		server.folder = xstrdup(opt_folder);
    + static int auth_cram_md5(struct imap_store *ctx, const char *prompt)
    +@@ imap-send.c: static int auth_cram_md5(struct imap_store *ctx, const char *prompt)
    + 	return 0;
    + }
    + 
    ++static int auth_oauthbearer(struct imap_store *ctx, const char *prompt UNUSED)
    ++{
    ++	int ret;
    ++	char *b64;
    ++
    ++	b64 = oauthbearer_base64(ctx->cfg->user, ctx->cfg->pass);
    ++	if (!b64)
    ++		return error("OAUTHBEARER: base64 encoding failed");
    ++
    ++	/* Send the base64-encoded response */
    ++	ret = socket_write(&ctx->imap->buf.sock, b64, strlen(b64));
    ++	if (ret != (int)strlen(b64)) {
    ++		free(b64);
    ++		return error("IMAP error: sending OAUTHBEARER response failed");
    ++	}
    ++
    ++	free(b64);
    ++	return 0;
    ++}
    ++
    ++static int auth_xoauth2(struct imap_store *ctx, const char *prompt UNUSED)
    ++{
    ++	int ret;
    ++	char *b64;
    ++
    ++	b64 = xoauth2_base64(ctx->cfg->user, ctx->cfg->pass);
    ++	if (!b64)
    ++		return error("XOAUTH2: base64 encoding failed");
    ++
    ++	/* Send the base64-encoded response */
    ++	ret = socket_write(&ctx->imap->buf.sock, b64, strlen(b64));
    ++	if (ret != (int)strlen(b64)) {
    ++		free(b64);
    ++		return error("IMAP error: sending XOAUTH2 response failed");
     +	}
     +
    - 	if (argc)
    - 		usage_with_options(imap_send_usage, imap_send_options);
    ++	free(b64);
    ++	return 0;
    ++}
    ++
    + static void server_fill_credential(struct imap_server_conf *srvc, struct credential *cred)
    + {
    + 	if (srvc->user && srvc->pass)
    +@@ imap-send.c: static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
    + 					fprintf(stderr, "IMAP error: AUTHENTICATE CRAM-MD5 failed\n");
    + 					goto bail;
    + 				}
    ++			} else if (!strcmp(srvc->auth_method, "OAUTHBEARER")) {
    ++				if (!CAP(AUTH_OAUTHBEARER)) {
    ++					fprintf(stderr, "You specified "
    ++						"OAUTHBEARER as authentication method, "
    ++						"but %s doesn't support it.\n", srvc->host);
    ++					goto bail;
    ++				}
    ++				/* OAUTHBEARER */
    ++
    ++				memset(&cb, 0, sizeof(cb));
    ++				cb.cont = auth_oauthbearer;
    ++				if (imap_exec(ctx, &cb, "AUTHENTICATE OAUTHBEARER") != RESP_OK) {
    ++					fprintf(stderr, "IMAP error: AUTHENTICATE OAUTHBEARER failed\n");
    ++					goto bail;
    ++				}
    ++			} else if (!strcmp(srvc->auth_method, "XOAUTH2")) {
    ++				if (!CAP(AUTH_XOAUTH2)) {
    ++					fprintf(stderr, "You specified "
    ++						"XOAUTH2 as authentication method, "
    ++						"but %s doesn't support it.\n", srvc->host);
    ++					goto bail;
    ++				}
    ++				/* XOAUTH2 */
    ++
    ++				memset(&cb, 0, sizeof(cb));
    ++				cb.cont = auth_xoauth2;
    ++				if (imap_exec(ctx, &cb, "AUTHENTICATE XOAUTH2") != RESP_OK) {
    ++					fprintf(stderr, "IMAP error: AUTHENTICATE XOAUTH2 failed\n");
    ++					goto bail;
    ++				}
    + 			} else {
    + 				fprintf(stderr, "Unknown authentication method:%s\n", srvc->host);
    + 				goto bail;
    +@@ imap-send.c: static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
    + 
    + 	server_fill_credential(srvc, cred);
    + 	curl_easy_setopt(curl, CURLOPT_USERNAME, srvc->user);
    +-	curl_easy_setopt(curl, CURLOPT_PASSWORD, srvc->pass);
    ++
    ++	if (!srvc->auth_method ||
    ++	    strcmp(srvc->auth_method, "XOAUTH2") ||
    ++	    strcmp(srvc->auth_method, "OAUTHBEARER"))
    ++		curl_easy_setopt(curl, CURLOPT_PASSWORD, srvc->pass);
    + 
    + 	strbuf_addstr(&path, srvc->use_ssl ? "imaps://" : "imap://");
    + 	strbuf_addstr(&path, srvc->host);
    +@@ imap-send.c: static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
    + 	curl_easy_setopt(curl, CURLOPT_PORT, srvc->port);
    + 
    + 	if (srvc->auth_method) {
    +-		struct strbuf auth = STRBUF_INIT;
    +-		strbuf_addstr(&auth, "AUTH=");
    +-		strbuf_addstr(&auth, srvc->auth_method);
    +-		curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
    +-		strbuf_release(&auth);
    ++		if (!strcmp(srvc->auth_method, "XOAUTH2") ||
    ++		    !strcmp(srvc->auth_method, "OAUTHBEARER")) {
    ++
    ++			/* While CURLOPT_XOAUTH2_BEARER looks as if it only supports XOAUTH2,
    ++			 * upon debugging, it has been found that it is capable of detecting
    ++			 * the best option out of OAUTHBEARER and XOAUTH2.
    ++			 */
    ++			curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, srvc->pass);
    ++		} else {
    ++			struct strbuf auth = STRBUF_INIT;
    ++			strbuf_addstr(&auth, "AUTH=");
    ++			strbuf_addstr(&auth, srvc->auth_method);
    ++			curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
    ++			strbuf_release(&auth);
    ++		}
    + 	}
      
    + 	if (!srvc->use_ssl)
-:  ---------- > 3:  e3dc19dc49 imap-send: add PLAIN authentication method to OpenSSL
-:  ---------- > 4:  11f7ac1325 imap-send: fix memory leak in case auth_cram_md5 fails
-:  ---------- > 5:  f6e7a5498e imap-send: enable specifying the folder using the command line
2:  245cc89cca = 6:  4769924781 imap-send: enable user to choose between libcurl and openssl using the config
-- 
2.49.0.windows.1
Previous: Aditya GargNext: Aditya Garg
Message 39 of 52 in “docs: add instructions to use Yahoo with send-mail”
  1. docs: add instructions to use Yahoo with send-mailAditya Garg, May 13, 2025
  2. Aditya GargMay 13, 2025
  3. Junio C HamanoMay 13, 2025
  4. Aditya GargMay 13, 2025
  5. Aditya GargMay 13, 2025
  6. Junio C HamanoMay 14, 2025
  7. Aditya GargMay 14, 2025
  8. 0/2 docs: update email credential helpersAditya Garg, May 15, 2025
  9. 1/2 docs: add credential helper for yahoo and link Google's sendgmail toolAditya Garg, May 15, 2025
  10. 2/2 docs: remove credential helper links for emails from gitcredentialsAditya Garg, May 15, 2025
  11. 0/3 docs: update email credential helpers and improve formattingAditya Garg, May 18, 2025
  12. 1/3 docs: add credential helper for yahoo and link Google's sendgmail toolAditya Garg, May 18, 2025
  13. 2/3 docs: improve formatting in git-send-email documentationAditya Garg, May 18, 2025
  14. 3/3 docs: remove credential helper links for emails from gitcredentialsAditya Garg, May 18, 2025
  15. 0/3 docs: update email credential helpers and improve formattingAditya Garg, May 19, 2025
  16. 1/3 docs: add credential helper for yahoo and link Google's sendgmail toolAditya Garg, May 19, 2025
  17. 2/3 docs: improve formatting in git-send-email documentationAditya Garg, May 19, 2025
  18. 3/3 docs: remove credential helper links for emails from gitcredentialsAditya Garg, May 19, 2025
  19. Junio C HamanoMay 19, 2025
  20. Aditya GargMay 19, 2025
  21. 0/4 docs: update email credential helpers and improve formattingAditya Garg, May 28, 2025
  22. 1/4 docs: add credential helper for yahoo and link Google's sendgmail toolAditya Garg, May 28, 2025
  23. 2/4 docs: improve formatting in git-send-email documentationAditya Garg, May 28, 2025
  24. Junio C HamanoMay 29, 2025
  25. Aditya GargMay 29, 2025
  26. Junio C HamanoMay 30, 2025
  27. Aditya GargMay 30, 2025
  28. Junio C HamanoMay 30, 2025
  29. Aditya GargMay 30, 2025
  30. Junio C HamanoMay 30, 2025
  31. Ben KnobleMay 30, 2025
  32. Aditya GargMay 30, 2025
  33. 4/4 docs: make the purpose of using app password for Gmail more clear in send-emailAditya Garg, May 28, 2025
  34. Junio C HamanoMay 29, 2025
  35. Aditya GargMay 29, 2025
  36. 3/4 docs: remove credential helper links for emails from gitcredentialsAditya Garg, May 28, 2025
  37. Eric SunshineMay 28, 2025
  38. Aditya GargMay 28, 2025
  39. Aditya GargMay 28, 2025
  40. Aditya GargMay 28, 2025
  41. Aditya GargMay 28, 2025
  42. 0/4 docs: update email credential helpers and improve formattingAditya Garg, May 30, 2025
  43. 1/4 docs: add credential helper for yahoo and link Google's sendgmail toolAditya Garg, May 30, 2025
  44. 2/4 docs: improve formatting in git-send-email documentationAditya Garg, May 30, 2025
  45. 3/4 docs: remove credential helper links for emails from gitcredentialsAditya Garg, May 30, 2025
  46. 4/4 docs: make the purpose of using app password for Gmail more clear in send-emailAditya Garg, May 30, 2025
  47. 0/4 docs: add credential helper for yahoo and link Google's sendgmail toolAditya Garg, May 30, 2025
  48. 1/4 docs: add credential helper for yahoo and link Google's sendgmail toolAditya Garg, May 30, 2025
  49. 2/4 docs: improve formatting in git-send-email documentationAditya Garg, May 30, 2025
  50. 3/4 docs: remove credential helper links for emails from gitcredentialsAditya Garg, May 30, 2025
  51. 4/4 docs: make the purpose of using app password for Gmail more clear in send-emailAditya Garg, May 30, 2025
  52. Junio C HamanoMay 30, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.