tweedegolf / mailcrab

Email test server for development, written in Rust

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MailCrab always proceeds `AUTH PLAIN` even though `ENABLE_TLS_AUTH` is not set

cuongvuong-phoenix opened this issue Β· comments

I just discovered the app today, and thanks a lot for this awesome tiny app! The UI looks so nice and clean, and it even has dark mode which is just πŸš€.

However, when I'm using it as a replacement for MailCatcher, I cannot receive any email from my app. When launching MailCrab with RUST_LOG=debug to find the pitfall, I found that the backend always got Sending: 503 Bad sequence of commands after Received: AUTH PLAIN AAA=.
When I set ENABLE_TLS_AUTH=true, my app just hangs and on the backend side of MailCrab nothing is logged after the message Connection from 127.0.0.1:{random port} (just like when running the curl command without -k --ssl-reqd options).
Therefore, I think my app just doesn't have a proper SSL authentication in the development environment, and as MailCrab always proceeds AUTH PLAIN no matter ENABLE_TLS_AUTH is set or not, I cannot see any email from my app.

The key thing here is that I'm running MailCatcher/MailCrab mostly in a development environment, so I think it should be better to just ignore the AUTH PLAIN header, right? Both MailCatcher and MailHog seem to be doing it as they can receive my app emails normally (just that their UI is meh...).

How are you connecting to MailCrab - which SMTP parameters are configured in your app?

Maybe your app tries to upgrade a plain SMTP connection to TLS using STARTTLS, which we do not support (in fact, I want to discourage people from using STARTTLS given the security implications).

In that case you just have to change your SMTP parameters in your app for development.

MailCrab ignores any client authentication, it will accept and proceed any username password, but you can also just omit them in you SMTP parameters.

Thanks for taking a look at this issue.

My app is using Rails 6, and yes, there is a config to use STARTTLS (enable_starttls_auto: true in their docs). However, I also initialized a plain new Rails 6 project and used the identical config and MailCrab was receiving the emails very fine.
As I said, the only difference is that somehow my app emails contain a line AUTH PLAIN AAA= while the plain new Rails project's don't.

My app is quite large already and I'm not sure how to remove that line when sending emails in development environment...

After diving into the MailCrab codebase, I found that the SMTP library maillin parses the AUTH PLAIN line and then handles it in the HelloAuth struct. However, since StateMachine.allow_auth_plain needs both StateMachine.auth_plain and StateMachine.tls to be set correctly (i.e. ENABLE_TLS_AUTH=true)
=> no pattern is matched within HelloAuth.handle function
=> default_handler is called with Cmd::AuthPlain
=> unhandled is called
=> BAD_SEQUENCE_COMMANDS response is returned eventually
In the handle_steam function of MailCrab, even though response.action is still Action::Reply, somehow stream cannot read anything more after processing the line. Not sure whats going on here since stream is from Tokio and is separated from maillin...

But the most interesting thing is that when I tried editing the default_handler function of mailin to handle Cmd::AuthPlain just like Cmd::Noop, everything is working normally and my app emails are received by MailCrab without losing a single bit!

So now I can confirm the root cause is from maillin, I'm not sure whether I should raise this to the library author or suggest MailCrab to tackle this.
From my point of view:

  • maillin is like a standard SMTP server library which means making AUTH PLAIN lines become Noop might not be a good idea.
  • Whereas MailCrab is an email test server, it should be better to just ignore or at least provide an option to ignore the irrelevant lines.

p/s: Just took a look at MailHog and MailCatcher codebase and seems like they don't even process AUTH PLAIN at all. Not sure if MailCrab should rewrite a custom parser to be more fit within the test environment context tho...

Well, I've just checked again my app configuration, seems like it has some empty env vars (set in .env) and Ruby is parsing them as empty strings instead of falling to the default case which is nil. The 3 settings user_name, password, and authentication insert that AUTH PLAIN AAA= line in the emails which led to the issue I described.
The new Rails project doesn't even have those env vars set, so they're all nil and no AUTH PLAIN is inserted. Removing the 3 settings in my app now could easily resolve the problem. βœ”οΈ

However, I still think MailCrab should consider rewriting or modifying the existing parser of maillin to just completely ignore the authentication thingy because MailCrab is supposed to mostly be used for the test environment.

Anyway, I will just share this beautiful Rust app with my friends and co-workers now. Hope it will grow better πŸ¦€

Thank you @cuongvuong-phoenix for your thorough analysis!

You are correct - mailin forbids authentication when TLS is disabled. I will into this a bit further...

As you stated mailin explicitly forbids authentication when TLS is not enabled. This seems reasonable to me, since any credentials would be sent in plaintext if TLS is not enabled. This would be possibly disastrous in a production environment, since credentials could be leaked this way.

MailCrab is intended for a test environment, but not allowing sending encrypted credentials might help users to not make this mistake production. Also in a test setting sending credentials this way would not make much sense.

So for now, MailCrab only supports one of the following:

  • SMTP without TLS or authentication
  • SMTP over TLS with PLAIN or LOGIN authentication

The LOGIN authentication variant was added to mailin recently, so I will also enable this in MailCrab (see #118)

Thanks again for your deep dive into this issue. I will consider writing a custom SMTP parser in the future.