[GH-ISSUE #87] Does not work with Alpine Linux's sendmail #57

Closed
opened 2026-03-15 12:19:01 +03:00 by kerem · 3 comments
Owner

Originally created by @sjinks on GitHub (Apr 10, 2023).
Original GitHub issue: https://github.com/axllent/mailpit/issues/87

Steps to reproduce:

  1. Run mailpit container: docker run -it --rm axllent/mailpit
  2. docker exec into the container and run:
apk add php
php -d "sendmail_path=/usr/sbin/sendmail -v -S 127.0.0.1:1025 -t" -r 'mail("admin@example.com", "Subject", "Body");'

Expected result: email is queued

Actual result:

sendmail: recv:'220 28c20bcce561 Mailpit ESMTP Service ready'
sendmail: send:'EHLO 28c20bcce561'
sendmail: recv:'250-28c20bcce561 greets 28c20bcce561'
sendmail: recv:'250-SIZE 0'
sendmail: recv:'250 ENHANCEDSTATUSCODES'
sendmail: send:'MAIL FROM:<root@28c20bcce561>'
sendmail: recv:'250 2.1.0 Ok'
sendmail: send:'RCPT TO:<admin@example.com>'
sendmail: recv:'250 2.1.5 Ok'
sendmail: send:'DATA'
sendmail: recv:'354 Start mail input; end with <CR><LF>.<CR><LF>'
'endmail: send:'To: admin@example.com
'endmail: send:'Subject: Subject
'endmail: send:'
'endmail: send:'Body
sendmail: send:'.'
sendmail: recv:'451 4.3.5 Unable to process mail'
sendmail: . failed

In mailpit logs, I see: RRO[2023/04/10 10:51:02] error parsing message: malformed MIME header line: To: admin@example.com

My debugging showed that mailpit does not handle <CR>: the lines above with the leading ' actually contain the <CR> character:

'endmail: send:'To: admin@example.com

is

sendmail: send:'To: admin@example.com<CR>'

To confirm my finding, I modified the sendmail_path setting:

php -d "sendmail_path=sh -c 'dos2unix | /usr/sbin/sendmail -v -S 127.0.0.1:1025 -t'" -r 'mail("admin@example.com", "Subject", "Body");'

Now it works as expected:

sendmail: recv:'220 28c20bcce561 Mailpit ESMTP Service ready'
sendmail: send:'EHLO 28c20bcce561'
sendmail: recv:'250-28c20bcce561 greets 28c20bcce561'
sendmail: recv:'250-SIZE 0'
sendmail: recv:'250 ENHANCEDSTATUSCODES'
sendmail: send:'MAIL FROM:<root@28c20bcce561>'
sendmail: recv:'250 2.1.0 Ok'
sendmail: send:'RCPT TO:<admin@example.com>'
sendmail: recv:'250 2.1.5 Ok'
sendmail: send:'DATA'
sendmail: recv:'354 Start mail input; end with <CR><LF>.<CR><LF>'
sendmail: send:'To: admin@example.com'
sendmail: send:'Subject: Subject'
sendmail: send:''
sendmail: send:'Body'
sendmail: send:'.'
sendmail: recv:'250 2.0.0 Ok: queued'
sendmail: send:'QUIT'
sendmail: recv:'221 2.0.0 28c20bcce561 Mailpit ESMTP Service closing transmission channel'

However, I think that mailpit should handle the <CR> character in the mail body (MailHog does).

Unfortunately, I don't know Go good enough to submit a PR, sorry :-(

Originally created by @sjinks on GitHub (Apr 10, 2023). Original GitHub issue: https://github.com/axllent/mailpit/issues/87 Steps to reproduce: 1. Run `mailpit` container: `docker run -it --rm axllent/mailpit` 2. `docker exec` into the container and run: ``` apk add php php -d "sendmail_path=/usr/sbin/sendmail -v -S 127.0.0.1:1025 -t" -r 'mail("admin@example.com", "Subject", "Body");' ``` Expected result: email is queued Actual result: ``` sendmail: recv:'220 28c20bcce561 Mailpit ESMTP Service ready' sendmail: send:'EHLO 28c20bcce561' sendmail: recv:'250-28c20bcce561 greets 28c20bcce561' sendmail: recv:'250-SIZE 0' sendmail: recv:'250 ENHANCEDSTATUSCODES' sendmail: send:'MAIL FROM:<root@28c20bcce561>' sendmail: recv:'250 2.1.0 Ok' sendmail: send:'RCPT TO:<admin@example.com>' sendmail: recv:'250 2.1.5 Ok' sendmail: send:'DATA' sendmail: recv:'354 Start mail input; end with <CR><LF>.<CR><LF>' 'endmail: send:'To: admin@example.com 'endmail: send:'Subject: Subject 'endmail: send:' 'endmail: send:'Body sendmail: send:'.' sendmail: recv:'451 4.3.5 Unable to process mail' sendmail: . failed ``` In mailpit logs, I see: ` RRO[2023/04/10 10:51:02] error parsing message: malformed MIME header line: To: admin@example.com` My debugging showed that `mailpit` does not handle `<CR>`: the lines above with the leading `'` actually contain the `<CR>` character: ``` 'endmail: send:'To: admin@example.com ``` is ``` sendmail: send:'To: admin@example.com<CR>' ``` To confirm my finding, I modified the `sendmail_path` setting: ``` php -d "sendmail_path=sh -c 'dos2unix | /usr/sbin/sendmail -v -S 127.0.0.1:1025 -t'" -r 'mail("admin@example.com", "Subject", "Body");' ``` Now it works as expected: ``` sendmail: recv:'220 28c20bcce561 Mailpit ESMTP Service ready' sendmail: send:'EHLO 28c20bcce561' sendmail: recv:'250-28c20bcce561 greets 28c20bcce561' sendmail: recv:'250-SIZE 0' sendmail: recv:'250 ENHANCEDSTATUSCODES' sendmail: send:'MAIL FROM:<root@28c20bcce561>' sendmail: recv:'250 2.1.0 Ok' sendmail: send:'RCPT TO:<admin@example.com>' sendmail: recv:'250 2.1.5 Ok' sendmail: send:'DATA' sendmail: recv:'354 Start mail input; end with <CR><LF>.<CR><LF>' sendmail: send:'To: admin@example.com' sendmail: send:'Subject: Subject' sendmail: send:'' sendmail: send:'Body' sendmail: send:'.' sendmail: recv:'250 2.0.0 Ok: queued' sendmail: send:'QUIT' sendmail: recv:'221 2.0.0 28c20bcce561 Mailpit ESMTP Service closing transmission channel' ``` However, I think that `mailpit` should handle the `<CR>` character in the mail body (MailHog does). Unfortunately, I don't know Go good enough to submit a PR, sorry :-(
kerem closed this issue 2026-03-15 12:19:07 +03:00
Author
Owner

@axllent commented on GitHub (Apr 11, 2023):

Thanks for all the testing and narrowing down the issue @sjinks.

I believe the big difference here between MailHog and Mailpit is that the SMTPD server within MailHog appears to be a custom implementation which maybe isn't as RFC-compliant as it says it is (and, according to the screenshots in the PR you linked from, makes a real mess of the headers / body). Mailpit uses mhale/smtpd which complies to the RFC standards, and will reject non-compliant emails.

The RFC standards state that CRLF is required. The issue here appears to be coming from PHP8, which, according to that bug report, now produces an CRLF (\r\n) by default (which is required by a SMTP server), rather than the former LF (\n in < v8). It's a long thread to follow, but the PHP devs are pointing fingers to the MTA (in this case sendmail) which is making a mess of it. This would make sense if sendmail is changing all \n returns to \r\n, which would result in \r\r\n, and which is I believe what is happening here.

There are a couple of work-arounds (eg: dos2unix as you suggested), which would remove the \r from the \r\n from PHP's mail() ~ which sendmail then adds back in. Very messy, but, as you said, works....

There also appears to be a new backwards-compatibility PHP INI configuration - but I couldn't get that working so that may only be PHP 8.2 (or still unreleased?), I don't know.

Either way though, I do not think the issue here is in Mailpit's SMTPD, but in the default MTA used in Alpine (which is actually busybox's sendmail implementation) - or in Alpine itself (this goes beyong my understanding unfortunately). Mailpit is simply following the RFC, and doing what it should - the email being delivered via sendmail is not compliant, so it is rejected. If I was to create a work-around within Mailpit, it would mean that Mailpit would allow non-compliant emails to be delivered, and by definition defy the point of an SMTP testing tool. I do not think that is a good solution at all.

