asdasd
This commit is contained in:
@@ -193,51 +193,131 @@ final class Mailer
|
||||
stream_set_timeout($fp, 15);
|
||||
|
||||
$transcript = [];
|
||||
$read = function (string $label = 'read') use ($fp, &$transcript) {
|
||||
$line = fgets($fp, 515);
|
||||
if ($line !== false) {
|
||||
$transcript[] = $label . ': ' . trim($line);
|
||||
$readResponse = function (array $expectCodes = [], string $label = 'read') use ($fp, &$transcript): array {
|
||||
$lines = [];
|
||||
while (($line = fgets($fp, 515)) !== false) {
|
||||
$line = rtrim($line, "\r\n");
|
||||
$lines[] = $line;
|
||||
$transcript[] = $label . ': ' . $line;
|
||||
// SMTP multiline: code + '-' means more lines, code + ' ' means end
|
||||
if (strlen($line) >= 4 && $line[3] === ' ') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $line;
|
||||
$code = 0;
|
||||
if ($lines) {
|
||||
$code = (int)substr($lines[0], 0, 3);
|
||||
}
|
||||
return [
|
||||
'ok' => !$expectCodes || in_array($code, $expectCodes, true),
|
||||
'code' => $code,
|
||||
'lines' => $lines,
|
||||
];
|
||||
};
|
||||
$write = function (string $cmd, string $label = 'write', bool $mask = false) use ($fp, &$transcript) {
|
||||
$write = function (string $cmd, string $label = 'write', bool $mask = false) use ($fp, &$transcript): void {
|
||||
$transcript[] = $label . ': ' . ($mask ? '[omitted]' : $cmd);
|
||||
fwrite($fp, $cmd . "\r\n");
|
||||
};
|
||||
|
||||
$read();
|
||||
$resp = $readResponse([220], 'greeting');
|
||||
if (!$resp['ok']) {
|
||||
fclose($fp);
|
||||
$this->log('mail_smtp_greeting_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
|
||||
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
|
||||
$this->sendMailFn($to, $subject, $html, $from, $fromName);
|
||||
return;
|
||||
}
|
||||
|
||||
$write('EHLO ' . $this->app->config()->primaryDomain);
|
||||
$read();
|
||||
$resp = $readResponse([250], 'ehlo');
|
||||
if (!$resp['ok']) {
|
||||
fclose($fp);
|
||||
$this->log('mail_smtp_ehlo_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
|
||||
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
|
||||
$this->sendMailFn($to, $subject, $html, $from, $fromName);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($secure === 'tls') {
|
||||
$write('STARTTLS');
|
||||
$read();
|
||||
if (!stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
|
||||
$resp = $readResponse([220], 'starttls');
|
||||
if (!$resp['ok'] || !stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
|
||||
fclose($fp);
|
||||
$this->log('mail_smtp_starttls_failed', ['host' => $host, 'port' => $port]);
|
||||
$this->log('mail_smtp_starttls_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
|
||||
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
|
||||
$this->sendMailFn($to, $subject, $html, $from, $fromName);
|
||||
return;
|
||||
}
|
||||
$write('EHLO ' . $this->app->config()->primaryDomain);
|
||||
$read();
|
||||
$resp = $readResponse([250], 'ehlo-tls');
|
||||
if (!$resp['ok']) {
|
||||
fclose($fp);
|
||||
$this->log('mail_smtp_ehlo_tls_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
|
||||
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
|
||||
$this->sendMailFn($to, $subject, $html, $from, $fromName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($user !== '') {
|
||||
$write('AUTH LOGIN');
|
||||
$read();
|
||||
$resp = $readResponse([334], 'auth-login');
|
||||
if (!$resp['ok']) {
|
||||
fclose($fp);
|
||||
$this->log('mail_smtp_auth_login_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
|
||||
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
|
||||
$this->sendMailFn($to, $subject, $html, $from, $fromName);
|
||||
return;
|
||||
}
|
||||
$write(base64_encode($user), 'auth-user', true);
|
||||
$read();
|
||||
$resp = $readResponse([334], 'auth-user');
|
||||
if (!$resp['ok']) {
|
||||
fclose($fp);
|
||||
$this->log('mail_smtp_auth_user_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
|
||||
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
|
||||
$this->sendMailFn($to, $subject, $html, $from, $fromName);
|
||||
return;
|
||||
}
|
||||
$write(base64_encode($pass), 'auth-pass', true);
|
||||
$read();
|
||||
$resp = $readResponse([235], 'auth-pass');
|
||||
if (!$resp['ok']) {
|
||||
fclose($fp);
|
||||
$this->log('mail_smtp_auth_pass_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
|
||||
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
|
||||
$this->sendMailFn($to, $subject, $html, $from, $fromName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$write('MAIL FROM: <' . $from . '>');
|
||||
$read();
|
||||
$resp = $readResponse([250], 'mail-from');
|
||||
if (!$resp['ok']) {
|
||||
fclose($fp);
|
||||
$this->log('mail_smtp_mailfrom_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
|
||||
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
|
||||
$this->sendMailFn($to, $subject, $html, $from, $fromName);
|
||||
return;
|
||||
}
|
||||
|
||||
$write('RCPT TO: <' . $to . '>');
|
||||
$read();
|
||||
$resp = $readResponse([250, 251], 'rcpt-to');
|
||||
if (!$resp['ok']) {
|
||||
fclose($fp);
|
||||
$this->log('mail_smtp_rcpt_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
|
||||
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
|
||||
$this->sendMailFn($to, $subject, $html, $from, $fromName);
|
||||
return;
|
||||
}
|
||||
|
||||
$write('DATA');
|
||||
$read();
|
||||
$resp = $readResponse([354], 'data-start');
|
||||
if (!$resp['ok']) {
|
||||
fclose($fp);
|
||||
$this->log('mail_smtp_data_start_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
|
||||
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
|
||||
$this->sendMailFn($to, $subject, $html, $from, $fromName);
|
||||
return;
|
||||
}
|
||||
|
||||
$msg = "From: {$fromName} <{$from}>\r\n";
|
||||
$msg .= "To: <{$to}>\r\n";
|
||||
@@ -245,14 +325,16 @@ final class Mailer
|
||||
$msg .= "MIME-Version: 1.0\r\n";
|
||||
$msg .= "Content-Type: text/html; charset=utf-8\r\n\r\n";
|
||||
$msg .= $html . "\r\n.\r\n";
|
||||
$write($msg, 'data');
|
||||
$resp = $read('data-response');
|
||||
$write($msg, 'data', false);
|
||||
$resp = $readResponse([250], 'data-end');
|
||||
|
||||
$write('QUIT');
|
||||
$readResponse([221], 'quit');
|
||||
fclose($fp);
|
||||
|
||||
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
|
||||
|
||||
if ($resp === false || !str_starts_with((string)$resp, '250')) {
|
||||
if (!$resp['ok']) {
|
||||
$this->log('mail_smtp_send_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
|
||||
$this->sendMailFn($to, $subject, $html, $from, $fromName);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user