{"thread":{"id":"63325","subject":"[PATCH 0/2] Ad support for Oauth2 and fix message-id bug in outlook","startedAt":"2025-04-22T07:19:14Z","lastAt":"2025-04-22T07:19:16Z","messageCount":3,"participants":["Aditya Garg via GitGitGadget","Julian Swagemakers via GitGitGadget"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"516464","messageId":"pull.1949.git.git.1745306351.gitgitgadget@gmail.com","threadId":"63325","inReplyTo":null,"subject":"[PATCH 0/2] Ad support for Oauth2 and fix message-id bug in outlook","fromName":"Aditya Garg via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-22T07:19:08Z","receivedAt":"2025-04-22T07:19:14Z","isPatch":true,"sender":{"key":"gargaditya08@live.com","avatar":"https://avatars.githubusercontent.com/u/85610623?v=4"},"body":"This pull request introduces 2 changes:\n\n 1. It adds support for Oauth2 authentication, which is now compulsory my\n    Microsoft. This patch has been rebased to the latest version from the\n    original version at\n    https://lore.kernel.org/git/20250125190131.48717-1-julian@swagemakers.org/\n\n 2. The second patch makes the script reply to the message id set by the\n    outlook, since outlook has its own proprietary way to handle message\n    ids, and does not allow user to set their own. As a result, threads were\n    breaking.\n\nAditya Garg (1):\n  send-email: retrieve Message-ID from outlook SMTP server\n\nJulian Swagemakers (1):\n  send-email: implement SMTP bearer authentication\n\n Documentation/git-send-email.adoc |  5 ++-\n git-send-email.perl               | 75 ++++++++++++++++++++++++++++++-\n 2 files changed, 78 insertions(+), 2 deletions(-)\n\n\nbase-commit: 4bbb303af69990ccd05fe3a2eb58a1ce036f8220\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1949%2FAdityaGarg8%2Fmaster-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1949/AdityaGarg8/master-v1\nPull-Request: https://github.com/git/git/pull/1949\n-- \ngitgitgadget\n"},{"id":"516465","messageId":"3165055f209c50372dcf6829f04e05378e100d02.1745306351.git.gitgitgadget@gmail.com","threadId":"63325","inReplyTo":"pull.1949.git.git.1745306351.gitgitgadget@gmail.com","subject":"[PATCH 1/2] send-email: implement SMTP bearer authentication","fromName":"Julian Swagemakers via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-22T07:19:09Z","receivedAt":"2025-04-22T07:19:15Z","isPatch":true,"sender":{"key":"julian@swagemakers.org","avatar":"https://gravatar.com/avatar/61b8010bc77390da6713f1622e3276430152d11cd512c11c1c241716991a358b?d=mp&s=160"},"body":"From: Julian Swagemakers <julian@swagemakers.org>\n\nManually send SMTP AUTH command for auth type OAUTHBEARER and XOAUTH2.\nThis is necessary since they are currently not supported by the Perls\nAuthen::SASL module.\n\nThe bearer token needs to be passed in as the password. This can be done\nwith git-credential-oauth[0] after minor modifications[1]. Which will\nallow using git send-email with Gmail and oauth2 authentication:\n\n    [credential]\n        helper = cache --timeout 7200    # two hours\n        helper = oauth\n    [sendemail]\n        smtpEncryption = tls\n        smtpServer = smtp.gmail.com\n        smtpUser = example@gmail.com\n        smtpServerPort = 587\n        smtpauth = OAUTHBEARER\n\nAs well as Office 365 accounts:\n\n    [credential]\n        helper = cache --timeout 7200   # two hours\n        helper = oauth\n    [sendemail]\n        smtpEncryption = tls\n        smtpServer = smtp.office365.com\n        smtpUser = example@example.com\n        smtpServerPort = 587\n        smtpauth = XOAUTH2\n\n[0] https://github.com/hickford/git-credential-oauth\n[1] https://github.com/hickford/git-credential-oauth/issues/48\n\nTested-by: M Hickford <mirth.hickford@gmail.com>\nSigned-off-by: Julian Swagemakers <julian@swagemakers.org>\nSigned-off-by: Aditya Garg <gargaditya08@live.com>\n---\n Documentation/git-send-email.adoc |  5 ++-\n git-send-email.perl               | 64 ++++++++++++++++++++++++++++++-\n 2 files changed, 67 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-send-email.adoc b/Documentation/git-send-email.adoc\nindex 7f223db42dd..1bf75c060d3 100644\n--- a/Documentation/git-send-email.adoc\n+++ b/Documentation/git-send-email.adoc\n@@ -213,7 +213,10 @@ SMTP server and if it is supported by the utilized SASL library, the mechanism\n is used for authentication. If neither 'sendemail.smtpAuth' nor `--smtp-auth`\n is specified, all mechanisms supported by the SASL library can be used. The\n special value 'none' maybe specified to completely disable authentication\n-independently of `--smtp-user`\n+independently of `--smtp-user`. Specifying `OAUTHBEARER` or `XOAUTH2` will\n+bypass SASL negotiation and force bearer authentication. In this case the\n+bearer token must be provided with `--smtp-pass` or using a credential helper\n+and `--smtp-encryption=tls` must be set.\n \n --smtp-pass[=<password>]::\n \tPassword for SMTP-AUTH. The argument is optional: If no\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 1f613fa979d..aa6aad596f2 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -1398,6 +1398,63 @@ sub smtp_host_string {\n \t}\n }\n \n+sub generate_oauthbearer_string {\n+\t# This will generate the oauthbearer string used for authentication.\n+\t#\n+\t# \"n,a=\" {User} \",^Ahost=\" {Host} \"^Aport=\" {Port} \"^Aauth=Bearer \" {Access Token} \"^A^A\n+\t#\n+\t# The first part `n,a=\" {User} \",` is the gs2 header described in RFC5801.\n+\t# * gs2-cb-flag `n` -> client does not support CB\n+\t# * gs2-authzid `a=\" {User} \"`\n+\t#\n+\t# The second part are key value pairs containing host, port and auth as\n+\t# described in RFC7628.\n+\t#\n+\t# https://datatracker.ietf.org/doc/html/rfc5801\n+\t# https://datatracker.ietf.org/doc/html/rfc7628\n+\tmy $username = shift;\n+\tmy $token = shift;\n+\treturn \"n,a=$username,\\001port=$smtp_server_port\\001auth=Bearer $token\\001\\001\";\n+}\n+\n+sub generate_xoauth2_string {\n+\t# \"user=\" {User} \"^Aauth=Bearer \" {Access Token} \"^A^A\"\n+\t# https://developers.google.com/gmail/imap/xoauth2-protocol#initial_client_response\n+\tmy $username = shift;\n+\tmy $token = shift;\n+\treturn \"user=$username\\001auth=Bearer $token\\001\\001\";\n+}\n+\n+sub smtp_bearer_auth {\n+\tmy $username = shift;\n+\tmy $token = shift;\n+\tmy $auth_string;\n+\tif ($smtp_encryption ne \"tls\") {\n+\t\t# As described in RFC7628 TLS is required and will be enforced\n+\t\t# at this point.\n+\t\t#\n+\t\t# https://datatracker.ietf.org/doc/html/rfc7628#section-3\n+\t\tdie __(\"For $smtp_auth TLS is required.\")\n+\t}\n+\tif ($smtp_auth eq \"OAUTHBEARER\") {\n+\t\t$auth_string = generate_oauthbearer_string($username, $token);\n+\t} elsif ($smtp_auth eq \"XOAUTH2\") {\n+\t\t$auth_string = generate_xoauth2_string($username, $token);\n+\t}\n+\tmy $encoded_auth_string = MIME::Base64::encode($auth_string, \"\");\n+\t$smtp->command(\"AUTH $smtp_auth $encoded_auth_string\\r\\n\");\n+\tuse Net::Cmd qw(CMD_OK);\n+\tif ($smtp->response() == CMD_OK){\n+\t\treturn 1;\n+\t} else {\n+\t\t# Send dummy request on authentication failure according to rfc7628.\n+\t\t# https://datatracker.ietf.org/doc/html/rfc7628#section-3.2.3\n+\t\t$smtp->command(MIME::Base64::encode(\"\\001\"));\n+\t\t$smtp->response();\n+\t\treturn 0;\n+\t}\n+}\n+\n # Returns 1 if authentication succeeded or was not necessary\n # (smtp_user was not specified), and 0 otherwise.\n \n@@ -1436,7 +1493,12 @@ sub smtp_auth_maybe {\n \n \t\t# catch all SMTP auth error in a unified eval block\n \t\teval {\n-\t\t\tif ($smtp_auth) {\n+\t\t\tif (defined $smtp_auth && ($smtp_auth eq \"OAUTHBEARER\" || $smtp_auth eq \"XOAUTH2\")) {\n+\t\t\t\t# Since Authen:SASL does not support XOAUTH2 nor OAUTHBEARER we will\n+\t\t\t\t# manually authenticate for these types. The password field should\n+\t\t\t\t# contain the auth token at this point.\n+\t\t\t\t$result = smtp_bearer_auth($cred->{'username'}, $cred->{'password'});\n+\t\t\t} elsif ($smtp_auth) {\n \t\t\t\tmy $sasl = Authen::SASL->new(\n \t\t\t\t\tmechanism => $smtp_auth,\n \t\t\t\t\tcallback => {\n-- \ngitgitgadget\n\n"},{"id":"516466","messageId":"00e1be73ab91db1c37447544ebcdc4f33432dbcb.1745306351.git.gitgitgadget@gmail.com","threadId":"63325","inReplyTo":"pull.1949.git.git.1745306351.gitgitgadget@gmail.com","subject":"[PATCH 2/2] send-email: retrieve Message-ID from outlook SMTP server","fromName":"Aditya Garg via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-22T07:19:10Z","receivedAt":"2025-04-22T07:19:16Z","isPatch":true,"sender":{"key":"gargaditya08@live.com","avatar":"https://avatars.githubusercontent.com/u/85610623?v=4"},"body":"From: Aditya Garg <gargaditya08@live.com>\n\nOutlook does not accept the Message-ID header in the email body. Instead\nit saves it in its own proprietary X-Microsoft-Original-Message-ID\nheader and a random Message-ID is set my the server. As a result,\nreplying to threads does not work.\n\nThe $smtp->message variable in this script for outlook is something like\nthis:\n\n2.0.0 OK <Message-ID> [Hostname=Some-hostname]\n\nThis contains the Message-ID set by Microsoft in the first <>.\n\nThis patch retrieves the Message-ID from this server response\nand sets it in the email headers instead of using the self generated one.\n\nSigned-off-by: Aditya Garg <gargaditya08@live.com>\n---\n git-send-email.perl | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex aa6aad596f2..f2a926872de 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -1799,6 +1799,17 @@ EOF\n \t\t\t$smtp->datasend(\"$line\") or die $smtp->message;\n \t\t}\n \t\t$smtp->dataend() or die $smtp->message;\n+\n+\t\t# Retrieve the Message-ID from the server response in case of Outlook\n+\t\tif ($smtp_server eq 'smtp.office365.com' || $smtp_server eq 'smtp-mail.outlook.com') {\n+\t\t\tif ($smtp->message =~ /<([^>]+)>/) {\n+\t\t\t\t$message_id = \"<$1>\";\n+\t\t\t\tprint __(\"Outlook: Retrieved Message-ID: $message_id\\n\");\n+\t\t\t} else {\n+\t\t\t\twarn __(\"Warning: Could not retrieve Message-ID from server response.\\n\");\n+\t\t\t}\n+\t\t}\n+\n \t\t$smtp->code =~ /250|200/ or die sprintf(__(\"Failed to send %s\\n\"), $subject).$smtp->message;\n \t}\n \tif ($quiet) {\n-- \ngitgitgadget\n"}]}