{"thread":{"id":"63519","subject":"[PATCH RFC] send-mail: add support for Microsoft Graph API","startedAt":"2025-05-25T11:06:39Z","lastAt":"2025-05-26T03:38:19Z","messageCount":5,"participants":["Aditya Garg","brian m. carlson","Drew DeVault"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"518857","messageId":"20250525110621.64308-1-gargaditya08@live.com","threadId":"63519","inReplyTo":null,"subject":"[PATCH RFC] send-mail: add support for Microsoft Graph API","fromName":"Aditya Garg","fromEmail":"gargaditya08@live.com","sentAt":"2025-05-25T11:06:32Z","receivedAt":"2025-05-25T11:06:39Z","isPatch":true,"sender":{"key":"gargaditya08@live.com","avatar":"https://avatars.githubusercontent.com/u/85610623?v=4"},"body":"Apart from SMTP, Microsoft also provides a REST API, branded as\nMicrosoft Graph for sending mails. Upon testing a bit, I have\nfound a few benefits over SMTP. Firstly, SMTP servers of Microsoft\nare kinda slow. On an average, initialising the SMTP server even\non a fast internet connection takes around 8-10 seconds with\nsend-email. Once initialised, subsequent messages sometimes also\nface delays, taking around 3-5 seconds per message, and other\ntimes they are sent almost instantaneously. Secondly, their SMTP\nserver does not respect the Message-ID specified by the user and\nreplaces it with their own generated string.\n\nMicrosoft Graph API solves both these problems. It is extremely\nfast, taking around 1 second to send a series of 5 patches, and\nalso respects the Message-ID specified by the user.\n\nAfter this patch, users can use the graph API by having their\nconfig as:\n\n[sendemail]\n\tuseMSGraph = true\n\tMSGraphUser = yourname@outlook.com\n\nThe API requires an OAuth2.0 access token for authentication, and\nusers can either generate them manually, or use a credential helper\n\n\nTODO:\nI still need to write the documentation for this feature, but I wanted to\nget the code reviewed first.\n\nPS: This patch is sent using MS Graph. Note the fixed Message-ID ;)\n\nSigned-off-by: Aditya Garg <gargaditya08@live.com>\n---\n git-send-email.perl | 71 ++++++++++++++++++++++++++++++++++++++++++---\n 1 file changed, 67 insertions(+), 4 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex b09251c4fc..edb96c7e1a 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -73,7 +73,10 @@ sub usage {\n     --no-smtp-auth                 * Disable SMTP authentication. Shorthand for\n                                      `--smtp-auth=none`\n     --smtp-debug            <0|1>  * Disable, enable Net::SMTP debug.\n-\n+    --[no-]use-msgraph      <str>  * Use Microsoft Graph API instead of SMTP.\n+    --msgraph-user          <str>  * Username in case an email API is used.\n+                                     If not specified, the from address is used.\n+    --msgraph-token         <str>  * OAuth2.0 access token for the email API.\n     --batch-size            <int>  * send max <int> message per connection.\n     --relogin-delay         <int>  * delay <int> seconds between two successive login.\n                                      This option can only be used with --batch-size\n@@ -201,7 +204,7 @@ sub format_2822_time {\n # Variables we fill in automatically, or via prompting:\n my (@to,@cc,@xh,$envelope_sender,\n \t$initial_in_reply_to,$reply_to,$initial_subject,@files,\n-\t$author,$sender,$smtp_authpass,$annotate,$compose,$time);\n+\t$author,$sender,$smtp_authpass,$annotate,$compose,$time,$msgraph_token);\n # Things we either get from config, *or* are overridden on the\n # command-line.\n my ($no_cc, $no_to, $no_bcc, $no_identity, $no_header_cmd);\n@@ -283,6 +286,7 @@ sub do_edit {\n my ($compose_encoding);\n my ($sendmail_cmd);\n my ($mailmap_file, $mailmap_blob);\n+my ($msgraph_user);\n # Variables with corresponding config settings & hardcoded defaults\n my ($debug_net_smtp) = 0;\t\t# Net::SMTP, see send_message()\n my $thread = 1;\n@@ -293,6 +297,7 @@ sub do_edit {\n my $target_xfer_encoding = 'auto';\n my $forbid_sendmail_variables = 1;\n my $outlook_id_fix = 'auto';\n+my $use_msgraph = 0;\n \n my %config_bool_settings = (\n     \"thread\" => \\$thread,\n@@ -309,6 +314,7 @@ sub do_edit {\n     \"forbidsendmailvariables\" => \\$forbid_sendmail_variables,\n     \"mailmap\" => \\$mailmap,\n     \"outlookidfix\" => \\$outlook_id_fix,\n+    \"usemsgraph\" => \\$use_msgraph,\n );\n \n my %config_settings = (\n@@ -337,6 +343,8 @@ sub do_edit {\n     \"composeencoding\" => \\$compose_encoding,\n     \"transferencoding\" => \\$target_xfer_encoding,\n     \"sendmailcmd\" => \\$sendmail_cmd,\n+    \"msgraphuser\" => \\$msgraph_user,\n+    \"msgraphtoken\" => \\$msgraph_token,\n );\n \n my %config_path_settings = (\n@@ -556,6 +564,9 @@ sub config_regexp {\n \t\t    \"git-completion-helper\" => \\$git_completion_helper,\n \t\t    \"v=s\" => \\$reroll_count,\n \t\t    \"outlook-id-fix!\" => \\$outlook_id_fix,\n+\t\t    \"use-msgraph!\" => \\$use_msgraph,\n+\t\t    \"msgraph-user=s\" => \\$msgraph_user,\n+\t\t    \"msgraph-token:s\" => \\$msgraph_token,\n );\n $rc = GetOptions(%options);\n \n@@ -1095,7 +1106,7 @@ sub expand_one_alias {\n \t$reply_to = sanitize_address($reply_to);\n }\n \n-if (!defined $sendmail_cmd && !defined $smtp_server) {\n+if (!defined $sendmail_cmd && !defined $smtp_server && !$use_msgraph) {\n \tmy @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );\n \tpush @sendmail_paths, map {\"$_/sendmail\"} split /:/, $ENV{PATH};\n \tforeach (@sendmail_paths) {\n@@ -1603,6 +1614,7 @@ sub is_outlook {\n sub send_message {\n \tmy ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();\n \tmy @recipients = @$recipients_ref;\n+\tmy $msgraph_response_code;\n \n \tmy @sendmail_parameters = ('-i', @recipients);\n \tmy $raw_from = $sender;\n@@ -1680,6 +1692,52 @@ sub send_message {\n \t\t}\n \t\tprint $sm \"$header\\n$message\";\n \t\tclose $sm or die $!;\n+\t} elsif ($use_msgraph) {\n+\t\t# Use Microsoft Graph API\n+\t\t# https://learn.microsoft.com/en-us/graph/api/user-sendmail\n+\t\tmy $auth_api;\n+\t\tif (!defined $msgraph_user) {\n+\t\t\t$msgraph_user = (defined $smtp_authuser\n+\t\t\t\t? $smtp_authuser\n+\t\t\t\t: $raw_from\n+\t\t\t);\n+\t\t}\n+\t\trequire MIME::Base64;\n+\t\trequire HTTP::Tiny;\n+\t\t$auth_api = Git::credential({\n+\t\t\t'protocol' => 'https',\n+\t\t\t'host' => 'graph.microsoft.com',\n+\t\t\t'username' => $msgraph_user,\n+\t\t\t'password' => $msgraph_token,\n+\t\t}, sub {\n+\t\t\tmy $cred = shift;\n+\t\t\t$msgraph_token = $cred->{'password'};\n+\t\t});\n+\t\tmy $email_url = \"https://graph.microsoft.com/v1.0/users/$msgraph_user/sendMail\";\n+\t\tmy $real_message = \"$header\\n$message\\n\";\n+\t\t# Convert LF to CRLF\n+\t\tunless ($real_message =~ /\\r\\n/) {\n+\t\t\t$real_message =~ s/\\r?\\n/\\r\\n/g;\n+\t\t}\n+\t\t# The API requires the message to be base64 encoded if sending in MIME format.\n+\t\tmy $encoded_message = MIME::Base64::encode_base64($real_message, \"\");\n+\t\tmy $http = HTTP::Tiny->new(\n+\t\t\tdefault_headers => {\n+\t\t\t\t'Authorization' => \"Bearer $msgraph_token\",\n+\t\t\t\t'Content-Type'  => 'text/plain',\n+\t\t\t},\n+\t\t);\n+\t\tmy $response = $http->post($email_url, {\n+\t\t\tcontent => $encoded_message,\n+\t\t});\n+\n+\n+\t\tif (!$response->{success}) {\n+\t\t\tdie sprintf(__(\"Failed to send email: %s\\nResponse: %s\"),\n+\t\t\t\t$response->{status}, $response->{content});\n+\t\t} else {\n+\t\t\t$msgraph_response_code = $response->{status};\n+\t\t}\n \t} else {\n \n \t\tif (!defined $smtp_server) {\n@@ -1790,12 +1848,15 @@ sub send_message {\n \t} else {\n \t\tprint($dry_run ? __(\"Dry-OK. Log says:\") : __(\"OK. Log says:\"));\n \t\tprint \"\\n\";\n-\t\tif (!defined $sendmail_cmd && !file_name_is_absolute($smtp_server)) {\n+\t\tif (!defined $sendmail_cmd && !file_name_is_absolute($smtp_server)\n+\t\t   && !$use_msgraph) {\n \t\t\tprint \"Server: $smtp_server\\n\";\n \t\t\tprint \"MAIL FROM:<$raw_from>\\n\";\n \t\t\tforeach my $entry (@recipients) {\n \t\t\t    print \"RCPT TO:<$entry>\\n\";\n \t\t\t}\n+\t\t} elsif ($use_msgraph) {\n+\t\t\tprint \"Email API: Microsoft Graph API\\n\";\n \t\t} else {\n \t\t\tmy $sm;\n \t\t\tif (defined $sendmail_cmd) {\n@@ -1810,6 +1871,8 @@ sub send_message {\n \t\tif ($smtp) {\n \t\t\tprint __(\"Result: \"), $smtp->code, ' ',\n \t\t\t\t($smtp->message =~ /\\n([^\\n]+\\n)$/s);\n+\t\t} elsif (defined $msgraph_response_code) {\n+\t\t\tprint __(\"Result: \"), $msgraph_response_code;\n \t\t} else {\n \t\t\tprint __(\"Result: OK\");\n \t\t}\n-- \n2.49.0\n\n\n"},{"id":"518858","messageId":"PN3PR01MB95974D6A19D6C53776BE4BAEB89AA@PN3PR01MB9597.INDPRD01.PROD.OUTLOOK.COM","threadId":"63519","inReplyTo":"20250525110621.64308-1-gargaditya08@live.com","subject":"Re: [PATCH RFC] send-mail: add support for Microsoft Graph API","fromName":"Aditya Garg","fromEmail":"gargaditya08@live.com","sentAt":"2025-05-25T11:22:39Z","receivedAt":"2025-05-25T11:22:48Z","isPatch":true,"sender":{"key":"gargaditya08@live.com","avatar":"https://avatars.githubusercontent.com/u/85610623?v=4"},"body":"\n\nOn 25/05/25 4:34 pm, Aditya Garg wrote:\n> Apart from SMTP, Microsoft also provides a REST API, branded as\n> Microsoft Graph for sending mails. Upon testing a bit, I have\n> found a few benefits over SMTP. Firstly, SMTP servers of Microsoft\n> are kinda slow. On an average, initialising the SMTP server even\n> on a fast internet connection takes around 8-10 seconds with\n> send-email. Once initialised, subsequent messages sometimes also\n> face delays, taking around 3-5 seconds per message, and other\n> times they are sent almost instantaneously. Secondly, their SMTP\n> server does not respect the Message-ID specified by the user and\n> replaces it with their own generated string.\n> \n> Microsoft Graph API solves both these problems. It is extremely\n> fast, taking around 1 second to send a series of 5 patches, and\n> also respects the Message-ID specified by the user.\n> \n> After this patch, users can use the graph API by having their\n> config as:\n> \n> [sendemail]\n> \tuseMSGraph = true\n> \tMSGraphUser = yourname@outlook.com\n> \n> The API requires an OAuth2.0 access token for authentication, and\n> users can either generate them manually, or use a credential helper\n\nAlso, if someone is interested in testing, you can use a small credentialhelper for msgraph here:\n\nhttps://github.com/AdityaGarg8/git-credential-email/tree/msgraph\n"},{"id":"518881","messageId":"aDN8mYEJS0ARD1d7@tapette.crustytoothpaste.net","threadId":"63519","inReplyTo":"20250525110621.64308-1-gargaditya08@live.com","subject":"Re: [PATCH RFC] send-mail: add support for Microsoft Graph API","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2025-05-25T20:24:57Z","receivedAt":"2025-05-25T20:25:07Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2025-05-25 at 11:06:32, Aditya Garg wrote:\n> Apart from SMTP, Microsoft also provides a REST API, branded as\n> Microsoft Graph for sending mails. Upon testing a bit, I have\n> found a few benefits over SMTP. Firstly, SMTP servers of Microsoft\n> are kinda slow. On an average, initialising the SMTP server even\n> on a fast internet connection takes around 8-10 seconds with\n> send-email. Once initialised, subsequent messages sometimes also\n> face delays, taking around 3-5 seconds per message, and other\n> times they are sent almost instantaneously. Secondly, their SMTP\n> server does not respect the Message-ID specified by the user and\n> replaces it with their own generated string.\n> \n> Microsoft Graph API solves both these problems. It is extremely\n> fast, taking around 1 second to send a series of 5 patches, and\n> also respects the Message-ID specified by the user.\n\nI don't think we should be adding support for proprietary methods of\nsending mail.  There are two standard methods, which are SMTP and the\nsendmail binary, that are well known, well understood, and widely\ndeployed.\n\nIt is well known that Microsoft has invented a lot of proprietary\nOutlook-specific formats for messages, such as TNEF and MAPI, which we\nshould also not support because they are poorly defined and not\nspecified in an open standard.  I would also be opposed to sending mail\nin formats or using methods that are proprietary to Google, Amazon, or\nany other provider, since we already have clear specifications on how\nmail is to be sent that precede this project's existence by some time.\n\nI understand that the Outlook servers may be slow and inefficient as\nwell as modify the Message-ID, but that's ultimately a problem you need\nto address with them and get them to fix.  I should note that I don't\nhave that problem: I run my own Postfix and Dovecot servers which are\nvery speedy, and I feel confident any other provider could do so as\nwell.  I also have never had that problem sending mail through Google's\nSMTP server at work.\n\nIf this REST API approach is well defined by an RFC or some other open\nspecification process that the public can participate in and deployed\namong a large number of providers, including several open source\nimplementations, then we might consider adopting it.\n-- \nbrian m. carlson (they/them)\nToronto, Ontario, CA\n"},{"id":"518898","messageId":"8830BDD2-5664-4F3C-B30F-8CD3A8FE199C.1@mx.sendamatic.net","threadId":"63519","inReplyTo":"aDN8mYEJS0ARD1d7@tapette.crustytoothpaste.net","subject":"Re: [PATCH RFC] send-mail: add support for Microsoft Graph API","fromName":"Drew DeVault","fromEmail":"drew@ddevault.org","sentAt":"2025-05-26T01:36:40Z","receivedAt":"2025-05-26T01:37:53Z","isPatch":true,"sender":{"key":"drew@ddevault.org","avatar":null},"body":"I'm inclined to agree that it would be less than ideal to add\nfirst-class support for proprietary protocols to git send-email. Some\nkind of local SMTP => Graph API bridge is probably a better solution,\nassuming Microsoft won't listen to reason (nor your boss, when you ask\nthem to switch away from Outlook).\n"},{"id":"518899","messageId":"PN3PR01MB959731DDE3E22C88211A84C2B865A@PN3PR01MB9597.INDPRD01.PROD.OUTLOOK.COM","threadId":"63519","inReplyTo":"aDN8mYEJS0ARD1d7@tapette.crustytoothpaste.net","subject":"Re: [PATCH RFC] send-mail: add support for Microsoft Graph API","fromName":"Aditya Garg","fromEmail":"gargaditya08@live.com","sentAt":"2025-05-26T03:38:13Z","receivedAt":"2025-05-26T03:38:19Z","isPatch":true,"sender":{"key":"gargaditya08@live.com","avatar":"https://avatars.githubusercontent.com/u/85610623?v=4"},"body":"\n\n> On 26 May 2025, at 1:55 AM, brian m. carlson <sandals@crustytoothpaste.net> wrote:\n> \n> ﻿On 2025-05-25 at 11:06:32, Aditya Garg wrote:\n>> Apart from SMTP, Microsoft also provides a REST API, branded as\n>> Microsoft Graph for sending mails. Upon testing a bit, I have\n>> found a few benefits over SMTP. Firstly, SMTP servers of Microsoft\n>> are kinda slow. On an average, initialising the SMTP server even\n>> on a fast internet connection takes around 8-10 seconds with\n>> send-email. Once initialised, subsequent messages sometimes also\n>> face delays, taking around 3-5 seconds per message, and other\n>> times they are sent almost instantaneously. Secondly, their SMTP\n>> server does not respect the Message-ID specified by the user and\n>> replaces it with their own generated string.\n>> \n>> Microsoft Graph API solves both these problems. It is extremely\n>> fast, taking around 1 second to send a series of 5 patches, and\n>> also respects the Message-ID specified by the user.\n> \n> I don't think we should be adding support for proprietary methods of\n> sending mail.  There are two standard methods, which are SMTP and the\n> sendmail binary, that are well known, well understood, and widely\n> deployed.\n> \n> It is well known that Microsoft has invented a lot of proprietary\n> Outlook-specific formats for messages, such as TNEF and MAPI, which we\n> should also not support because they are poorly defined and not\n> specified in an open standard.  I would also be opposed to sending mail\n> in formats or using methods that are proprietary to Google, Amazon, or\n> any other provider, since we already have clear specifications on how\n> mail is to be sent that precede this project's existence by some time.\n> \n> I understand that the Outlook servers may be slow and inefficient as\n> well as modify the Message-ID, but that's ultimately a problem you need\n> to address with them and get them to fix.  I should note that I don't\n> have that problem: I run my own Postfix and Dovecot servers which are\n> very speedy, and I feel confident any other provider could do so as\n> well.  I also have never had that problem sending mail through Google's\n> SMTP server at work.\n> \n> If this REST API approach is well defined by an RFC or some other open\n> specification process that the public can participate in and deployed\n> among a large number of providers, including several open source\n> implementations, then we might consider adopting it.\n\nFair, I was thinking proprietary protocols might not be accepted upstream.\nI think its best to use an SMTP bridge, or use the sendmail-cmd like\ncapabilities of send-email."}]}