', 250); sendCommand($socket, 'RCPT TO:<' . $to . '>', 250); sendCommand($socket, 'DATA', 354); $message = buildMessage($fromHeader, $to, $subject, $body); fwrite($socket, $message); expectCode($socket, 250); sendCommand($socket, 'QUIT', 221); } finally { fclose($socket); } } /** @return resource */ function connectSmtp(string $host, int $port, string $encryption) { $target = $encryption === 'ssl' ? "ssl://{$host}:{$port}" : "tcp://{$host}:{$port}"; $socket = @stream_socket_client( $target, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, stream_context_create(['ssl' => ['verify_peer' => true, 'verify_peer_name' => true]]) ); if ($socket === false) { throw new RuntimeException("SMTP connect failed: {$errstr} ({$errno})"); } stream_set_timeout($socket, 30); return $socket; } /** @param resource $socket */ function sendCommand($socket, string $command, int $expectedCode): void { fwrite($socket, $command . "\r\n"); expectCode($socket, $expectedCode); } /** @param resource $socket */ function expectCode($socket, int $expectedCode): void { $response = readResponse($socket); $code = (int) substr($response, 0, 3); if ($code !== $expectedCode) { throw new RuntimeException("SMTP error (expected {$expectedCode}): {$response}"); } } /** @param resource $socket */ function readResponse($socket): string { $response = ''; while (($line = fgets($socket, 515)) !== false) { $response .= $line; if (isset($line[3]) && $line[3] === ' ') { break; } } return trim($response); } function buildMessage(string $from, string $to, string $subject, string $body): string { $domain = env('DOMAIN', '0012.de'); $date = gmdate('D, d M Y H:i:s') . ' +0000'; $messageId = sprintf('<%s@%s>', bin2hex(random_bytes(8)), $domain); $headers = [ "From: {$from}", "To: {$to}", "Subject: {$subject}", "Date: {$date}", "Message-ID: {$messageId}", 'MIME-Version: 1.0', 'Content-Type: text/plain; charset=UTF-8', 'Content-Transfer-Encoding: 8bit', ]; return implode("\r\n", $headers) . "\r\n\r\n" . $body . "\r\n.\r\n"; } function sendAlert(string $subject, string $body): void { $to = env('ALERT_EMAIL'); if (!$to) { throw new RuntimeException('ALERT_EMAIL not set in .env'); } sendMail($to, $subject, $body); }