Git Mailing List Archive mirror
 help / color / mirror / Atom feed
* [GSoC PATCH v3 0/1] Refactor SMTP Auth Error Handling
@ 2025-03-12  6:46 Zheng Yuting
  2025-03-12  6:46 ` [GSoC PATCH v3 1/1] Unify SMTP auth error handling Zheng Yuting
  0 siblings, 1 reply; 27+ messages in thread
From: Zheng Yuting @ 2025-03-12  6:46 UTC (permalink / raw)
  To: git; +Cc: Zheng Yuting

This patch unifies error capture for both SASL and plain SMTP authentication.
It replaces regex-based error detection with SMTP status code parsing,
differentiating transient (retryable) errors from permanent failures.


Zheng Yuting (1):
  SMTP Auth: Use status codes to differentiate transient vs. permanent
    errors

 git-send-email.perl | 72 +++++++++++++++++++++++++++------------------
 1 file changed, 43 insertions(+), 29 deletions(-)

--
2.49.0.rc0.57.gdb91954e18

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v3 1/1] Unify SMTP auth error handling
  2025-03-12  6:46 [GSoC PATCH v3 0/1] Refactor SMTP Auth Error Handling Zheng Yuting
@ 2025-03-12  6:46 ` Zheng Yuting
  2025-03-13 19:58   ` Junio C Hamano
  0 siblings, 1 reply; 27+ messages in thread
From: Zheng Yuting @ 2025-03-12  6:46 UTC (permalink / raw)
  To: git; +Cc: Zheng Yuting

Refactored SMTP authentication to use a unified error capture block for
both SASL and plain methods. Errors are now handled by parsing SMTP status
codes (4yz for transient, 5yz for permanent) instead of relying on regex
matching. This change improves clarity .


Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 72 +++++++++++++++++++++++++++------------------
 1 file changed, 43 insertions(+), 29 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index a012d61abb..532dda264c 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1411,7 +1411,7 @@ sub smtp_auth_maybe {
 	eval {
 		require Authen::SASL;
 		Authen::SASL->import(qw(Perl));
-	};
+	}

 	# Check mechanism naming as defined in:
 	# https://tools.ietf.org/html/rfc4422#page-8
@@ -1426,42 +1426,56 @@ sub smtp_auth_maybe {
 		'protocol' => 'smtp',
 		'host' => smtp_host_string(),
 		'username' => $smtp_authuser,
+		# if there's no password, "git credential fill" will
+		# give us one, otherwise it'll just pass this one.
 		'password' => $smtp_authpass
-
 	}, sub {
 		my $cred = shift;
 		my $result;
 		my $error;
-		if ($smtp_auth) {
-			my $sasl = Authen::SASL->new(
-				mechanism => $smtp_auth,
-				callback => {
-					user => $cred->{'username'},
-					pass => $cred->{'password'},
-					authname => $cred->{'username'},
-				}
-			);
-			return !!$smtp->auth($sasl);
-		} else {
-			# Handle plain authentication errors
-			eval {
+
+		# catch all SMTP auth error
+		eval {
+			if ($smtp_auth) {
+				my $sasl = Authen::SASL->new(
+					mechanism => $smtp_auth,
+					callback => {
+						user => $cred->{'username'},
+						pass => $cred->{'password'},
+						authname => $cred->{'username'},
+					}
+				);
+				$result = $smtp->auth($sasl);
+			} else {
 				$result = $smtp->auth($cred->{'username'}, $cred->{'password'});
-				1; # Ensure true value is returned
-			} or do {
-				$error = $@ || 'Unknown error';
-			};
-		}
-		# Unified error handling logic
+			}
+			1; # Ensure true value is returned if no exception is thrown.
+		} or do {
+			$error = $@ || 'Unknown error';
+		};
+
+		#check if an error was captured
 		if ($error) {
-			# Match temporary errors
-			if ($error =~ /timeout|temporary|greylist|throttled|quota\s+exceeded|queue|overload|try\s+again|connection\s+lost|network\s+error/i) {
-				warn "SMTP temporary error: $error";
-				return 1;
+			#Parse SMTP status code from error message in:
+			#https://www.rfc-editor.org/rfc/rfc5321.html
+			if ($error =~ /\b(\d{3})\b/) {
+				my $status_code = $1;
+				if ($status_code =~ /^4/) {
+					# 4yz: Transient Negative Completion reply
+					warn "SMTP temporary error (status code $status_code): $error";
+					return 1;
+				} elsif ($status_code =~ /^5/) {
+					# 5yz: Permanent Negative Completion reply
+					warn "SMTP permanent error (status code $status_code): $error";
+					return 0;
+				}
+				# If no status code is found, treat as permanent error
+				warn "SMTP unknown error: $error";
+				return 0;
 			}
-			return 0;
-		}
-		return !!$result;
-	});
+			return $result ? 1 : 0;
+		});
+
 	return $auth;
 }

--
2.49.0.rc0.57.gdb91954e18

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [GSoC PATCH v3 1/1] Unify SMTP auth error handling
  2025-03-12  6:46 ` [GSoC PATCH v3 1/1] Unify SMTP auth error handling Zheng Yuting
@ 2025-03-13 19:58   ` Junio C Hamano
  2025-03-14 12:55     ` Yuting Zheng
  2025-03-16  5:09     ` [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization Zheng Yuting
  0 siblings, 2 replies; 27+ messages in thread
From: Junio C Hamano @ 2025-03-13 19:58 UTC (permalink / raw)
  To: Zheng Yuting; +Cc: git

Zheng Yuting <05zyt30@gmail.com> writes:

> Refactored SMTP authentication to use a unified error capture block for
> both SASL and plain methods. Errors are now handled by parsing SMTP status
> codes (4yz for transient, 5yz for permanent) instead of relying on regex
> matching. This change improves clarity .

"improves clarity ." is (not well formatted and) a bit subjective
and does not apply to all three changes the patch is making here,
does it?

> Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
> ---
>  git-send-email.perl | 72 +++++++++++++++++++++++++++------------------
>  1 file changed, 43 insertions(+), 29 deletions(-)
>
> diff --git a/git-send-email.perl b/git-send-email.perl
> index a012d61abb..532dda264c 100755
> --- a/git-send-email.perl
> +++ b/git-send-email.perl
> @@ -1411,7 +1411,7 @@ sub smtp_auth_maybe {
>  	eval {
>  		require Authen::SASL;
>  		Authen::SASL->import(qw(Perl));
> -	};
> +	}

Hmph, the interpreter may tolerate the new block-eval "eval {}"
simple statement that lacks terminating ';' but is this an
improvement?  The original look more kosher from syntactic point of
view.  It seems to be totally unrelated change from the rest of the
patch.

> @@ -1426,42 +1426,56 @@ sub smtp_auth_maybe {
>  		'protocol' => 'smtp',
>  		'host' => smtp_host_string(),
>  		'username' => $smtp_authuser,
> +		# if there's no password, "git credential fill" will
> +		# give us one, otherwise it'll just pass this one.
>  		'password' => $smtp_authpass
> -

We seem to already have the comment added by this hunk, since
4d31a44a (git-send-email: use git credential to obtain password,
2013-02-12).  Am I looking at a wrong version of the source (or a
wrong version of the patch)?

>  	}, sub {
>  		my $cred = shift;
>  		my $result;
>  		my $error;
> -		if ($smtp_auth) {
> -			my $sasl = Authen::SASL->new(
> -				mechanism => $smtp_auth,
> -				callback => {
> -					user => $cred->{'username'},
> -					pass => $cred->{'password'},
> -					authname => $cred->{'username'},
> -				}
> -			);
> -			return !!$smtp->auth($sasl);
> -		} else {
> -			# Handle plain authentication errors
> -			eval {

And curiously we do not seem to have this else clause with the
comment that is getting removed.

> +		# catch all SMTP auth error
> +		eval {
> +			if ($smtp_auth) {
> +				my $sasl = Authen::SASL->new(
> +					mechanism => $smtp_auth,
> +					callback => {
> +						user => $cred->{'username'},
> +						pass => $cred->{'password'},
> +						authname => $cred->{'username'},
> +					}
> +				);
> +				$result = $smtp->auth($sasl);
> +			} else {
>  				$result = $smtp->auth($cred->{'username'}, $cred->{'password'});
> -				1; # Ensure true value is returned
> -			} or do {
> -				$error = $@ || 'Unknown error';
> -			};
> -		}
> -		# Unified error handling logic
> +			}
> +			1; # Ensure true value is returned if no exception is thrown.
> +		} or do {
> +			$error = $@ || 'Unknown error';
> +		};
> +
> +		#check if an error was captured

As I do not see two evals in our copy of git-send-email.perl source,
it may be moot at this point to comment on this patch, but if we did
have a eval block each of the if/else arms, moving the control
structure around and turning "if eval {} else eval {}" into "eval {
if ... else ...}" may make it cleaner to see what is going on,
especially if we plan to extend the choices and add elsif to the
chain later.

>  		if ($error) {
> -			# Match temporary errors
> -			if ($error =~ /timeout|temporary|greylist|throttled|quota\s+exceeded|queue|overload|try\s+again|connection\s+lost|network\s+error/i) {
> -				warn "SMTP temporary error: $error";
> -				return 1;
> +			#Parse SMTP status code from error message in:
> +			#https://www.rfc-editor.org/rfc/rfc5321.html

Have a SP between "#" and the comment body.

Using the numeric error codes allows us to give more precise errors,
which should be a good change that can be done regardless of the
eval change.  IOW, this part should be in a separate patch on its
own, either before or after the if-eval-else-eval change. 

I'll stop here, as the patch does not seem to be designed to apply
to our source tree.


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [GSoC PATCH v3 1/1] Unify SMTP auth error handling
  2025-03-13 19:58   ` Junio C Hamano
