Expected behaviour
When Textpattern sends mail via Textpattern\Mail\Adapter\Mail (e.g. through a com_connect contact form using From, Reply-to, X-Mailer, Content-Type etc.), each header should arrive at the recipient's mail client as a distinct header field, with the sender name/address displayed correctly (e.g. From: info@example.com, Reply-to: visitor@example.com).
Actual behaviour
On our server (Hostpoint shared hosting, FreeBSD, Exim as MTA), outgoing mail headers built by Mail.php are separated by a bare \n (line feed only, no carriage return), since neither IS_WIN nor cgi.rfc2616_headers apply in our environment:
protected $separator = "\n";
...
if (IS_WIN) {
$this->separator = "\r\n";
} elseif (ini_get('cgi.rfc2616_headers') != 0) {
$this->separator = "\r\n";
}
Exim interprets the subsequent header lines (Reply-to, X-Mailer, Content-Transfer-Encoding, Content-Type) as continuation lines of the preceding From: header (RFC 5322 folding), rather than as separate header fields. The raw received message shows:
From: <info@example.com>
Reply-to: <visitor@example.com>
X-Mailer: Textpattern
Content-Transfer-Encoding: 8bit
Content-Type: text/plain; charset="UTF-8"
As a result, mail clients (e.g. Mozilla Thunderbird) that correctly parse this as one long, folded From: value display garbled fragments (text/plain,, charset= UTF-8) in place of the sender name, instead of showing the intended sender/reply-to addresses.
Manually forcing $separator to "\r\n" unconditionally (regardless of IS_WIN/cgi.rfc2616_headers) resolved the issue completely.
Steps to reproduce
- On a non-Windows server where
cgi.rfc2616_headers is not set (e.g. typical FreeBSD/Exim shared hosting such as Hostpoint), install the com_connect plugin (v4.9.0, using the new Textpattern\Mail classes).
- Configure a contact form with
<txp:com_connect to="recipient@example.com" from="sender@example.com" /> (or any other flow that goes through Textpattern\Mail\Adapter\Mail::send() with a Reply-to and/or custom headers set).
- Submit the form as a visitor.
- Inspect the raw source of the received email in an email client (e.g. Thunderbird's "View Source").
- Observe that
Reply-to, X-Mailer, Content-Transfer-Encoding and Content-Type headers are indented with a leading space and are being folded into the From: header value, rather than appearing as separate header lines.
Additional information
Textpattern version: 4.9.1
Web server vendor and version: Apache (Hostpoint shared hosting)
Database server vendor and version: MariaDB 10.11.18
PHP version: 8.3.32
Operating system: FreeBSD (Hostpoint managed hosting, mail() delivered via local Exim 4.99.5)
Suggested fix
Since \r\n is the only correct line separator for SMTP/RFC 5322 headers regardless of platform, consider setting protected $separator = "\r\n"; unconditionally in vendors/Textpattern/Mail/Adapter/Mail.php, rather than conditionally based on IS_WIN or cgi.rfc2616_headers. The current detection appears to miss common non-Windows, non-CGI hosting setups (e.g. PHP-FPM on FreeBSD) where the receiving MTA still requires strict \r\n separation to avoid folding subsequent headers into the preceding one.
Expected behaviour
When Textpattern sends mail via
Textpattern\Mail\Adapter\Mail(e.g. through acom_connectcontact form usingFrom,Reply-to,X-Mailer,Content-Typeetc.), each header should arrive at the recipient's mail client as a distinct header field, with the sender name/address displayed correctly (e.g.From: info@example.com,Reply-to: visitor@example.com).Actual behaviour
On our server (Hostpoint shared hosting, FreeBSD, Exim as MTA), outgoing mail headers built by
Mail.phpare separated by a bare\n(line feed only, no carriage return), since neitherIS_WINnorcgi.rfc2616_headersapply in our environment:Exim interprets the subsequent header lines (
Reply-to,X-Mailer,Content-Transfer-Encoding,Content-Type) as continuation lines of the precedingFrom:header (RFC 5322 folding), rather than as separate header fields. The raw received message shows:As a result, mail clients (e.g. Mozilla Thunderbird) that correctly parse this as one long, folded
From:value display garbled fragments (text/plain,,charset= UTF-8) in place of the sender name, instead of showing the intended sender/reply-to addresses.Manually forcing
$separatorto"\r\n"unconditionally (regardless ofIS_WIN/cgi.rfc2616_headers) resolved the issue completely.Steps to reproduce
cgi.rfc2616_headersis not set (e.g. typical FreeBSD/Exim shared hosting such as Hostpoint), install thecom_connectplugin (v4.9.0, using the newTextpattern\Mailclasses).<txp:com_connect to="recipient@example.com" from="sender@example.com" />(or any other flow that goes throughTextpattern\Mail\Adapter\Mail::send()with aReply-toand/or custom headers set).Reply-to,X-Mailer,Content-Transfer-EncodingandContent-Typeheaders are indented with a leading space and are being folded into theFrom:header value, rather than appearing as separate header lines.Additional information
Textpattern version: 4.9.1
Web server vendor and version: Apache (Hostpoint shared hosting)
Database server vendor and version: MariaDB 10.11.18
PHP version: 8.3.32
Operating system: FreeBSD (Hostpoint managed hosting,
mail()delivered via local Exim 4.99.5)Suggested fix
Since
\r\nis the only correct line separator for SMTP/RFC 5322 headers regardless of platform, consider settingprotected $separator = "\r\n";unconditionally invendors/Textpattern/Mail/Adapter/Mail.php, rather than conditionally based onIS_WINorcgi.rfc2616_headers. The current detection appears to miss common non-Windows, non-CGI hosting setups (e.g. PHP-FPM on FreeBSD) where the receiving MTA still requires strict\r\nseparation to avoid folding subsequent headers into the preceding one.