@@ -1419,7 +1419,7 @@ sub smtp_auth_maybe {
14191419 die " invalid smtp auth: '${smtp_auth} '" ;
14201420 }
14211421
1422- # TODO: Authentication may fail not because credentials were
1422+ # Authentication may fail not because credentials were
14231423 # invalid but due to other reasons, in which we should not
14241424 # reject credentials.
14251425 $auth = Git::credential({
@@ -1431,24 +1431,61 @@ sub smtp_auth_maybe {
14311431 ' password' => $smtp_authpass
14321432 }, sub {
14331433 my $cred = shift ;
1434+ my $result ;
1435+ my $error ;
1436+
1437+ # catch all SMTP auth error in a unified eval block
1438+ eval {
1439+ if ($smtp_auth ) {
1440+ my $sasl = Authen::SASL-> new(
1441+ mechanism => $smtp_auth ,
1442+ callback => {
1443+ user => $cred -> {' username' },
1444+ pass => $cred -> {' password' },
1445+ authname => $cred -> {' username' },
1446+ }
1447+ );
1448+ $result = $smtp -> auth($sasl );
1449+ } else {
1450+ $result = $smtp -> auth($cred -> {' username' }, $cred -> {' password' });
1451+ }
1452+ 1; # ensure true value is returned if no exception is thrown
1453+ } or do {
1454+ $error = $@ || ' Unknown error' ;
1455+ };
1456+
1457+ return ($error
1458+ ? handle_smtp_error($error )
1459+ : ($result ? 1 : 0));
1460+ });
14341461
1435- if ($smtp_auth ) {
1436- my $sasl = Authen::SASL-> new(
1437- mechanism => $smtp_auth ,
1438- callback => {
1439- user => $cred -> {' username' },
1440- pass => $cred -> {' password' },
1441- authname => $cred -> {' username' },
1442- }
1443- );
1462+ return $auth ;
1463+ }
14441464
1445- return !!$smtp -> auth($sasl );
1465+ sub handle_smtp_error {
1466+ my ($error ) = @_ ;
1467+
1468+ # Parse SMTP status code from error message in:
1469+ # https://www.rfc-editor.org/rfc/rfc5321.html
1470+ if ($error =~ / \b (\d {3})\b / ) {
1471+ my $status_code = $1 ;
1472+ if ($status_code =~ / ^4/ ) {
1473+ # 4yz: Transient Negative Completion reply
1474+ warn " SMTP transient error (status code $status_code ): $error " ;
1475+ return 1;
1476+ } elsif ($status_code =~ / ^5/ ) {
1477+ # 5yz: Permanent Negative Completion reply
1478+ warn " SMTP permanent error (status code $status_code ): $error " ;
1479+ return 0;
14461480 }
1481+ # If no recognized status code is found, treat as transient error
1482+ warn " SMTP unknown error: $error . Treating as transient failure." ;
1483+ return 1;
1484+ }
14471485
1448- return !!$smtp -> auth($cred -> {' username' }, $cred -> {' password' });
1449- });
1450-
1451- return $auth ;
1486+ # If no status code is found, treat as transient error
1487+ warn " SMTP generic error: $error " ;
1488+ return 1;
14521489}
14531490
14541491sub ssl_verify_params {
0 commit comments