axllent / mailpit

An email and SMTP testing tool with API for developers

Home Page:https://mailpit.axllent.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Using directly TLS

tsmanuelanton opened this issue · comments

Hi, maybe I'm missing something, but is there a way to connect using TLS directly instead of starting without encryption and then upgrading with STARTTLS?

Hi @tsmanuelanton. Currently no, it's only STARTTLS. Is there a particular reason you want/need TLS only? I'm not 100% sure if this is even possible via the smtpd module I use, so I'd need to look into that first.

Thank you for your fast reply, @axllent 💯. I am using this server for integration tests and wanted to ensure that my code is compatible with TLS from the beginning. However, I will assume that if it works with STARTTLS, the same would happen with TLS.

I cannot see why it wouldn't work. TLS requires encryption from beginning to end, where STARTTLS does not initially require it for the handshake. The thing to note is that if you are using authentication, TLS is required and your client must upgrade to TLS (unless you specifically disabled that in the Mailpit with --smtp-auth-allow-insecure).

So the short answer is, TLS is definitely used for sending using authentication (unless disabled in Mailpit), even when using STARTTLS.

There might be some configuration issue on the server or in my code. I am using the Go net/smtp package, and everything works fine when I set Security=SecurityStartTLS. However, when I set Security=SecuritySSLTLS, it gives me the error shown in the image below

if srv.Security == SecurityStartTLS {
	if client, err = smtp.Dial(srv.ServerName()); err != nil {
		return fmt.Errorf("new client: %w", err)
	}

	if err = client.StartTLS(tlsconfig); err != nil {
		return fmt.Errorf("start TLS: %w", err)
	}
} else if srv.Security == SecuritySSLTLS {
	conn, err := tls.Dial("tcp", srv.ServerName(), tlsconfig)
	if err != nil {
		return fmt.Errorf("set TLS Dial: %w", err)
	}

	if client, err = smtp.NewClient(conn, srv.Host); err != nil {
		return fmt.Errorf("new client: %w", err)
	}
} else {
	return fmt.Errorf("security not implemented")
}

imagen

Maybe it does in fact require TSL (I've never tested that). Leave this with me and I'll look into how/if it's possible to add an option to Mailpit to use TSL instead of STARTTSL. I'm not too sure when I'll get a chance to look into it, bit I hope in the next couple of days.

Thank you very much, I really appreciate your help. Please, don't feel the need to rush for me 😄.

You are absolutely correct - I have been doing a bit of testing and you cannot connect to STARTTLS directly using TLS in a client. The good news it I can add this feature (it is supported) - I just need to figure out a way to add it so that it makes sense to the user.

Currently there are the following logic in Mailpit:

  • When you add SMTP certificates the SMTP server automatically allows STARTTLS, but it does not require/enforce STARTTLS (ie: you can send unencrypted although most clients automatically upgrade). Basically the client connects and can decide whether to send plain or encrypted (the connection is then upgraded to TLS after the client connects).
  • If the SMTP server is using authentication, then STARTTLS is required (although you can override this with --smtp-auth-allow-insecure to allow auth over an unencrypted connection - just like before TLS was "a thing" in the good old days).
  • There is also an option to enforce STARTTLS (--smtp-tls-required) even without authentication, meaning that a client connecting must use STARTTLS to send the email. This option does not imply TLS-only (what you are after), but rather that a client must upgrade to encryption after it connects. This logic aligns with the TLSRequired flag in the smtpd package I use, and from what I understand aligns with the evolution of SMTP encryption in general.

Now I want to add the option for actual TLS (only) which means that the entire connection must run only over TLS only. This aligns with the TLSListener flag, and is different to STARTTLS because the TCP handshake is encrypted too (and why the two are not compatible even though they both use TLS).

As you can probably see, there will be probably confusion for Mailpit users because of the existing --smtp-tls-required flag in Mailpit.

I think I may have to deprecate the --smtp-tls-required and replace it with two new flags to either:

  1. require STARTTLS, or
  2. enforce & require TLS/SSL

I am thinking maybe --smtp-require-starttls and --smtp-require-tls (they cannot both be used at the same time). I really do not like deprecating flags, but I feel this may be the only way as it will help prevent confusion moving forward when I add "actual TLS" into the mix.

I'm going to slap on this decision as I may have a fresh idea in the morning, but I'd appreciate your comments if you have any. Sorry for the long post!

Apologies for the extra workload 😉. Although I'm not very familiar with this topic, you might consider keeping the --smtp-tls-required flag and detecting whether the client is already using TLS, ensuring the conversion is transparent for the client. I would be happy to assist you in any way I can.

Unfortunately that's not how it works, TLS is TLS and doesn't support upgrading from an unencrypted connection (it doesn't allow an unencrypted connection at all). STARTTLS on the other hand does, which is why it is the more common (though slightly less secure) protocol as it is more backwards compatible. This is why email providers who support both protocols run these on different ports.

Ultimately I predict everything will eventually move to pure TLS in the future (a bit like HTTPS), but that's not for a long time.

In the meantime I will add the option soon to use TLS (instead of STARTTLS) for those like yourself wanting to explicitly test SSL/TLS rather than STARTTLS. I just need to implement it and do the changes I mentioned earlier. I'll also need to write up some documentation as this is a somewhat confusing topic to most.

Also don't apologise for the time/work to implement this. This investigation has allowed me to investigate and better understand the SMTP protocols and their differences, and I see the benefits of adding this feature 👍

@tsmanuelanton I have just released a new version of Mailpit (v1.15.0) which includes TLS support for SMTP 🥳 You can read the documentation on the website.

Please confirm this works for you?

I've just tried and still not working for me. Keeps giving same error tls: first record does not look like a TLS handshake when calling tls.Dial("tcp", srv.ServerName(), tlsconfig). Do I have to use/open any new port?

imagen

It's MP_SMTP_REQUIRE_TLS=true 😄 It runs on the same port you configured (which now should only accept TLS).

My bad, I am dumb 💀. Yeah, now it works fine. Much thank you!

Excellent, thanks for the feedback!