Files
pk10/App/Core/Mailer.php
T

102 lines
3.5 KiB
PHP

<?php
namespace App\Core;
use Db\Database;
class Mailer {
public static function send(string $to, string $subject, string $htmlBody): bool {
$cfg = self::getConfig();
if (empty($cfg['smtp_host']) || empty($cfg['smtp_user'])) {
// fallback to mail()
$headers = "MIME-Version: 1.0\r\nContent-type:text/html;charset=UTF-8\r\nFrom: {$cfg['smtp_from']}\r\n";
return @mail($to, $subject, $htmlBody, $headers);
}
$host = $cfg['smtp_host'];
$port = (int)($cfg['smtp_port'] ?: 465);
$user = $cfg['smtp_user'];
$pass = $cfg['smtp_pass'];
$from = $cfg['smtp_from'] ?: $user;
$fromName = $cfg['smtp_from_name'] ?: 'System';
$encryption = $cfg['smtp_encryption'] ?: 'ssl';
try {
$target = ($encryption === 'ssl') ? "ssl://{$host}" : $host;
$sock = @fsockopen($target, $port, $errno, $errstr, 10);
if (!$sock) throw new \RuntimeException("Connect failed: {$errstr}");
self::readLine($sock);
self::cmd($sock, "EHLO localhost");
// STARTTLS for tls mode
if ($encryption === 'tls') {
self::cmd($sock, "STARTTLS");
stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
self::cmd($sock, "EHLO localhost");
}
// AUTH LOGIN
self::cmd($sock, "AUTH LOGIN");
self::cmd($sock, base64_encode($user));
self::cmd($sock, base64_encode($pass));
self::cmd($sock, "MAIL FROM:<{$from}>");
self::cmd($sock, "RCPT TO:<{$to}>");
self::cmd($sock, "DATA");
$msg = "From: {$fromName} <{$from}>\r\n"
. "To: {$to}\r\n"
. "Subject: {$subject}\r\n"
. "MIME-Version: 1.0\r\n"
. "Content-Type: text/html; charset=UTF-8\r\n"
. "\r\n"
. $htmlBody . "\r\n.\r\n";
fwrite($sock, $msg);
self::readLine($sock);
self::cmd($sock, "QUIT");
fclose($sock);
return true;
} catch (\Throwable $e) {
error_log("Mailer error: " . $e->getMessage());
return false;
}
}
private static function cmd($sock, string $cmd): string {
fwrite($sock, $cmd . "\r\n");
return self::readLine($sock);
}
private static function readLine($sock): string {
$resp = '';
while ($line = fgets($sock, 512)) {
$resp .= $line;
if (isset($line[3]) && $line[3] === ' ') break;
}
return $resp;
}
public static function getConfig(): array {
$defaults = [
'smtp_host' => '', 'smtp_port' => '465', 'smtp_user' => '',
'smtp_pass' => '', 'smtp_from' => '', 'smtp_from_name' => 'PK10',
'smtp_encryption' => 'ssl',
];
try {
$db = new Database();
$rows = $db->select('system_settings', ['setting_key', 'setting_value'], [
'setting_key[~]' => 'smtp_%'
]);
foreach ($rows as $r) $defaults[$r['setting_key']] = $r['setting_value'];
} catch (\Throwable $e) {}
return $defaults;
}
public static function test(string $to): array {
$ok = self::send($to, 'SMTP Test', '<h2>SMTP configuration is working!</h2><p>Time: ' . date('Y-m-d H:i:s') . '</p>');
return ['success' => $ok, 'message' => $ok ? 'Test email sent' : 'Failed to send, check SMTP settings'];
}
}