From 1a0004b51bcb9a3cf233b7c2a0e6dbe9b0c47ced Mon Sep 17 00:00:00 2001 From: Robin van der Vliet Date: Mon, 22 Dec 2025 15:08:17 +0100 Subject: [PATCH] Improve memory usage when sending large attachments --- src/SMTP.php | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/SMTP.php b/src/SMTP.php index b657798c..1abf967c 100644 --- a/src/SMTP.php +++ b/src/SMTP.php @@ -770,6 +770,25 @@ class SMTP } } + private function iterateLines($s) + { + $start = 0; + $length = strlen($s); + + for ($i = 0; $i < $length; $i++) { + $c = $s[$i]; + if ($c === "\n" || $c === "\r") { + yield substr($s, $start, $i - $start); + if ($c === "\r" && $i + 1 < $length && $s[$i + 1] === "\n") { + $i++; + } + $start = $i + 1; + } + } + + yield substr($s, $start); + } + /** * Send an SMTP DATA command. * Issues a data command and sends the msg_data to the server, @@ -798,15 +817,16 @@ class SMTP * NOTE: this does not count towards line-length limit. */ - //Normalize line breaks before exploding - $lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $msg_data)); + //Iterate over lines with normalized line breaks + $lines = $this->iterateLines($msg_data); /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field * of the first line (':' separated) does not contain a space then it _should_ be a header, and we will * process all lines before a blank line as headers. */ - $field = substr($lines[0], 0, strpos($lines[0], ':')); + $first_line = $lines->current(); + $field = substr($first_line, 0, strpos($first_line, ':')); $in_headers = false; if (!empty($field) && strpos($field, ' ') === false) { $in_headers = true;