Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does not work with Alpine Linux's sendmail #87

Closed
sjinks opened this issue Apr 10, 2023 · 3 comments
Closed

Does not work with Alpine Linux's sendmail #87

sjinks opened this issue Apr 10, 2023 · 3 comments

Comments

@sjinks
Copy link

sjinks commented Apr 10, 2023

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("[email protected]", "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:<[email protected]>'
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: [email protected]
'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: [email protected]

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

'endmail: send:'To: [email protected]

is

sendmail: send:'To: [email protected]<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("[email protected]", "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:<[email protected]>'
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: [email protected]'
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 :-(

@axllent
Copy link
Owner

axllent commented 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.

@sjinks
Copy link
Author

sjinks commented 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("[email protected]", "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:<[email protected]>'
sendmail: recv:'250 2.1.5 Ok'
sendmail: send:'DATA'
sendmail: recv:'354 End data with <CR><LF>.<CR><LF>'
'endmail: send:'To: [email protected]
'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("[email protected]", "Subject", "Body");'

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

@sjinks sjinks closed this as completed Apr 11, 2023
@axllent
Copy link
Owner

axllent commented 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!

axllent added a commit that referenced this issue Aug 16, 2023
…<CR><CR><LF>

Due to a bug in some common sendmail implementations and PHP >=8.0, message headers sometimes contain `\r\r\n` which is not RFC compliant.

Mailpit will now fix these non-compliant headers. This can be disabled via `--smtp-strict-rfc-headers`

See #87 / #153
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants