Subject: Re: [PATCH v4 2/3] send-email: retrieve Message-ID from outlook SMTP server

From: Junio C Hamano <[email-masked]>
Date: Wed, 23 Apr 2025 11:54:33 -0700

Aditya Garg <[email-masked]> writes:

> The script generates a Message-ID alongwith the other headers when
> gen_header is called, and is sent alongwith the email. For most email
> providers, including gmail, the Message-ID goes unchanged to the
> recipient.
>
> But, this does not seem to be a case with Outlook. In Outlook, when we
> send our own Message-ID as a part of the headers, it discards it. Rather
> it generates a new random Message-ID and that is was the recipient gets.

"Rather" -> "Then".
"that is was the" -> "that is what the".

probably.

> The Message-ID we specified get stored as a part of Outlook's
> proprietary X-Microsoft-Original-Message-ID header.

For our purpose, X-MS-Original stuff is an extra noise that can be
omitted, as there is no way we or recipients can make good use of
the value on that field.

> This is a problem because the Message-ID is crucial when we are sending
> multiple emails in a thread. The current implementation for threads in
> the script replies to the Message-ID it generated, but due to Outlook's
> behavior, it is not the same as the one that the recipient got, thus
> breaking threads. So a need arises to retrieve the Message-ID from the
> server response and set it in the In-Reply-To and References email
> headers instead of using the self generated one for the purpose of
> replies.
>
> The $smtp->message variable in this script for outlook is something like
> this:
>
> 2.0.0 OK <Message-ID> [Hostname=Some-hostname]
>
> The Message-ID here is the one the receipient gets, rather than the one
> the script generated.
>
> This patch uses the fact above and retrieves the Message-ID from the
> server response. It then changes the value of the $message_id variable
> to the one received from the server. This value will be used when next
> and subsequent messages are sent as replies to the message, thus
> preserving the threading of the messages.
>
> Signed-off-by: Aditya Garg <[email-masked]>
> ---

Thanks for a thorough description.  It reads very well.

>  git-send-email.perl | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
>
> diff --git a/git-send-email.perl b/git-send-email.perl
> index a6cafda29c..a18e978e22 100755
> --- a/git-send-email.perl
> +++ b/git-send-email.perl
> @@ -1636,6 +1636,11 @@ sub gen_header {
>  	return ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header);
>  }
>  
> +sub is_outlook {
> +	my ($host) = @_;
> +	return ($host eq 'smtp.office365.com' || $host eq 'smtp-mail.outlook.com');
> +}
> +
>  # Prepares the email, then asks the user what to do.
>  #
>  # If the user chooses to send the email, it's sent and 1 is returned.
> @@ -1799,6 +1804,21 @@ sub send_message {
>  			$smtp->datasend("$line") or die $smtp->message;
>  		}
>  		$smtp->dataend() or die $smtp->message;
> +
> +		# Outlook discards the Message-ID header we set while sending the email.
> +		# It instead saves it in its proprietary X-Microsoft-Original-Message-ID
> +		# header and assigns a new random Message-ID to the email. So in order to

Again, "It instead ... header and" is probably better left unsaid.

> +		# avoid breaking threads, we simply retrieve the Message-ID from the server
> +		# response and assign it to $message_id.

Perhaps add ", which will then be assigned to $in_reply_to by the
caller when the next message is sent as a response to this message"
at the end?

Other than that, looks superb.  Thanks.

> +		if (is_outlook($smtp_server)) {
> +			if ($smtp->message =~ /<([^>]+)>/) {
> +				$message_id = "<$1>";
> +				printf __("Outlook reassigned Message-ID to: %s\n"), $message_id;
> +			} else {
> +				warn __("Warning: Could not retrieve Message-ID from server response.\n");
> +			}
> +		}
> +
>  		$smtp->code =~ /250|200/ or die sprintf(__("Failed to send %s\n"), $subject).$smtp->message;
>  	}
>  	if ($quiet) {