So I'm not sure "where to" from here unfortunately, but I feel the solution lies in the sendmail version used. There are alternative sendmail implementations available in Alpine. I use msmtp in production (for Alpine docker implementations), and configure PHP to use to mailpit sendmail directly in development, so I cannot say I have experience with the setup you use.

<!-- gh-comment-id:1502720004 --> @axllent commented on GitHub (Apr 11, 2023): Thanks for all the testing and narrowing down the issue @sjinks. I believe the big difference here between MailHog and Mailpit is that the SMTPD server within MailHog appears to be a [custom implementation](https://github.com/mailhog/smtp) which maybe isn't as RFC-compliant as it says it is (and, according to the screenshots in the [PR you linked from](https://github.com/Automattic/vip-cli/pull/1329), makes a real mess of the headers / body). Mailpit uses [mhale/smtpd](https://github.com/mhale/smtpd) which complies to the RFC standards, and will reject non-compliant emails. The RFC standards state that `CRLF` is required. The [issue here](https://github.com/php/php-src/issues/8086) appears to be coming from PHP8, which, according to that bug report, now produces an `CRLF` (`\r\n`) by default (which is required by a SMTP server), rather than the former `LF` (`\n` in < v8). It's a long thread to follow, but the PHP devs are pointing fingers to the MTA (in this case sendmail) which is making a mess of it. This would make sense if sendmail is changing all `\n` returns to `\r\n`, which would result in `\r\r\n`, and which is I believe what is happening here. There are a couple of work-arounds (eg: `dos2unix` as you suggested), which would remove the `\r` from the `\r\n` from PHP's `mail()` ~ which sendmail then adds back in. Very messy, but, as you said, works.... There also appears to be a new backwards-compatibility [PHP INI configuration](https://github.com/php/php-src/blob/master/php.ini-production#L1115-L1117) - but I couldn't get that working so that may only be PHP 8.2 (or still unreleased?), I don't know. Either way though, I do not think the issue here is in Mailpit's SMTPD, but in the default MTA used in Alpine (which is actually busybox's sendmail implementation) - or in Alpine itself (this goes beyong my understanding unfortunately). Mailpit is simply following the RFC, and doing what it should - the email being delivered via sendmail is not compliant, so it is rejected. If I was to create a work-around within Mailpit, it would mean that Mailpit would allow non-compliant emails to be delivered, and by definition defy the point of an SMTP testing tool. I do not think that is a good solution at all. So I'm not sure "where to" from here unfortunately, but I feel the solution lies in the sendmail version used. There are alternative sendmail implementations available in Alpine. I use msmtp in production (for Alpine docker implementations), and configure PHP to use to `mailpit sendmail` directly in development, so I cannot say I have experience with the setup you use.
Author
Owner

@sjinks commented on GitHub (Apr 11, 2023):

Hmmm… However, it still works with Postfix:

/ # php -d "sendmail_path=/usr/sbin/sendmail -v -S my.postfix.server:25 -t" -r 'mail("volodymyr@wildwolf.name", "Subject", "Body");'
sendmail: recv:'220 my.postfix.server ESMTP Postfix (Ubuntu)'
sendmail: send:'EHLO 92aa3eeba134'
sendmail: recv:'250-my.postfix.server'
sendmail: recv:'250-PIPELINING'
sendmail: recv:'250-SIZE 10240000'
sendmail: recv:'250-VRFY'
sendmail: recv:'250-ETRN'
sendmail: recv:'250-STARTTLS'
sendmail: recv:'250-ENHANCEDSTATUSCODES'
sendmail: recv:'250-8BITMIME'
sendmail: recv:'250-DSN'
sendmail: recv:'250-SMTPUTF8'
sendmail: recv:'250 CHUNKING'
sendmail: send:'MAIL FROM:<root@92aa3eeba134>'
sendmail: recv:'250 2.1.0 Ok'
sendmail: send:'RCPT TO:<volodymyr@wildwolf.name>'
sendmail: recv:'250 2.1.5 Ok'
sendmail: send:'DATA'
sendmail: recv:'354 End data with <CR><LF>.<CR><LF>'
'endmail: send:'To: volodymyr@wildwolf.name
'endmail: send:'Subject: Subject
'endmail: send:'
'endmail: send:'Body
sendmail: send:'.'
sendmail: recv:'250 2.0.0 Ok: queued as 1F0671D81AEE'
sendmail: send:'QUIT'
sendmail: recv:'221 2.0.0 Bye'

which would result in \r\r\n, and which is I believe what is happening here.

Yes, you were right, I was able to confirm that with

nc -l -p 10025 -s 127.0.0.1 -e nc -v -o transaction2.txt 127.0.0.1:1025

and

cat data.txt | /usr/sbin/sendmail -v -S 127.0.0.1:10025 -t

(where data.txt was a email with CR LF line endings)

Screenshot_20230411_101318

I use msmtp in production

Great, thanks! I was able to send a test email with this:

php -d "sendmail_path=/usr/bin/msmtp --host=127.0.0.1 --port=1025 -t --auto-from" -r 'mail("admin@example.com", "Subject", "Body");'

Closing then, as this is not a bug :-) Thank you!