@ 2025-03-14 12:55     ` Yuting Zheng
  2025-03-16  5:09     ` [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization Zheng Yuting
  1 sibling, 0 replies; 27+ messages in thread
From: Yuting Zheng @ 2025-03-14 12:55 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Fri Mar 14, 2025 at 3:58 AM CST, Junio C Hamano wrote:

Thank you for the thorough review. As a newcomer, I really appreciate you
taking time to help me improve.

> "improves clarity ." is (not well formatted and) a bit subjective
> and does not apply to all three changes the patch is making here,
> does it?

I'll reformat the commit message and split the patch into more detailed
parts.

> Hmph, the interpreter may tolerate the new block-eval "eval {}"
> simple statement that lacks terminating ';' but is this an
> improvement?  The original look more kosher from syntactic point of
> view.  It seems to be totally unrelated change from the rest of the
> patch.

I'll revert it to the original state.

> We seem to already have the comment added by this hunk, since
> 4d31a44a (git-send-email: use git credential to obtain password,
> 2013-02-12).  Am I looking at a wrong version of the source (or a
> wrong version of the patch)?
>
> And curiously we do not seem to have this else clause with the
> comment that is getting removed.

You're correct - this was caused by my failure to rebase before
submission.I'll clean up all duplicate comments.

> As I do not see two evals in our copy of git-send-email.perl source,
> it may be moot at this point to comment on this patch, but if we did
> have a eval block each of the if/else arms, moving the control
> structure around and turning "if eval {} else eval {}" into "eval {
> if ... else ...}" may make it cleaner to see what is going on,
> especially if we plan to extend the choices and add elsif to the
> chain later.

I'll use if/else structure which is more extensible.

> Have a SP between "#" and the comment body.

Understood. I'll rigorously adhere to code style guidelines by adding
space after comment markers.

> I'll stop here, as the patch does not seem to be designed to apply
> to our source tree.

This was caused by my local branch being several commits behind upstream.
I've now synchronized and will resubmit properly.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization
  2025-03-13 19:58   ` Junio C Hamano
  2025-03-14 12:55     ` Yuting Zheng
