[PATCH v3 3/3] send-email: add option to generate passswords like OAuth2 tokens

Aditya Garg
2025-04-22T15:26:42Z

Some email providers like outlook allow only OAuth2 tokens to be used
for authentication. This commit adds an option to generate OAuth2 tokens
using scripts like M365-IMAP[1]. This option is similar to passwordeval
in msmtp.

Example usage:

[sendemail]
smtpEncryption = tls
smtpServer = smtp.office365.com
smtpUser = someone@outlook.com
smtpServerPort = 587
smtpauth = XOAUTH2
smtpPassEval = cd /workspaces/codespaces-blank/M365-IMAP && python3 ./refresh_token.py

Signed-off-by: Aditya Garg <gargaditya08@live.com>
---
Documentation/git-send-email.adoc | 8 ++++++++
git-send-email.perl | 15 +++++++++++++++
2 files changed, 23 insertions(+)

diff --git a/Documentation/git-send-email.adoc b/Documentation/git-send-email.adoc
index 1bf75c060d..b41c807960 100644
--- a/Documentation/git-send-email.adoc
+++ b/Documentation/git-send-email.adoc
@@ -230,6 +230,14 @@ or on the command line. If a username has been specified (with
specified (with `--smtp-pass` or `sendemail.smtpPass`), then
a password is obtained using 'git-credential'.

+--smtp-passeval[=<command>]::
+ Generate password or OAuth2 token for SMTP AUTH. The argument is
+ optional. If specified, it will use the output of any password
+ or OAuth2 token generated using the command specified.
++
+Note that it will override any existing password specified using
+`--smtp-user` or a `sendemail.smtpUser`.
+
--no-smtp-auth::
Disable SMTP authentication. Short hand for `--smtp-auth=none`

diff --git a/git-send-email.perl b/git-send-email.perl
index 216b23caa5..49de6a048e 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -59,6 +59,8 @@ sub usage {
--smtp-server-port <int> * Outgoing SMTP server port.
--smtp-user <str> * Username for SMTP-AUTH.
--smtp-pass <str> * Password for SMTP-AUTH; not necessary.
+ --smtp-passeval <str> * Path to script or a command to generate
+ password like OAuth2 token for SMTP-AUTH.
--smtp-encryption <str> * tls or ssl; anything else disables.
--smtp-ssl * Deprecated. Use '--smtp-encryption ssl'.
--smtp-ssl-cert-path <str> * Path to ca-certificates (either directory or file).
@@ -280,6 +282,7 @@ sub do_edit {
my ($auto_8bit_encoding);
my ($compose_encoding);
my ($sendmail_cmd);
+my ($smtp_authpasseval);
my ($mailmap_file, $mailmap_blob);
# Variables with corresponding config settings & hardcoded defaults
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
@@ -316,6 +319,7 @@ sub do_edit {
"smtppass" => \$smtp_authpass,
"smtpdomain" => \$smtp_domain,
"smtpauth" => \$smtp_auth,
+ "smtppasseval" => \$smtp_authpasseval,
"smtpbatchsize" => \$batch_size,
"smtprelogindelay" => \$relogin_delay,
"to" => \@config_to,
@@ -516,6 +520,7 @@ sub config_regexp {
"smtp-server-port=s" => \$smtp_server_port,
"smtp-user=s" => \$smtp_authuser,
"smtp-pass:s" => \$smtp_authpass,
+ "smtp-passeval=s" => \$smtp_authpasseval,
"smtp-ssl" => sub { $smtp_encryption = 'ssl' },
"smtp-encryption=s" => \$smtp_encryption,
"smtp-ssl-cert-path=s" => \$smtp_ssl_cert_path,
@@ -1463,6 +1468,16 @@ sub smtp_auth_maybe {
return 1;
}

+ # If smtpPassEval is set, run the user specified command to get the password
+ if (defined $smtp_authpasseval) {
+ printf __("Executing smtpPassEval: %s\n"), $smtp_authpasseval;
+ chomp(my $generated_password = `$smtp_authpasseval 2>&1`);
+ if ($? != 0) {
+ die sprintf(__("Failed to execute smtpPassEval: %s\n"), $smtp_authpasseval);
+ }
+ $smtp_authpass = $generated_password;
+ }
+
# Workaround AUTH PLAIN/LOGIN interaction defect
# with Authen::SASL::Cyrus
eval {
--
2.49.0