Skip to content

Mail\Adapter\Mail: LF-only header separator causes header folding on some Unix MTAs (e.g. Exim/Hostpoint) #2082

Description

@mbeer

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

  1. 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).
  2. 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).
  3. Submit the form as a visitor.
  4. Inspect the raw source of the received email in an email client (e.g. Thunderbird's "View Source").
  5. 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions