Lisää SMTP-lähetystuki postilaatikoihin
Aiemmin sähköpostit lähetettiin PHP mail()-funktiolla, mikä ei toimi kunnolla useimmilla palvelimilla (SPF/DKIM-ongelmat). Nyt mailboxiin voi konfiguroida SMTP-asetukset (host, port, user, pass, encryption), ja lähetys tapahtuu suoraan SMTP-palvelimen kautta socket-yhteydellä. Fallback PHP mail():iin jos SMTP-asetuksia ei ole asetettu. - db.php: smtp_host/port/user/password/encryption sarakkeet - api.php: sendViaSMTP() socket-pohjainen SMTP-client - index.html: SMTP-kentät mailbox-lomakkeeseen - script.js: SMTP-kenttien luku/kirjoitus lomakkeessa Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
137
api.php
137
api.php
@@ -572,6 +572,13 @@ function sendTicketMail(string $to, string $subject, string $body, string $inRep
|
||||
$fromEmail = $mailbox['smtp_from_email'] ?? $mailbox['imap_user'] ?? MAIL_FROM;
|
||||
$fromName = $mailbox['smtp_from_name'] ?? $mailbox['nimi'] ?? 'Asiakaspalvelu';
|
||||
|
||||
// Jos mailboxilla on SMTP-asetukset, käytä SMTP:tä
|
||||
$smtpHost = $mailbox['smtp_host'] ?? '';
|
||||
if ($smtpHost !== '') {
|
||||
return sendViaSMTP($to, $subject, $body, $fromEmail, $fromName, $inReplyTo, $references, $mailbox, $cc);
|
||||
}
|
||||
|
||||
// Fallback: PHP mail()
|
||||
$headers = "MIME-Version: 1.0\r\n";
|
||||
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
|
||||
$headers .= "From: {$fromName} <{$fromEmail}>\r\n";
|
||||
@@ -586,6 +593,118 @@ function sendTicketMail(string $to, string $subject, string $body, string $inRep
|
||||
return mail($to, $subject, $body, $headers, '-f ' . $fromEmail);
|
||||
}
|
||||
|
||||
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'];
|
||||
$port = (int)($mailbox['smtp_port'] ?? 587);
|
||||
$user = $mailbox['smtp_user'] ?? '';
|
||||
$pass = $mailbox['smtp_password'] ?? '';
|
||||
$encryption = $mailbox['smtp_encryption'] ?? 'tls';
|
||||
|
||||
$timeout = 15;
|
||||
$errno = 0; $errstr = '';
|
||||
|
||||
// Yhteys
|
||||
if ($encryption === 'ssl') {
|
||||
$fp = @stream_socket_client("ssl://{$host}:{$port}", $errno, $errstr, $timeout);
|
||||
} else {
|
||||
$fp = @stream_socket_client("tcp://{$host}:{$port}", $errno, $errstr, $timeout);
|
||||
}
|
||||
if (!$fp) {
|
||||
error_log("SMTP connect failed: {$errstr} ({$errno})");
|
||||
return false;
|
||||
}
|
||||
stream_set_timeout($fp, $timeout);
|
||||
|
||||
$resp = fgets($fp, 512);
|
||||
if (substr($resp, 0, 3) !== '220') { fclose($fp); error_log("SMTP banner: $resp"); return false; }
|
||||
|
||||
// EHLO
|
||||
fwrite($fp, "EHLO " . gethostname() . "\r\n");
|
||||
$ehloResp = '';
|
||||
while ($line = fgets($fp, 512)) {
|
||||
$ehloResp .= $line;
|
||||
if (substr($line, 3, 1) === ' ') break;
|
||||
}
|
||||
|
||||
// STARTTLS jos tls
|
||||
if ($encryption === 'tls') {
|
||||
fwrite($fp, "STARTTLS\r\n");
|
||||
$resp = fgets($fp, 512);
|
||||
if (substr($resp, 0, 3) !== '220') { fclose($fp); error_log("SMTP STARTTLS: $resp"); return false; }
|
||||
$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; }
|
||||
// EHLO uudelleen TLS:n jälkeen
|
||||
fwrite($fp, "EHLO " . gethostname() . "\r\n");
|
||||
while ($line = fgets($fp, 512)) {
|
||||
if (substr($line, 3, 1) === ' ') break;
|
||||
}
|
||||
}
|
||||
|
||||
// AUTH LOGIN
|
||||
if ($user !== '') {
|
||||
fwrite($fp, "AUTH LOGIN\r\n");
|
||||
$resp = fgets($fp, 512);
|
||||
if (substr($resp, 0, 3) !== '334') { fclose($fp); error_log("SMTP AUTH: $resp"); return false; }
|
||||
fwrite($fp, base64_encode($user) . "\r\n");
|
||||
$resp = fgets($fp, 512);
|
||||
if (substr($resp, 0, 3) !== '334') { fclose($fp); error_log("SMTP AUTH user: $resp"); return false; }
|
||||
fwrite($fp, base64_encode($pass) . "\r\n");
|
||||
$resp = fgets($fp, 512);
|
||||
if (substr($resp, 0, 3) !== '235') { fclose($fp); error_log("SMTP AUTH pass: $resp"); return false; }
|
||||
}
|
||||
|
||||
// MAIL FROM
|
||||
fwrite($fp, "MAIL FROM:<{$fromEmail}>\r\n");
|
||||
$resp = fgets($fp, 512);
|
||||
if (substr($resp, 0, 3) !== '250') { fclose($fp); error_log("SMTP MAIL FROM: $resp"); return false; }
|
||||
|
||||
// RCPT TO
|
||||
$allRecipients = array_filter(array_map('trim', explode(',', $to)));
|
||||
if ($cc) {
|
||||
$allRecipients = array_merge($allRecipients, array_filter(array_map('trim', explode(',', $cc))));
|
||||
}
|
||||
foreach ($allRecipients as $rcpt) {
|
||||
fwrite($fp, "RCPT TO:<{$rcpt}>\r\n");
|
||||
$resp = fgets($fp, 512);
|
||||
if (substr($resp, 0, 3) !== '250' && substr($resp, 0, 3) !== '251') {
|
||||
fclose($fp); error_log("SMTP RCPT TO: $resp"); return false;
|
||||
}
|
||||
}
|
||||
|
||||
// DATA
|
||||
fwrite($fp, "DATA\r\n");
|
||||
$resp = fgets($fp, 512);
|
||||
if (substr($resp, 0, 3) !== '354') { fclose($fp); error_log("SMTP DATA: $resp"); return false; }
|
||||
|
||||
// Rakennetaan viesti
|
||||
$messageId = '<' . uniqid('msg_', true) . '@' . (explode('@', $fromEmail)[1] ?? 'localhost') . '>';
|
||||
$msg = "From: {$fromName} <{$fromEmail}>\r\n";
|
||||
$msg .= "To: {$to}\r\n";
|
||||
if ($cc) $msg .= "Cc: {$cc}\r\n";
|
||||
$msg .= "Subject: =?UTF-8?B?" . base64_encode($subject) . "?=\r\n";
|
||||
$msg .= "Message-ID: {$messageId}\r\n";
|
||||
if ($inReplyTo) {
|
||||
$msg .= "In-Reply-To: {$inReplyTo}\r\n";
|
||||
$msg .= "References: " . ($references ? $references . ' ' : '') . $inReplyTo . "\r\n";
|
||||
}
|
||||
$msg .= "MIME-Version: 1.0\r\n";
|
||||
$msg .= "Content-Type: text/plain; charset=UTF-8\r\n";
|
||||
$msg .= "Content-Transfer-Encoding: base64\r\n";
|
||||
$msg .= "Date: " . date('r') . "\r\n";
|
||||
$msg .= "\r\n";
|
||||
$msg .= chunk_split(base64_encode($body));
|
||||
$msg .= "\r\n.\r\n";
|
||||
|
||||
fwrite($fp, $msg);
|
||||
$resp = fgets($fp, 512);
|
||||
if (substr($resp, 0, 3) !== '250') { fclose($fp); error_log("SMTP send: $resp"); return false; }
|
||||
|
||||
// QUIT
|
||||
fwrite($fp, "QUIT\r\n");
|
||||
fclose($fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseLiittymat(array $input): array {
|
||||
$liittymat = [];
|
||||
foreach (($input['liittymat'] ?? []) as $l) {
|
||||
@@ -2580,6 +2699,7 @@ switch ($action) {
|
||||
$result[] = [
|
||||
'id' => $mb['id'],
|
||||
'nimi' => $mb['nimi'] ?? $mb['imap_user'] ?? '',
|
||||
'smtp_from_email' => $mb['smtp_from_email'] ?? $mb['imap_user'] ?? '',
|
||||
'company_id' => $comp['id'],
|
||||
'company_nimi' => $comp['nimi'],
|
||||
];
|
||||
@@ -2755,6 +2875,7 @@ switch ($action) {
|
||||
// Palauta postilaatikot ilman salasanoja
|
||||
$mbs = array_map(function($mb) {
|
||||
$mb['imap_password'] = !empty($mb['imap_password']) ? '********' : '';
|
||||
$mb['smtp_password'] = !empty($mb['smtp_password']) ? '********' : '';
|
||||
return $mb;
|
||||
}, $mailboxes);
|
||||
echo json_encode($mbs);
|
||||
@@ -2775,16 +2896,26 @@ switch ($action) {
|
||||
'imap_encryption' => trim($input['imap_encryption'] ?? 'ssl'),
|
||||
'smtp_from_email' => trim($input['smtp_from_email'] ?? ''),
|
||||
'smtp_from_name' => trim($input['smtp_from_name'] ?? ''),
|
||||
'smtp_host' => trim($input['smtp_host'] ?? ''),
|
||||
'smtp_port' => intval($input['smtp_port'] ?? 587),
|
||||
'smtp_user' => trim($input['smtp_user'] ?? ''),
|
||||
'smtp_encryption' => trim($input['smtp_encryption'] ?? 'tls'),
|
||||
'aktiivinen' => $input['aktiivinen'] ?? true,
|
||||
];
|
||||
// Salasana: jos ******** -> pidä vanha, muuten päivitä
|
||||
// Hae vanha mailbox salasanojen vertailua varten
|
||||
$existingMb = dbGetMailbox($mb['id']);
|
||||
// IMAP-salasana: jos ******** -> pidä vanha, muuten päivitä
|
||||
if (isset($input['imap_password']) && $input['imap_password'] !== '********') {
|
||||
$mb['imap_password'] = $input['imap_password'];
|
||||
} else {
|
||||
// Hae vanha salasana
|
||||
$existingMb = dbGetMailbox($mb['id']);
|
||||
$mb['imap_password'] = $existingMb ? ($existingMb['imap_password'] ?? '') : '';
|
||||
}
|
||||
// SMTP-salasana: jos ******** -> pidä vanha, muuten päivitä
|
||||
if (isset($input['smtp_password']) && $input['smtp_password'] !== '********') {
|
||||
$mb['smtp_password'] = $input['smtp_password'];
|
||||
} else {
|
||||
$mb['smtp_password'] = $existingMb ? ($existingMb['smtp_password'] ?? '') : '';
|
||||
}
|
||||
|
||||
if (empty($mb['nimi'])) {
|
||||
http_response_code(400);
|
||||
|
||||
Reference in New Issue
Block a user