<!-- gh-comment-id:1502797659 --> @sjinks commented on GitHub (Apr 11, 2023): Hmmm… However, it still works with Postfix: ``` / # php -d "sendmail_path=/usr/sbin/sendmail -v -S my.postfix.server:25 -t" -r 'mail("volodymyr@wildwolf.name", "Subject", "Body");' sendmail: recv:'220 my.postfix.server ESMTP Postfix (Ubuntu)' sendmail: send:'EHLO 92aa3eeba134' sendmail: recv:'250-my.postfix.server' sendmail: recv:'250-PIPELINING' sendmail: recv:'250-SIZE 10240000' sendmail: recv:'250-VRFY' sendmail: recv:'250-ETRN' sendmail: recv:'250-STARTTLS' sendmail: recv:'250-ENHANCEDSTATUSCODES' sendmail: recv:'250-8BITMIME' sendmail: recv:'250-DSN' sendmail: recv:'250-SMTPUTF8' sendmail: recv:'250 CHUNKING' sendmail: send:'MAIL FROM:<root@92aa3eeba134>' sendmail: recv:'250 2.1.0 Ok' sendmail: send:'RCPT TO:<volodymyr@wildwolf.name>' sendmail: recv:'250 2.1.5 Ok' sendmail: send:'DATA' sendmail: recv:'354 End data with <CR><LF>.<CR><LF>' 'endmail: send:'To: volodymyr@wildwolf.name 'endmail: send:'Subject: Subject 'endmail: send:' 'endmail: send:'Body sendmail: send:'.' sendmail: recv:'250 2.0.0 Ok: queued as 1F0671D81AEE' sendmail: send:'QUIT' sendmail: recv:'221 2.0.0 Bye' ``` > which would result in \r\r\n, and which is I believe what is happening here. Yes, you were right, I was able to confirm that with ```sh nc -l -p 10025 -s 127.0.0.1 -e nc -v -o transaction2.txt 127.0.0.1:1025 ``` and ```sh cat data.txt | /usr/sbin/sendmail -v -S 127.0.0.1:10025 -t ``` (where `data.txt` was a email with CR LF line endings) ![Screenshot_20230411_101318](https://user-images.githubusercontent.com/7810770/231084115-a84f57ba-c2c4-4781-96c1-e6973fef0225.png) > I use msmtp in production Great, thanks! I was able to send a test email with this: ```sh php -d "sendmail_path=/usr/bin/msmtp --host=127.0.0.1 --port=1025 -t --auto-from" -r 'mail("admin@example.com", "Subject", "Body");' ``` Closing then, as this is not a bug :-) Thank you!
Author
Owner

@axllent commented on GitHub (Apr 11, 2023):

Thanks for the confirmation either way. Interesting that it works with postfix, though I suspect that is a "feature" in postfix to fix this very issue (work-around). Then again, even if postfix accepts the mail, it doesn't mean it is strictly valid, and there's no assurance other mail servers will accept it.

I'm no C expert, but I found send_r_n() which is referenced several times in sendmail.c. It sends every line with a trailing \r\n. The lines are however split with xmalloc_fgetline() which looks to me like it splits lines with \n. This means the \r is left at the end of each line, resulting in \r\r\n being sent through to the SMTP server. Again, I'm no C expert, but I think the sendmail implementation in busybox is the definite cause here. I think that if you wanted a proper fix, that would be the place to start.

Glad you got it working though!

<!-- gh-comment-id:1503001683 --> @axllent commented on GitHub (Apr 11, 2023): Thanks for the confirmation either way. Interesting that it works with postfix, though I suspect that is a "feature" in postfix to fix this very issue (work-around). Then again, even if postfix accepts the mail, it doesn't mean it is strictly valid, and there's no assurance other mail servers will accept it. I'm no C expert, but I found [send_r_n()](https://git.busybox.net/busybox/tree/mailutils/mail.c#n85) which is referenced several times in [sendmail.c](https://git.busybox.net/busybox/tree/mailutils/sendmail.c). It sends every line with a trailing `\r\n`. The lines are however split with [xmalloc_fgetline()](https://git.busybox.net/busybox/tree/libbb/get_line_from_file.c) which looks to me like it splits lines with `\n`. This means the `\r` is left at the end of each line, resulting in `\r\r\n` being sent through to the SMTP server. Again, I'm no C expert, but I think the sendmail implementation in busybox is the definite cause here. I think that if you wanted a proper fix, that would be the place to start. Glad you got it working though!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/mailpit#57
No description provided.