@ 2025-03-16  5:09     ` Zheng Yuting
  2025-03-16  5:09       ` [GSoC PATCH v4 1/2] Unify capture of SMTP errors Zheng Yuting
                         ` (3 more replies)
  1 sibling, 4 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-16  5:09 UTC (permalink / raw)
  To: gitster; +Cc: 05zyt30, git, Zheng Yuting

This v4 patch series includes two improvements:

1. Unified error capture:
Consolidate exception handling within a single eval block by introducing
local variables to store results and error states, thereby streamlining
code structure and enabling future extensibility.

2. Status code processing optimization:
After catching the authentication exception, parse the three-digit status
code in the error message, For temporary errors (4yz), only print warnings
and return success, while for permanent errors (5xx), return failure,
Unrecognized status codes are treated as permanent errors by default.

Zheng Yuting (2):
  Unify capture of SMTP errors
  Error handling for SMTP status codes

 git-send-email.perl | 62 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 45 insertions(+), 17 deletions(-)

--
2.48.1

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v4 1/2] Unify capture of SMTP errors
  2025-03-16  5:09     ` [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization Zheng Yuting
@ 2025-03-16  5:09       ` Zheng Yuting
  2025-03-16  5:09       ` [GSoC PATCH v4 2/2] Error handling for SMTP status codes Zheng Yuting
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-16  5:09 UTC (permalink / raw)
  To: gitster; +Cc: 05zyt30, git, Zheng Yuting

This change adds local variables $result and $error to store authentication
return results and exception information respectively.

In the eval block, different auth methods are called depending on whether
the SMTP authentication mechanism is specified, and true is returned when
there is no exception.

After catching the exception, the error information is saved. This makes
the error capture logic more centralized and easier to understand, and
lays the foundation for subsequent expansion.

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 45 ++++++++++++++++++++++++++-------------------
 1 file changed, 26 insertions(+), 19 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 798d59b84f..8feb43e9f7 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1419,7 +1419,7 @@ sub smtp_auth_maybe {
 		die "invalid smtp auth: '${smtp_auth}'";
 	}

-	# TODO: Authentication may fail not because credentials were
+	# Authentication may fail not because credentials were
 	# invalid but due to other reasons, in which we should not
 	# reject credentials.
 	$auth = Git::credential({
@@ -1431,25 +1431,32 @@ sub smtp_auth_maybe {
 		'password' => $smtp_authpass
 	}, sub {
 		my $cred = shift;
+		my $result;
+		my $error;
+
+		# catch all SMTP auth error in a unified eval block
+		eval {
+			if ($smtp_auth) {
+				my $sasl = Authen::SASL->new(
+					mechanism => $smtp_auth,
+					callback => {
+						user     => $cred->{'username'},
+						pass     => $cred->{'password'},
+						authname => $cred->{'username'},
+					}
+				);
+				$result = $smtp->auth($sasl);
+			} else {
+				$result = $smtp->auth($cred->{'username'}, $cred->{'password'});
+			}
+			1; # ensure true value is returned if no exception is thrown
+		} or do {
+			$error = $@ || 'Unknown error';
+		};

-		if ($smtp_auth) {
-			my $sasl = Authen::SASL->new(
-				mechanism => $smtp_auth,
-				callback => {
-					user => $cred->{'username'},
-					pass => $cred->{'password'},
-					authname => $cred->{'username'},
-				}
-			);
-
-			return !!$smtp->auth($sasl);
-		}
-
-		return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
-	});
-
-	return $auth;
-}
+		# NOTE: SMTP status code handling will be added in a subsequent commit
+		return $result ? 1 : 0;
+	}

 sub ssl_verify_params {
 	eval {
--
2.48.1

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [GSoC PATCH v4 2/2] Error handling for SMTP status codes
  2025-03-16  5:09     ` [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization Zheng Yuting
  2025-03-16  5:09       ` [GSoC PATCH v4 1/2] Unify capture of SMTP errors Zheng Yuting
@ 2025-03-16  5:09       ` Zheng Yuting
  2025-03-17 23:01       ` [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization Junio C Hamano
  2025-03-19  2:02       ` [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling Zheng Yuting
  3 siblings, 0 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-16  5:09 UTC (permalink / raw)
  To: gitster; +Cc: 05zyt30, git, Zheng Yuting

This change further parses and processes the captured exception information
based on the previous patch's unified error capture. Specifically, a
three-digit status code is extracted from the error information through a
regular expression, and judged according to the definition of RFC 5321:

- If the status code starts with "4" (temporary error), only a warning is
printed and success (1) is returned to allow subsequent retries;

- If the status code starts with "5" (permanent error), a warning is
printed and failure (0) is returned;

- If the status code is not recognized in the error, it is considered a
permanent error, and an unknown error message is printed and failure is
returned.

In the absence of an error, the authentication result is still returned
according to the original logic. This change makes SMTP authentication
error handling more refined,

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 8feb43e9f7..69ba328653 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1454,9 +1454,30 @@ sub smtp_auth_maybe {
 			$error = $@ || 'Unknown error';
 		};

-		# NOTE: SMTP status code handling will be added in a subsequent commit
-		return $result ? 1 : 0;
-	}
+		# check if an error was captured
+		if ($error) {
+			# parse SMTP status code from error message in:
+			# https://www.rfc-editor.org/rfc/rfc5321.html
+			if ($error =~ /\b(\d{3})\b/) {
+				my $status_code = $1;
+				if ($status_code =~ /^4/) {
+					# 4yz: Transient Negative Completion reply
+					warn "SMTP temporary error (status code $status_code): $error";
+					return 1;
+				} elsif ($status_code =~ /^5/) {
+					# 5yz: Permanent Negative Completion reply
+					warn "SMTP permanent error (status code $status_code): $error";
+					return 0;
+				}
+				# if no recognized status code is found, treat as permanent error
+				warn "SMTP unknown error: $error";
+				return 0;
+			}
+			return $result ? 1 : 0;
+		} else {
+			return $result ? 1 : 0;
+		}
+}

 sub ssl_verify_params {
 	eval {
--
2.48.1

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization
  2025-03-16  5:09     ` [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization Zheng Yuting
  2025-03-16  5:09       ` [GSoC PATCH v4 1/2] Unify capture of SMTP errors Zheng Yuting
  2025-03-16  5:09       ` [GSoC PATCH v4 2/2] Error handling for SMTP status codes Zheng Yuting
@ 2025-03-17 23:01       ` Junio C Hamano
  2025-03-19  2:02       ` [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling Zheng Yuting
  3 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2025-03-17 23:01 UTC (permalink / raw)
  To: Zheng Yuting; +Cc: git

Zheng Yuting <05zyt30@gmail.com> writes:

> This v4 patch series includes two improvements:
>
> 1. Unified error capture:
> Consolidate exception handling within a single eval block by introducing
> local variables to store results and error states, thereby streamlining
> code structure and enabling future extensibility.
>
> 2. Status code processing optimization:
> After catching the authentication exception, parse the three-digit status
> code in the error message, For temporary errors (4yz), only print warnings
> and return success, while for permanent errors (5xx), return failure,
> Unrecognized status codes are treated as permanent errors by default.
>
> Zheng Yuting (2):
>   Unify capture of SMTP errors
>   Error handling for SMTP status codes

Give title your commits following the project convention
(Documentation/SubmittingPatches:summary-section).

I think these two can share "sendemail:" as their "<area>:" part.

	sendemail: capture errors in an eval {} block
	sendemail: finer-grained SMTP error handling

or something like that, perhaps.

For both patches, the usual way to compose a log message of this
project is to

 - Give an observation on how the current system work in the present
   tense (so no need to say "Currently X is Y", just "X is Y"), and
   discuss what you perceive as a problem in it.

 - Propose a solution (optional---often, problem description
   trivially leads to an obvious solution in reader's minds).

 - Give commands to the codebase to "become like so".

in this order.  I got an impression that at least your 1/2 it was
unclear which part was explaining the state before the patch and
which part was about the state after the patch.

Thanks.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling
  2025-03-16  5:09     ` [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization Zheng Yuting
                         ` (2 preceding siblings ...)
  2025-03-17 23:01       ` [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization Junio C Hamano
@ 2025-03-19  2:02       ` Zheng Yuting
  2025-03-19  2:02         ` [GSoC PATCH v5 1/2] sendemail: capture errors in an eval {} block Zheng Yuting
                           ` (3 more replies)
  3 siblings, 4 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-19  2:02 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, Zheng Yuting

This patch series improves SMTP authentication error handling.

Auth relied solely on return values without capturing exceptions,
misjudging non-credential errors as authentication failures.

Patch v5 1/2 wraps the auth process in an eval {} block to catch all
exceptions, adds var error for future handling, and var result to return
auth state.

Patch v5 2/2 introduces finer-grained SMTP error handling, extracting
status codes per RFC 5321 to differentiate between temporary (4yz) and
permanent (5yz) errors. Unrecognized codes are treated as permanent
failures. Otherwise return the authentication result.


Zheng Yuting (2):
  sendemail: capture errors in an eval {} block
  sendemail: finer-grained SMTP error handling

 git-send-email.perl | 62 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 45 insertions(+), 17 deletions(-)

--
2.48.1

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v5 1/2] sendemail: capture errors in an eval {} block
  2025-03-19  2:02       ` [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling Zheng Yuting
@ 2025-03-19  2:02         ` Zheng Yuting
  2025-03-19  2:02         ` [GSoC PATCH v5 2/2] sendemail: finer-grained SMTP error handling Zheng Yuting
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-19  2:02 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, Zheng Yuting

Auth relied solely on return values without catching errors, misjudging
non-credential errors as auth failures without details.

Wrap the entire auth process in an eval {} block to catch all exceptions,
including non-credential errors.

Add $error to store exceptions for future handling and $result for
auth results.

Uses 'or do' to replace direct returns.

Merges if/else branches, integrates SASL and basic auth, with comments
for future status code handling.

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 45 ++++++++++++++++++++++++++-------------------
 1 file changed, 26 insertions(+), 19 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 798d59b84f..8feb43e9f7 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1419,7 +1419,7 @@ sub smtp_auth_maybe {
 		die "invalid smtp auth: '${smtp_auth}'";
 	}

-	# TODO: Authentication may fail not because credentials were
+	# Authentication may fail not because credentials were
 	# invalid but due to other reasons, in which we should not
 	# reject credentials.
 	$auth = Git::credential({
@@ -1431,25 +1431,32 @@ sub smtp_auth_maybe {
 		'password' => $smtp_authpass
 	}, sub {
 		my $cred = shift;
+		my $result;
+		my $error;
+
+		# catch all SMTP auth error in a unified eval block
+		eval {
+			if ($smtp_auth) {
+				my $sasl = Authen::SASL->new(
+					mechanism => $smtp_auth,
+					callback => {
+						user     => $cred->{'username'},
+						pass     => $cred->{'password'},
+						authname => $cred->{'username'},
+					}
+				);
+				$result = $smtp->auth($sasl);
+			} else {
+				$result = $smtp->auth($cred->{'username'}, $cred->{'password'});
+			}
+			1; # ensure true value is returned if no exception is thrown
+		} or do {
+			$error = $@ || 'Unknown error';
+		};

-		if ($smtp_auth) {
-			my $sasl = Authen::SASL->new(
-				mechanism => $smtp_auth,
-				callback => {
-					user => $cred->{'username'},
-					pass => $cred->{'password'},
-					authname => $cred->{'username'},
-				}
-			);
-
-			return !!$smtp->auth($sasl);
-		}
-
-		return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
-	});
-
-	return $auth;
-}
+		# NOTE: SMTP status code handling will be added in a subsequent commit
+		return $result ? 1 : 0;
+	}

 sub ssl_verify_params {
 	eval {
--
2.48.1

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [GSoC PATCH v5 2/2] sendemail: finer-grained SMTP error handling
  2025-03-19  2:02       ` [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling Zheng Yuting
  2025-03-19  2:02         ` [GSoC PATCH v5 1/2] sendemail: capture errors in an eval {} block Zheng Yuting
@ 2025-03-19  2:02         ` Zheng Yuting
  2025-03-19  6:35         ` [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling Meet Soni
  2025-03-21  2:51         ` [GSoC PATCH v6 0/2] send-email: " Zheng Yuting
  3 siblings, 0 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-19  2:02 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, Zheng Yuting

Code captured errors but did not process them further.
This treated all failures the same without distinguishing SMTP status.

Add a regex to extract status codes as defined in RFC 5321:

- For 4yz (temporary errors), return 1 and allow retries.
- For 5yz (permanent errors), return 0 as failure.
- For unrecognized codes, treat as permanent errors.
- If no error occurs, return the authentication result.

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 8feb43e9f7..69ba328653 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1454,9 +1454,30 @@ sub smtp_auth_maybe {
 			$error = $@ || 'Unknown error';
 		};

-		# NOTE: SMTP status code handling will be added in a subsequent commit
-		return $result ? 1 : 0;
-	}
+		# check if an error was captured
+		if ($error) {
+			# parse SMTP status code from error message in:
+			# https://www.rfc-editor.org/rfc/rfc5321.html
+			if ($error =~ /\b(\d{3})\b/) {
+				my $status_code = $1;
+				if ($status_code =~ /^4/) {
+					# 4yz: Transient Negative Completion reply
+					warn "SMTP temporary error (status code $status_code): $error";
+					return 1;
+				} elsif ($status_code =~ /^5/) {
+					# 5yz: Permanent Negative Completion reply
+					warn "SMTP permanent error (status code $status_code): $error";
+					return 0;
+				}
+				# if no recognized status code is found, treat as permanent error
+				warn "SMTP unknown error: $error";
+				return 0;
+			}
+			return $result ? 1 : 0;
+		} else {
+			return $result ? 1 : 0;
+		}
+}

 sub ssl_verify_params {
 	eval {
--
2.48.1

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling
  2025-03-19  2:02       ` [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling Zheng Yuting
  2025-03-19  2:02         ` [GSoC PATCH v5 1/2] sendemail: capture errors in an eval {} block Zheng Yuting
  2025-03-19  2:02         ` [GSoC PATCH v5 2/2] sendemail: finer-grained SMTP error handling Zheng Yuting
@ 2025-03-19  6:35         ` Meet Soni
  2025-03-21  2:51         ` [GSoC PATCH v6 0/2] send-email: " Zheng Yuting
  3 siblings, 0 replies; 27+ messages in thread
From: Meet Soni @ 2025-03-19  6:35 UTC (permalink / raw)
  To: Zheng Yuting; +Cc: git, gitster

On Wed, 19 Mar 2025 at 07:32, Zheng Yuting <05zyt30@gmail.com> wrote:
>
> This patch series improves SMTP authentication error handling.
>
> Auth relied solely on return values without capturing exceptions,
> misjudging non-credential errors as authentication failures.
>
> Patch v5 1/2 wraps the auth process in an eval {} block to catch all
> exceptions, adds var error for future handling, and var result to return
> auth state.
>
> Patch v5 2/2 introduces finer-grained SMTP error handling, extracting
> status codes per RFC 5321 to differentiate between temporary (4yz) and
> permanent (5yz) errors. Unrecognized codes are treated as permanent
> failures. Otherwise return the authentication result.
>
>
> Zheng Yuting (2):
>   sendemail: capture errors in an eval {} block
>   sendemail: finer-grained SMTP error handling
>
I'm not sure if this is worth a re-roll but, `sendemail` should be `send-email`.
>  git-send-email.perl | 62 ++++++++++++++++++++++++++++++++-------------
>  1 file changed, 45 insertions(+), 17 deletions(-)
>
> --
> 2.48.1
>
Thanks

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v6 0/2] send-email: improve error capture and status code handling
  2025-03-19  2:02       ` [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling Zheng Yuting
                           ` (2 preceding siblings ...)
  2025-03-19  6:35         ` [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling Meet Soni
@ 2025-03-21  2:51         ` Zheng Yuting
  2025-03-21  2:51           ` [GSoC PATCH v6 1/2] send-email: capture errors in an eval {} block Zheng Yuting
                             ` (4 more replies)
  3 siblings, 5 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-21  2:51 UTC (permalink / raw)
  To: git; +Cc: 05zyt30, meetsoni3017, gitster, Zheng Yuting

This patch series improves SMTP authentication error handling.

Auth relied solely on return values without capturing exceptions,
misjudging non-credential errors as authentication failures.

Patch v6 1/2 wraps the auth process in an eval {} block to catch all
exceptions, adds var error for future handling, and var result to return
auth state.

Patch v6 2/2 introduces finer-grained SMTP error handling, extracting
status codes per RFC 5321 to differentiate between temporary (4yz) and
permanent (5yz) errors. Unrecognized codes are treated as permanent
failures. Otherwise return the authentication result.

Zheng Yuting (2):
  send-email: capture errors in an eval {} block
  send-email: finer-grained SMTP error handling

 git-send-email.perl | 62 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 45 insertions(+), 17 deletions(-)

--
2.48.1

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v6 1/2] send-email: capture errors in an eval {} block
  2025-03-21  2:51         ` [GSoC PATCH v6 0/2] send-email: " Zheng Yuting
@ 2025-03-21  2:51           ` Zheng Yuting
  2025-03-21  2:51           ` [GSoC PATCH v6 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
                             ` (3 subsequent siblings)
  4 siblings, 0 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-21  2:51 UTC (permalink / raw)
  To: git; +Cc: 05zyt30, meetsoni3017, gitster, Zheng Yuting

Auth relied solely on return values without catching errors. This misjudges
non-credential errors as auth failure without error info.

Patch wraps the entire auth process in an eval {} block to catch
all exceptions, including non-credential errors. It adds a new $error var,
uses 'or do' to prevent flow break, and returns $result ? 1 : 0. And merges
if/else branches, integrates SASL and basic auth, with comments for
future status code handling.

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 45 ++++++++++++++++++++++++++-------------------
 1 file changed, 26 insertions(+), 19 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 798d59b84f..8feb43e9f7 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1419,7 +1419,7 @@ sub smtp_auth_maybe {
 		die "invalid smtp auth: '${smtp_auth}'";
 	}

-	# TODO: Authentication may fail not because credentials were
+	# Authentication may fail not because credentials were
 	# invalid but due to other reasons, in which we should not
 	# reject credentials.
 	$auth = Git::credential({
@@ -1431,25 +1431,32 @@ sub smtp_auth_maybe {
 		'password' => $smtp_authpass
 	}, sub {
 		my $cred = shift;
+		my $result;
+		my $error;
+
+		# catch all SMTP auth error in a unified eval block
+		eval {
+			if ($smtp_auth) {
+				my $sasl = Authen::SASL->new(
+					mechanism => $smtp_auth,
+					callback => {
+						user     => $cred->{'username'},
+						pass     => $cred->{'password'},
+						authname => $cred->{'username'},
+					}
+				);
+				$result = $smtp->auth($sasl);
+			} else {
+				$result = $smtp->auth($cred->{'username'}, $cred->{'password'});
+			}
+			1; # ensure true value is returned if no exception is thrown
+		} or do {
+			$error = $@ || 'Unknown error';
+		};

-		if ($smtp_auth) {
-			my $sasl = Authen::SASL->new(
-				mechanism => $smtp_auth,
-				callback => {
-					user => $cred->{'username'},
-					pass => $cred->{'password'},
-					authname => $cred->{'username'},
-				}
-			);
-
-			return !!$smtp->auth($sasl);
-		}
-
-		return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
-	});
-
-	return $auth;
-}
+		# NOTE: SMTP status code handling will be added in a subsequent commit
+		return $result ? 1 : 0;
+	}

 sub ssl_verify_params {
 	eval {
--
2.48.1

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [GSoC PATCH v6 2/2] send-email: finer-grained SMTP error handling
  2025-03-21  2:51         ` [GSoC PATCH v6 0/2] send-email: " Zheng Yuting
  2025-03-21  2:51           ` [GSoC PATCH v6 1/2] send-email: capture errors in an eval {} block Zheng Yuting
@ 2025-03-21  2:51           ` Zheng Yuting
  2025-03-21 15:38           ` [GSoC PATCH v6 0/2] send-email: improve error capture and status code handling Junio C Hamano
                             ` (2 subsequent siblings)
  4 siblings, 0 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-21  2:51 UTC (permalink / raw)
  To: git; +Cc: 05zyt30, meetsoni3017, gitster, Zheng Yuting

Code captured errors but did not process them further.
This treated all failures the same without distinguishing SMTP status.

Add a regex to extract status codes as defined in RFC 5321:

- For 4yz (temporary errors), return 1 and allow retries.
- For 5yz (permanent errors), return 0 as failure.
- For unrecognized codes, treat as permanent errors.
- If no error occurs, return the authentication result.

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 8feb43e9f7..69ba328653 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1454,9 +1454,30 @@ sub smtp_auth_maybe {
 			$error = $@ || 'Unknown error';
 		};
 
-		# NOTE: SMTP status code handling will be added in a subsequent commit
-		return $result ? 1 : 0;
-	}
+		# check if an error was captured
+		if ($error) {
+			# parse SMTP status code from error message in:
+			# https://www.rfc-editor.org/rfc/rfc5321.html
+			if ($error =~ /\b(\d{3})\b/) {
+				my $status_code = $1;
+				if ($status_code =~ /^4/) {
+					# 4yz: Transient Negative Completion reply
+					warn "SMTP temporary error (status code $status_code): $error";
+					return 1;
+				} elsif ($status_code =~ /^5/) {
+					# 5yz: Permanent Negative Completion reply
+					warn "SMTP permanent error (status code $status_code): $error";
+					return 0;
+				}
+				# if no recognized status code is found, treat as permanent error
+				warn "SMTP unknown error: $error";
+				return 0;
+			}
+			return $result ? 1 : 0;
+		} else {
+			return $result ? 1 : 0;
+		}
+}
 
 sub ssl_verify_params {
 	eval {
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [GSoC PATCH v6 0/2] send-email: improve error capture and status code handling
  2025-03-21  2:51         ` [GSoC PATCH v6 0/2] send-email: " Zheng Yuting
  2025-03-21  2:51           ` [GSoC PATCH v6 1/2] send-email: capture errors in an eval {} block Zheng Yuting
  2025-03-21  2:51           ` [GSoC PATCH v6 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
@ 2025-03-21 15:38           ` Junio C Hamano
  2025-03-23  2:21           ` [GSoC PATCH v7 " Zheng Yuting
  2025-03-24 14:53           ` [GSoC PATCH v8 0/2] send-email: improve error capture and status code handling Zheng Yuting
  4 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2025-03-21 15:38 UTC (permalink / raw)
  To: Zheng Yuting; +Cc: git, meetsoni3017

Does not pass t9001 when applied to Git 2.49.0.



Test Summary Report
-------------------
t9001-send-email.sh (Wstat: 256 (exited 1) Tests: 215 Failed: 169)
  Failed tests:  4-7, 9-10, 12-13, 15, 17, 19, 21-28, 31-35
                37, 39-60, 62, 64-66, 68, 70, 72, 74, 76
                78, 80, 82, 84-91, 94-99, 101-112, 114-127
                130, 132-135, 138, 140-142, 144, 146, 148
                151, 153-167, 169-189, 194-203, 205-215
  Non-zero exit status: 1
Files=1, Tests=215, 24 wallclock secs ( 0.19 usr  0.02 sys +  9.31 cusr 10.44 csys = 19.96 CPU)
Result: FAIL

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v7 0/2] send-email: improve error capture and status code handling
  2025-03-21  2:51         ` [GSoC PATCH v6 0/2] send-email: " Zheng Yuting
                             ` (2 preceding siblings ...)
  2025-03-21 15:38           ` [GSoC PATCH v6 0/2] send-email: improve error capture and status code handling Junio C Hamano
@ 2025-03-23  2:21           ` Zheng Yuting
  2025-03-23  2:21             ` [GSoC PATCH v7 1/2] send-email: capture errors in an eval {} block Zheng Yuting
  2025-03-23  2:21             ` [GSoC PATCH v7 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
  2025-03-24 14:53           ` [GSoC PATCH v8 0/2] send-email: improve error capture and status code handling Zheng Yuting
  4 siblings, 2 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-23  2:21 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, meetsoni3017, Zheng Yuting

This patch series improves SMTP authentication error handling.

Auth relied solely on return values without capturing exceptions,
misjudging non-credential errors as authentication failures.

Patch v7 1/2 wraps the auth process in an eval {} block to catch all
exceptions, adds var error for future handling, and var result to return
auth state.

Patch v7 2/2 introduces finer-grained SMTP error handling, extracting
status codes per RFC 5321 to differentiate between temporary (4yz) and
permanent (5yz) errors. For 4yz (transient errors), return 1 and allow
retries. For 5yz (permanent errors), return 0 as failure. Unrecognized
codes are treated as transient errors by returning 1. If the status code
is not caught or no error occurs but no result is defined, return 1 as a
transient error. Otherwise, return the authentication result.

Zheng Yuting (2):
  send-email: capture errors in an eval {} block
  send-email: finer-grained SMTP error handling

 git-send-email.perl | 68 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 54 insertions(+), 14 deletions(-)

-- 
2.49.0


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v7 1/2] send-email: capture errors in an eval {} block
  2025-03-23  2:21           ` [GSoC PATCH v7 " Zheng Yuting
@ 2025-03-23  2:21             ` Zheng Yuting
  2025-03-23  2:21             ` [GSoC PATCH v7 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
  1 sibling, 0 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-23  2:21 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, meetsoni3017, Zheng Yuting

Auth relied solely on return values without catching errors. This misjudges
non-credential errors as auth failure without error info.

Patch wraps the entire auth process in an eval {} block to catch
all exceptions, including non-credential errors. It adds a new $error var,
uses 'or do' to prevent flow break, and returns $result ? 1 : 0. And merges
if/else branches, integrates SASL and basic auth, with comments for
future status code handling.

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 43 +++++++++++++++++++++++++++----------------
 1 file changed, 27 insertions(+), 16 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 798d59b84f..0f05f55e50 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1419,7 +1419,7 @@ sub smtp_auth_maybe {
 		die "invalid smtp auth: '${smtp_auth}'";
 	}
 
-	# TODO: Authentication may fail not because credentials were
+	# Authentication may fail not because credentials were
 	# invalid but due to other reasons, in which we should not
 	# reject credentials.
 	$auth = Git::credential({
@@ -1431,21 +1431,32 @@ sub smtp_auth_maybe {
 		'password' => $smtp_authpass
 	}, sub {
 		my $cred = shift;
-
-		if ($smtp_auth) {
-			my $sasl = Authen::SASL->new(
-				mechanism => $smtp_auth,
-				callback => {
-					user => $cred->{'username'},
-					pass => $cred->{'password'},
-					authname => $cred->{'username'},
-				}
-			);
-
-			return !!$smtp->auth($sasl);
-		}
-
-		return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
+		my $result;
+		my $error;
+
+		# catch all SMTP auth error in a unified eval block
+		eval {
+			if ($smtp_auth) {
+				my $sasl = Authen::SASL->new(
+					mechanism => $smtp_auth,
+					callback => {
+						user     => $cred->{'username'},
+						pass     => $cred->{'password'},
+						authname => $cred->{'username'},
+					}
+				);
+				$result = $smtp->auth($sasl);
+			} else {
+				$result = $smtp->auth($cred->{'username'}, $cred->{'password'});
+			}
+			1; # ensure true value is returned if no exception is thrown
+		} or do {
+			$error = $@ || 'Unknown error';
+		};
+
+		# NOTE: SMTP status code handling will be added in a subsequent commit,
+		# return 1 when failed due to non-credential reasons
+		return $error ? 1 : ($result ? 1 : 0);
 	});
 
 	return $auth;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [GSoC PATCH v7 2/2] send-email: finer-grained SMTP error handling
  2025-03-23  2:21           ` [GSoC PATCH v7 " Zheng Yuting
  2025-03-23  2:21             ` [GSoC PATCH v7 1/2] send-email: capture errors in an eval {} block Zheng Yuting
@ 2025-03-23  2:21             ` Zheng Yuting
  2025-03-24  6:00               ` Junio C Hamano
  1 sibling, 1 reply; 27+ messages in thread
From: Zheng Yuting @ 2025-03-23  2:21 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, meetsoni3017, Zheng Yuting

Code captured errors but did not process them further.
This treated all failures the same without distinguishing SMTP status.

Add a regex to extract status codes as defined in RFC 5321:

- For 4yz (transient errors), return 1 and allow retries.
- For 5yz (permanent errors), return 0 as failure.
- For unrecognized codes, return 1 as transient errors.
- For errors where the status code was not caught, return 1 as transient
errors.
- If no error and no result is returned, return 1 as a transient error.
- If no error occurs with result defined, return the authentication result.

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 0f05f55e50..e09a4a316f 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1454,9 +1454,38 @@ sub smtp_auth_maybe {
 			$error = $@ || 'Unknown error';
 		};
 
-		# NOTE: SMTP status code handling will be added in a subsequent commit,
-		# return 1 when failed due to non-credential reasons
-		return $error ? 1 : ($result ? 1 : 0);
+		if ($error) {
+			# check if an error was captured
+			# parse SMTP status code from error message in:
+			# https://www.rfc-editor.org/rfc/rfc5321.html
+			if ($error =~ /\b(\d{3})\b/) {
+				my $status_code = $1;
+				if ($status_code =~ /^4/) {
+					# 4yz: Transient Negative Completion reply
+					warn "SMTP temporary error (status code $status_code): $error";
+					return 1;
+				} elsif ($status_code =~ /^5/) {
+					# 5yz: Permanent Negative Completion reply
+					warn "SMTP permanent error (status code $status_code): $error";
+					return 0;
+				} else {
+					# if no recognized status code is found, treat as transient error
+					warn "SMTP unknown error: $error. Treating as permanent failure.";
+					return 1;
+				}
+			} else {
+				# if no status code is found, treat as transient error
+				warn "SMTP generic error: $error";
+				return 1;
+			}
+		} elsif (!defined $result) {
+			# if no error and no result is returned, treat as transient error
+			warn "SMTP no result error: $error";
+		    return 1; 
+		}
+		else {
+			return $result ? 1 : 0;
+		}
 	});
 
 	return $auth;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [GSoC PATCH v7 2/2] send-email: finer-grained SMTP error handling
  2025-03-23  2:21             ` [GSoC PATCH v7 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
@ 2025-03-24  6:00               ` Junio C Hamano
  0 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2025-03-24  6:00 UTC (permalink / raw)
  To: Zheng Yuting; +Cc: git, meetsoni3017

Zheng Yuting <05zyt30@gmail.com> writes:

> +		if ($error) {

This block is full of overly long lines.  Would it make sense to
turn it into a helper sub and do just this here in the block

			return handle_smtp_error($error);

And then the remainder of the block would become a single helper
function that is called only from here, losing 2 levels of
indentation.

> +			# check if an error was captured
> +			# parse SMTP status code from error message in:
> +			# https://www.rfc-editor.org/rfc/rfc5321.html
> +			if ($error =~ /\b(\d{3})\b/) {
> +				my $status_code = $1;
> +				if ($status_code =~ /^4/) {
> +					# 4yz: Transient Negative Completion reply
> +					warn "SMTP temporary error (status code $status_code): $error";
> +					return 1;
> +				} elsif ($status_code =~ /^5/) {
> +					# 5yz: Permanent Negative Completion reply
> +					warn "SMTP permanent error (status code $status_code): $error";
> +					return 0;
> +				} else {
> +					# if no recognized status code is found, treat as transient error
> +					warn "SMTP unknown error: $error. Treating as permanent failure.";

The comment and warning message say different things.  I suspect
that the warning message is wrong, as the branch returns 1 to signal
the caller to do the same thing a the 4yz transient case?

> +					return 1;
> +				}
> +			} else {
> +				# if no status code is found, treat as transient error
> +				warn "SMTP generic error: $error";
> +				return 1;
> +			}
> +		} elsif (!defined $result) {
> +			# if no error and no result is returned, treat as transient error
> +			warn "SMTP no result error: $error";
> +		    return 1; 
> +		}
> +		else {
> +			return $result ? 1 : 0;
> +		}
>  	});
>  
>  	return $auth;

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v8 0/2] send-email: improve error capture and status code handling
  2025-03-21  2:51         ` [GSoC PATCH v6 0/2] send-email: " Zheng Yuting
                             ` (3 preceding siblings ...)
  2025-03-23  2:21           ` [GSoC PATCH v7 " Zheng Yuting
@ 2025-03-24 14:53           ` Zheng Yuting
  2025-03-24 14:53             ` [GSoC PATCH v8 1/2] send-email: capture errors in an eval {} block Zheng Yuting
                               ` (2 more replies)
  4 siblings, 3 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-24 14:53 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, meetsoni3017, Zheng Yuting

This patch series improves SMTP authentication error handling.

Auth relied solely on return values without capturing exceptions,
misjudging non-credential errors as authentication failures.

Patch v8 1/2 wraps the auth process in an eval {} block to catch all
exceptions, adds var error for future handling, and var result to return
auth state.

Patch v8 2/2 introduces finer-grained SMTP error handling by extracting
status codes per RFC 5321. For 4yz (transient) errors, return 1 and allow
retries; for 5yz (permanent) errors, return 0. Unrecognized or uncaught
status codes are treated as transient errors (return 1). If no error is
present and no result is defined, return 1 as a transient error; otherwise,
return the authentication result.


 Zheng Yuting (2):
  send-email: capture errors in an eval {} block
  send-email: finer-grained SMTP error handling

 git-send-email.perl | 69 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 54 insertions(+), 15 deletions(-)

--
2.49.0

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v8 1/2] send-email: capture errors in an eval {} block
  2025-03-24 14:53           ` [GSoC PATCH v8 0/2] send-email: improve error capture and status code handling Zheng Yuting
@ 2025-03-24 14:53             ` Zheng Yuting
  2025-03-24 14:53             ` [GSoC PATCH v8 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
  2025-03-26  7:52             ` [GSoC PATCH v9 0/2] send-email: improve error capture and status code handling Zheng Yuting
  2 siblings, 0 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-24 14:53 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, meetsoni3017, Zheng Yuting

Auth relied solely on return values without catching errors. This misjudges
non-credential errors as auth failure without error info.

Patch wraps the entire auth process in an eval {} block to catch
all exceptions, including non-credential errors. It adds a new $error var,
uses 'or do' to prevent flow break, and returns $result ? 1 : 0. And merges
if/else branches, integrates SASL and basic auth, with comments for
future status code handling.

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 43 +++++++++++++++++++++++++++----------------
 1 file changed, 27 insertions(+), 16 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 798d59b84f..0f05f55e50 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1419,7 +1419,7 @@ sub smtp_auth_maybe {
 		die "invalid smtp auth: '${smtp_auth}'";
 	}
 
-	# TODO: Authentication may fail not because credentials were
+	# Authentication may fail not because credentials were
 	# invalid but due to other reasons, in which we should not
 	# reject credentials.
 	$auth = Git::credential({
@@ -1431,21 +1431,32 @@ sub smtp_auth_maybe {
 		'password' => $smtp_authpass
 	}, sub {
 		my $cred = shift;
-
-		if ($smtp_auth) {
-			my $sasl = Authen::SASL->new(
-				mechanism => $smtp_auth,
-				callback => {
-					user => $cred->{'username'},
-					pass => $cred->{'password'},
-					authname => $cred->{'username'},
-				}
-			);
-
-			return !!$smtp->auth($sasl);
-		}
-
-		return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
+		my $result;
+		my $error;
+
+		# catch all SMTP auth error in a unified eval block
+		eval {
+			if ($smtp_auth) {
+				my $sasl = Authen::SASL->new(
+					mechanism => $smtp_auth,
+					callback => {
+						user     => $cred->{'username'},
+						pass     => $cred->{'password'},
+						authname => $cred->{'username'},
+					}
+				);
+				$result = $smtp->auth($sasl);
+			} else {
+				$result = $smtp->auth($cred->{'username'}, $cred->{'password'});
+			}
+			1; # ensure true value is returned if no exception is thrown
+		} or do {
+			$error = $@ || 'Unknown error';
+		};
+
+		# NOTE: SMTP status code handling will be added in a subsequent commit,
+		# return 1 when failed due to non-credential reasons
+		return $error ? 1 : ($result ? 1 : 0);
 	});
 
 	return $auth;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [GSoC PATCH v8 2/2] send-email: finer-grained SMTP error handling
  2025-03-24 14:53           ` [GSoC PATCH v8 0/2] send-email: improve error capture and status code handling Zheng Yuting
  2025-03-24 14:53             ` [GSoC PATCH v8 1/2] send-email: capture errors in an eval {} block Zheng Yuting
@ 2025-03-24 14:53             ` Zheng Yuting
  2025-03-25 15:34               ` Junio C Hamano
  2025-03-26  7:52             ` [GSoC PATCH v9 0/2] send-email: improve error capture and status code handling Zheng Yuting
  2 siblings, 1 reply; 27+ messages in thread
From: Zheng Yuting @ 2025-03-24 14:53 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, meetsoni3017, Zheng Yuting

Code captured errors but did not process them further.
This treated all failures the same without distinguishing SMTP status.

Add handle-smtp_error to extract SMTP status codes using a regex (as
defined in RFC 5321) and handle errors as follows:

- No error present:
	- If a result is provided, return 1 to indicate success.
	- Otherwise, return 0 to indicate failure.

- Error present with a captured three-digit status code:
	- For 4yz (transient errors), return 1 and allow retries.
	- For 5yz (permanent errors), return 0 to indicate failure.
	- For any other recognized status code, return 1, treating it as
	a transient error.

- Error present but no status code found:
	- Return 1 as a transient error.

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 34 +++++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 0f05f55e50..12b1a7c7de 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1454,14 +1454,42 @@ sub smtp_auth_maybe {
 			$error = $@ || 'Unknown error';
 		};
 
-		# NOTE: SMTP status code handling will be added in a subsequent commit,
-		# return 1 when failed due to non-credential reasons
-		return $error ? 1 : ($result ? 1 : 0);
+		return handle_smtp_error($error, $result);
 	});
 
 	return $auth;
 }
 
+sub handle_smtp_error {
+	my ($error, $result) = @_;
+
+	# If no error is present, return the result directly
+	return $result ? 1 : 0 unless $error;
+
+	# Check if an error was captured
+	# Parse SMTP status code from error message in:
+	# https://www.rfc-editor.org/rfc/rfc5321.html
+	if ($error =~ /\b(\d{3})\b/) {
+		my $status_code = $1;
+		if ($status_code =~ /^4/) {
+			# 4yz: Transient Negative Completion reply
+			warn "SMTP transient error (status code $status_code): $error";
+			return 1;
+		} elsif ($status_code =~ /^5/) {
+			# 5yz: Permanent Negative Completion reply
+			warn "SMTP permanent error (status code $status_code): $error";
+			return 0;
+		}
+		# If no recognized status code is found, treat as transient error
+		warn "SMTP unknown error: $error. Treating as transient failure.";
+		return 1;
+	}
+
+	# If no status code is found, treat as transient error
+	warn "SMTP generic error: $error";
+	return 1;
+}
+
 sub ssl_verify_params {
 	eval {
 		require IO::Socket::SSL;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [GSoC PATCH v8 2/2] send-email: finer-grained SMTP error handling
  2025-03-24 14:53             ` [GSoC PATCH v8 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
@ 2025-03-25 15:34               ` Junio C Hamano
  0 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2025-03-25 15:34 UTC (permalink / raw)
  To: Zheng Yuting; +Cc: git, meetsoni3017

Zheng Yuting <05zyt30@gmail.com> writes:

> -		# NOTE: SMTP status code handling will be added in a subsequent commit,
> -		# return 1 when failed due to non-credential reasons
> -		return $error ? 1 : ($result ? 1 : 0);
> +		return handle_smtp_error($error, $result);

It was a bit surprising that the new handle-smtp-error sub handles
the case without an error.  I would actually have expected for it to
be something like:

		return ($error
                        ? handle_smtp_error($error)
			: ($result ? 1 : 0));

I.e., we used to unconditionally return 1 upon error, and the only
change introduced by this step is to classify $error with the helper
function better and behave differently depending on the error.

Having said that ...

> +sub handle_smtp_error {
> +	my ($error, $result) = @_;
> +
> +	# If no error is present, return the result directly
> +	return $result ? 1 : 0 unless $error;

... as the "no error" case is implemented as an early return, the
mental burden on the readers is not so bad.  They can concentrate on
the error case when reading the remainder of the function.

Still, it would be with even less mental burden if the no-error case
is handled by the caller to make this function only about error cases.

> +	# Check if an error was captured
> +	# Parse SMTP status code from error message in:
> +	# https://www.rfc-editor.org/rfc/rfc5321.html
> +	if ($error =~ /\b(\d{3})\b/) {
> +		my $status_code = $1;
> +		if ($status_code =~ /^4/) {
> +			# 4yz: Transient Negative Completion reply
> +			warn "SMTP transient error (status code $status_code): $error";
> +			return 1;
> +		} elsif ($status_code =~ /^5/) {
> +			# 5yz: Permanent Negative Completion reply
> +			warn "SMTP permanent error (status code $status_code): $error";
> +			return 0;
> +		}
> +		# If no recognized status code is found, treat as transient error
> +		warn "SMTP unknown error: $error. Treating as transient failure.";
> +		return 1;
> +	}
> +
> +	# If no status code is found, treat as transient error
> +	warn "SMTP generic error: $error";
> +	return 1;
> +}
> +
>  sub ssl_verify_params {
>  	eval {
>  		require IO::Socket::SSL;

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v9 0/2] send-email: improve error capture and status code handling
  2025-03-24 14:53           ` [GSoC PATCH v8 0/2] send-email: improve error capture and status code handling Zheng Yuting
  2025-03-24 14:53             ` [GSoC PATCH v8 1/2] send-email: capture errors in an eval {} block Zheng Yuting
  2025-03-24 14:53             ` [GSoC PATCH v8 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
@ 2025-03-26  7:52             ` Zheng Yuting
  2025-03-26  7:52               ` [GSoC PATCH v9 1/2] send-email: capture errors in an eval {} block Zheng Yuting
  2025-03-26  7:52               ` [GSoC PATCH v9 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
  2 siblings, 2 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-26  7:52 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, meetsoni3017, Zheng Yuting

This patch series improves SMTP authentication error handling.

Auth relied solely on return values without capturing exceptions,
misjudging non-credential errors as authentication failures.

Patch v9 1/2 wraps the auth process in an eval {} block to catch all
exceptions, adds var error for future handling, and var result to return
auth state.

Patch v9 2/2 introduces finer-grained SMTP error handling by extracting
status codes per RFC 5321. For 4yz (transient) errors, return 1 and allow
retries; for 5yz (permanent) errors, return 0. Unrecognized or uncaught
status codes are treated as transient errors (return 1). If no error is
present and no result is defined, return 1 as a transient error; otherwise,
return the authentication result.


 Zheng Yuting (2):
  send-email: capture errors in an eval {} block
  send-email: finer-grained SMTP error handling

 git-send-email.perl | 69 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 54 insertions(+), 15 deletions(-)

--
2.49.0

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [GSoC PATCH v9 1/2] send-email: capture errors in an eval {} block
  2025-03-26  7:52             ` [GSoC PATCH v9 0/2] send-email: improve error capture and status code handling Zheng Yuting
@ 2025-03-26  7:52               ` Zheng Yuting
  2025-03-26  7:52               ` [GSoC PATCH v9 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
  1 sibling, 0 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-26  7:52 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, meetsoni3017, Zheng Yuting

Auth relied solely on return values without catching errors. This misjudges
non-credential errors as auth failure without error info.

Patch wraps the entire auth process in an eval {} block to catch
all exceptions, including non-credential errors. It adds a new $error var,
uses 'or do' to prevent flow break, and returns $result ? 1 : 0. And merges
if/else branches, integrates SASL and basic auth, with comments for
future status code handling.

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 43 +++++++++++++++++++++++++++----------------
 1 file changed, 27 insertions(+), 16 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 798d59b84f..0f05f55e50 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1419,7 +1419,7 @@ sub smtp_auth_maybe {
 		die "invalid smtp auth: '${smtp_auth}'";
 	}
 
-	# TODO: Authentication may fail not because credentials were
+	# Authentication may fail not because credentials were
 	# invalid but due to other reasons, in which we should not
 	# reject credentials.
 	$auth = Git::credential({
@@ -1431,21 +1431,32 @@ sub smtp_auth_maybe {
 		'password' => $smtp_authpass
 	}, sub {
 		my $cred = shift;
-
-		if ($smtp_auth) {
-			my $sasl = Authen::SASL->new(
-				mechanism => $smtp_auth,
-				callback => {
-					user => $cred->{'username'},
-					pass => $cred->{'password'},
-					authname => $cred->{'username'},
-				}
-			);
-
-			return !!$smtp->auth($sasl);
-		}
-
-		return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
+		my $result;
+		my $error;
+
+		# catch all SMTP auth error in a unified eval block
+		eval {
+			if ($smtp_auth) {
+				my $sasl = Authen::SASL->new(
+					mechanism => $smtp_auth,
+					callback => {
+						user     => $cred->{'username'},
+						pass     => $cred->{'password'},
+						authname => $cred->{'username'},
+					}
+				);
+				$result = $smtp->auth($sasl);
+			} else {
+				$result = $smtp->auth($cred->{'username'}, $cred->{'password'});
+			}
+			1; # ensure true value is returned if no exception is thrown
+		} or do {
+			$error = $@ || 'Unknown error';
+		};
+
+		# NOTE: SMTP status code handling will be added in a subsequent commit,
+		# return 1 when failed due to non-credential reasons
+		return $error ? 1 : ($result ? 1 : 0);
 	});
 
 	return $auth;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [GSoC PATCH v9 2/2] send-email: finer-grained SMTP error handling
  2025-03-26  7:52             ` [GSoC PATCH v9 0/2] send-email: improve error capture and status code handling Zheng Yuting
  2025-03-26  7:52               ` [GSoC PATCH v9 1/2] send-email: capture errors in an eval {} block Zheng Yuting
@ 2025-03-26  7:52               ` Zheng Yuting
  1 sibling, 0 replies; 27+ messages in thread
From: Zheng Yuting @ 2025-03-26  7:52 UTC (permalink / raw)
  To: 05zyt30; +Cc: git, gitster, meetsoni3017, Zheng Yuting

Code captured errors but did not process them further.
This treated all failures the same without distinguishing SMTP status.

Add handle-smtp_error to extract SMTP status codes using a regex (as
defined in RFC 5321) and handle errors as follows:

- No error present:
	- If a result is provided, return 1 to indicate success.
	- Otherwise, return 0 to indicate failure.

- Error present with a captured three-digit status code:
	- For 4yz (transient errors), return 1 and allow retries.
	- For 5yz (permanent errors), return 0 to indicate failure.
	- For any other recognized status code, return 1, treating it as
	a transient error.

- Error present but no status code found:
	- Return 1 as a transient error.

Signed-off-by: Zheng Yuting <05ZYT30@gmail.com>
---
 git-send-email.perl | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 0f05f55e50..1f613fa979 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1454,14 +1454,40 @@ sub smtp_auth_maybe {
 			$error = $@ || 'Unknown error';
 		};
 
-		# NOTE: SMTP status code handling will be added in a subsequent commit,
-		# return 1 when failed due to non-credential reasons
-		return $error ? 1 : ($result ? 1 : 0);
+		return ($error
+			? handle_smtp_error($error)
+			: ($result ? 1 : 0));
 	});
 
 	return $auth;
 }
 
+sub handle_smtp_error {
+	my ($error) = @_;
+
+	# Parse SMTP status code from error message in:
+	# https://www.rfc-editor.org/rfc/rfc5321.html
+	if ($error =~ /\b(\d{3})\b/) {
+		my $status_code = $1;
+		if ($status_code =~ /^4/) {
+			# 4yz: Transient Negative Completion reply
+			warn "SMTP transient error (status code $status_code): $error";
+			return 1;
+		} elsif ($status_code =~ /^5/) {
+			# 5yz: Permanent Negative Completion reply
+			warn "SMTP permanent error (status code $status_code): $error";
+			return 0;
+		}
+		# If no recognized status code is found, treat as transient error
+		warn "SMTP unknown error: $error. Treating as transient failure.";
+		return 1;
+	}
+
+	# If no status code is found, treat as transient error
+	warn "SMTP generic error: $error";
+	return 1;
+}
+
 sub ssl_verify_params {
 	eval {
 		require IO::Socket::SSL;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2025-03-26  7:53 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-12  6:46 [GSoC PATCH v3 0/1] Refactor SMTP Auth Error Handling Zheng Yuting
2025-03-12  6:46 ` [GSoC PATCH v3 1/1] Unify SMTP auth error handling Zheng Yuting
2025-03-13 19:58   ` Junio C Hamano
2025-03-14 12:55     ` Yuting Zheng
2025-03-16  5:09     ` [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization Zheng Yuting
2025-03-16  5:09       ` [GSoC PATCH v4 1/2] Unify capture of SMTP errors Zheng Yuting
2025-03-16  5:09       ` [GSoC PATCH v4 2/2] Error handling for SMTP status codes Zheng Yuting
2025-03-17 23:01       ` [GSoC PATCH v4 0/2] smtp_auth_maybe: unified error capture and status code processing optimization Junio C Hamano
2025-03-19  2:02       ` [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling Zheng Yuting
2025-03-19  2:02         ` [GSoC PATCH v5 1/2] sendemail: capture errors in an eval {} block Zheng Yuting
2025-03-19  2:02         ` [GSoC PATCH v5 2/2] sendemail: finer-grained SMTP error handling Zheng Yuting
2025-03-19  6:35         ` [GSoC PATCH v5 0/2] sendemail: improve error capture and status code handling Meet Soni
2025-03-21  2:51         ` [GSoC PATCH v6 0/2] send-email: " Zheng Yuting
2025-03-21  2:51           ` [GSoC PATCH v6 1/2] send-email: capture errors in an eval {} block Zheng Yuting
2025-03-21  2:51           ` [GSoC PATCH v6 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
2025-03-21 15:38           ` [GSoC PATCH v6 0/2] send-email: improve error capture and status code handling Junio C Hamano
2025-03-23  2:21           ` [GSoC PATCH v7 " Zheng Yuting
2025-03-23  2:21             ` [GSoC PATCH v7 1/2] send-email: capture errors in an eval {} block Zheng Yuting
2025-03-23  2:21             ` [GSoC PATCH v7 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
2025-03-24  6:00               ` Junio C Hamano
2025-03-24 14:53           ` [GSoC PATCH v8 0/2] send-email: improve error capture and status code handling Zheng Yuting
2025-03-24 14:53             ` [GSoC PATCH v8 1/2] send-email: capture errors in an eval {} block Zheng Yuting
2025-03-24 14:53             ` [GSoC PATCH v8 2/2] send-email: finer-grained SMTP error handling Zheng Yuting
2025-03-25 15:34               ` Junio C Hamano
2025-03-26  7:52             ` [GSoC PATCH v9 0/2] send-email: improve error capture and status code handling Zheng Yuting
2025-03-26  7:52               ` [GSoC PATCH v9 1/2] send-email: capture errors in an eval {} block Zheng Yuting
2025-03-26  7:52               ` [GSoC PATCH v9 2/2] send-email: finer-grained SMTP error handling Zheng Yuting

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).