Lisää tarkka virheviesti SMTP-lähetykseen debuggausta varten
Virheviesti palautetaan nyt frontendille tarkan SMTP-vaiheen kera (connect, STARTTLS, AUTH, MAIL FROM, RCPT TO, DATA, send), jotta nähdään missä kohtaa lähetys epäonnistuu. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
41
api.php
41
api.php
@@ -599,6 +599,7 @@ function sendTicketMail(string $to, string $subject, string $body, string $inRep
|
|||||||
|
|
||||||
// Jos mailboxilla on SMTP-asetukset, käytä SMTP:tä
|
// Jos mailboxilla on SMTP-asetukset, käytä SMTP:tä
|
||||||
$smtpHost = $mailbox['smtp_host'] ?? '';
|
$smtpHost = $mailbox['smtp_host'] ?? '';
|
||||||
|
error_log("MAIL DEBUG: to={$to} smtpHost={$smtpHost} from={$fromEmail} mailbox_keys=" . implode(',', array_keys($mailbox ?? [])));
|
||||||
if ($smtpHost !== '') {
|
if ($smtpHost !== '') {
|
||||||
return sendViaSMTP($to, $subject, $body, $fromEmail, $fromName, $inReplyTo, $references, $mailbox, $cc);
|
return sendViaSMTP($to, $subject, $body, $fromEmail, $fromName, $inReplyTo, $references, $mailbox, $cc);
|
||||||
}
|
}
|
||||||
@@ -618,6 +619,9 @@ function sendTicketMail(string $to, string $subject, string $body, string $inRep
|
|||||||
return mail($to, $subject, $body, $headers, '-f ' . $fromEmail);
|
return mail($to, $subject, $body, $headers, '-f ' . $fromEmail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var string|null Viimeisin SMTP-virhe (palautetaan frontendille) */
|
||||||
|
$GLOBALS['smtp_last_error'] = null;
|
||||||
|
|
||||||
function sendViaSMTP(string $to, string $subject, string $body, string $fromEmail, string $fromName, string $inReplyTo, string $references, array $mailbox, string $cc): bool {
|
function sendViaSMTP(string $to, string $subject, string $body, string $fromEmail, string $fromName, string $inReplyTo, string $references, array $mailbox, string $cc): bool {
|
||||||
$host = $mailbox['smtp_host'];
|
$host = $mailbox['smtp_host'];
|
||||||
$port = (int)($mailbox['smtp_port'] ?? 587);
|
$port = (int)($mailbox['smtp_port'] ?? 587);
|
||||||
@@ -628,6 +632,14 @@ function sendViaSMTP(string $to, string $subject, string $body, string $fromEmai
|
|||||||
$timeout = 15;
|
$timeout = 15;
|
||||||
$errno = 0; $errstr = '';
|
$errno = 0; $errstr = '';
|
||||||
|
|
||||||
|
$fail = function(string $step, string $detail) use (&$fp) {
|
||||||
|
$msg = "SMTP $step: $detail";
|
||||||
|
error_log($msg);
|
||||||
|
$GLOBALS['smtp_last_error'] = $msg;
|
||||||
|
if (isset($fp) && $fp) fclose($fp);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
// Yhteys
|
// Yhteys
|
||||||
if ($encryption === 'ssl') {
|
if ($encryption === 'ssl') {
|
||||||
$fp = @stream_socket_client("ssl://{$host}:{$port}", $errno, $errstr, $timeout);
|
$fp = @stream_socket_client("ssl://{$host}:{$port}", $errno, $errstr, $timeout);
|
||||||
@@ -635,13 +647,12 @@ function sendViaSMTP(string $to, string $subject, string $body, string $fromEmai
|
|||||||
$fp = @stream_socket_client("tcp://{$host}:{$port}", $errno, $errstr, $timeout);
|
$fp = @stream_socket_client("tcp://{$host}:{$port}", $errno, $errstr, $timeout);
|
||||||
}
|
}
|
||||||
if (!$fp) {
|
if (!$fp) {
|
||||||
error_log("SMTP connect failed: {$errstr} ({$errno})");
|
return $fail('connect', "{$errstr} ({$errno}) — host={$host}:{$port} enc={$encryption}");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
stream_set_timeout($fp, $timeout);
|
stream_set_timeout($fp, $timeout);
|
||||||
|
|
||||||
$resp = fgets($fp, 512);
|
$resp = fgets($fp, 512);
|
||||||
if (substr($resp, 0, 3) !== '220') { fclose($fp); error_log("SMTP banner: $resp"); return false; }
|
if (substr($resp, 0, 3) !== '220') return $fail('banner', trim($resp));
|
||||||
|
|
||||||
// EHLO
|
// EHLO
|
||||||
fwrite($fp, "EHLO " . gethostname() . "\r\n");
|
fwrite($fp, "EHLO " . gethostname() . "\r\n");
|
||||||
@@ -655,9 +666,9 @@ function sendViaSMTP(string $to, string $subject, string $body, string $fromEmai
|
|||||||
if ($encryption === 'tls') {
|
if ($encryption === 'tls') {
|
||||||
fwrite($fp, "STARTTLS\r\n");
|
fwrite($fp, "STARTTLS\r\n");
|
||||||
$resp = fgets($fp, 512);
|
$resp = fgets($fp, 512);
|
||||||
if (substr($resp, 0, 3) !== '220') { fclose($fp); error_log("SMTP STARTTLS: $resp"); return false; }
|
if (substr($resp, 0, 3) !== '220') return $fail('STARTTLS', trim($resp));
|
||||||
$crypto = stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT);
|
$crypto = @stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT);
|
||||||
if (!$crypto) { fclose($fp); error_log("SMTP TLS negotiation failed"); return false; }
|
if (!$crypto) return $fail('TLS', 'TLS negotiation failed');
|
||||||
// EHLO uudelleen TLS:n jälkeen
|
// EHLO uudelleen TLS:n jälkeen
|
||||||
fwrite($fp, "EHLO " . gethostname() . "\r\n");
|
fwrite($fp, "EHLO " . gethostname() . "\r\n");
|
||||||
while ($line = fgets($fp, 512)) {
|
while ($line = fgets($fp, 512)) {
|
||||||
@@ -669,19 +680,19 @@ function sendViaSMTP(string $to, string $subject, string $body, string $fromEmai
|
|||||||
if ($user !== '') {
|
if ($user !== '') {
|
||||||
fwrite($fp, "AUTH LOGIN\r\n");
|
fwrite($fp, "AUTH LOGIN\r\n");
|
||||||
$resp = fgets($fp, 512);
|
$resp = fgets($fp, 512);
|
||||||
if (substr($resp, 0, 3) !== '334') { fclose($fp); error_log("SMTP AUTH: $resp"); return false; }
|
if (substr($resp, 0, 3) !== '334') return $fail('AUTH', trim($resp));
|
||||||
fwrite($fp, base64_encode($user) . "\r\n");
|
fwrite($fp, base64_encode($user) . "\r\n");
|
||||||
$resp = fgets($fp, 512);
|
$resp = fgets($fp, 512);
|
||||||
if (substr($resp, 0, 3) !== '334') { fclose($fp); error_log("SMTP AUTH user: $resp"); return false; }
|
if (substr($resp, 0, 3) !== '334') return $fail('AUTH user', trim($resp) . " (user={$user})");
|
||||||
fwrite($fp, base64_encode($pass) . "\r\n");
|
fwrite($fp, base64_encode($pass) . "\r\n");
|
||||||
$resp = fgets($fp, 512);
|
$resp = fgets($fp, 512);
|
||||||
if (substr($resp, 0, 3) !== '235') { fclose($fp); error_log("SMTP AUTH pass: $resp"); return false; }
|
if (substr($resp, 0, 3) !== '235') return $fail('AUTH pass', trim($resp));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MAIL FROM
|
// MAIL FROM
|
||||||
fwrite($fp, "MAIL FROM:<{$fromEmail}>\r\n");
|
fwrite($fp, "MAIL FROM:<{$fromEmail}>\r\n");
|
||||||
$resp = fgets($fp, 512);
|
$resp = fgets($fp, 512);
|
||||||
if (substr($resp, 0, 3) !== '250') { fclose($fp); error_log("SMTP MAIL FROM: $resp"); return false; }
|
if (substr($resp, 0, 3) !== '250') return $fail('MAIL FROM', trim($resp) . " (from={$fromEmail})");
|
||||||
|
|
||||||
// RCPT TO
|
// RCPT TO
|
||||||
$allRecipients = array_filter(array_map('trim', explode(',', $to)));
|
$allRecipients = array_filter(array_map('trim', explode(',', $to)));
|
||||||
@@ -692,14 +703,14 @@ function sendViaSMTP(string $to, string $subject, string $body, string $fromEmai
|
|||||||
fwrite($fp, "RCPT TO:<{$rcpt}>\r\n");
|
fwrite($fp, "RCPT TO:<{$rcpt}>\r\n");
|
||||||
$resp = fgets($fp, 512);
|
$resp = fgets($fp, 512);
|
||||||
if (substr($resp, 0, 3) !== '250' && substr($resp, 0, 3) !== '251') {
|
if (substr($resp, 0, 3) !== '250' && substr($resp, 0, 3) !== '251') {
|
||||||
fclose($fp); error_log("SMTP RCPT TO: $resp"); return false;
|
return $fail('RCPT TO', trim($resp) . " (rcpt={$rcpt})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DATA
|
// DATA
|
||||||
fwrite($fp, "DATA\r\n");
|
fwrite($fp, "DATA\r\n");
|
||||||
$resp = fgets($fp, 512);
|
$resp = fgets($fp, 512);
|
||||||
if (substr($resp, 0, 3) !== '354') { fclose($fp); error_log("SMTP DATA: $resp"); return false; }
|
if (substr($resp, 0, 3) !== '354') return $fail('DATA', trim($resp));
|
||||||
|
|
||||||
// Rakennetaan viesti
|
// Rakennetaan viesti
|
||||||
$messageId = '<' . uniqid('msg_', true) . '@' . (explode('@', $fromEmail)[1] ?? 'localhost') . '>';
|
$messageId = '<' . uniqid('msg_', true) . '@' . (explode('@', $fromEmail)[1] ?? 'localhost') . '>';
|
||||||
@@ -722,7 +733,7 @@ function sendViaSMTP(string $to, string $subject, string $body, string $fromEmai
|
|||||||
|
|
||||||
fwrite($fp, $msg);
|
fwrite($fp, $msg);
|
||||||
$resp = fgets($fp, 512);
|
$resp = fgets($fp, 512);
|
||||||
if (substr($resp, 0, 3) !== '250') { fclose($fp); error_log("SMTP send: $resp"); return false; }
|
if (substr($resp, 0, 3) !== '250') return $fail('send', trim($resp));
|
||||||
|
|
||||||
// QUIT
|
// QUIT
|
||||||
fwrite($fp, "QUIT\r\n");
|
fwrite($fp, "QUIT\r\n");
|
||||||
@@ -2275,7 +2286,9 @@ switch ($action) {
|
|||||||
|
|
||||||
if (!$sent) {
|
if (!$sent) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['error' => 'Sähköpostin lähetys epäonnistui']);
|
$smtpErr = $GLOBALS['smtp_last_error'] ?? '';
|
||||||
|
$detail = $smtpErr ? " ({$smtpErr})" : '';
|
||||||
|
echo json_encode(['error' => "Sähköpostin lähetys epäonnistui{$detail}"]);
|
||||||
break 2;
|
break 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user