Skip to content

Commit 4c58159

Browse files
committed
Merge branch 'zy/send-email-error-handling'
Auth-related (and unrelated) error handling in send-email has been made more robust. * zy/send-email-error-handling: send-email: finer-grained SMTP error handling send-email: capture errors in an eval {} block
2 parents 01a6e24 + 1ac402c commit 4c58159

File tree

1 file changed

+52
-15
lines changed

1 file changed

+52
-15
lines changed

git-send-email.perl

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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

14541491
sub ssl_verify_params {

0 commit comments

Comments
 (0)