Can't connect to self-hosted SMTP


#1

It seems like I’m not able to connect to my self-hosted SMTP Server.

I’ve already tried to connect with it over localhost but I can’t manage to change the network mode to “host”.

Using SSL it says:
System.Net.Mail.SmtpException: Failure sending mail. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.

Connecting to it over the internet without SSL it says:
System.Net.Mail.SmtpException: The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.0 Must issue a STARTTLS command first

I’ve really no idea how to fix this problem.


#2

Does the SMTP server use a trusted SSL certificate?


#3

Yeah, it’s using the fullchain.pem file generated by LetsEncrypt.


#4

Maybe the CA cert needs to be installed in the containers? I am not sure.

You can try placing it in ./bwdata/ca-certificates


#5

Tried it. But it doesn’t work after all.
But when I don’t use SSL it doesn’t log any errors at all,
and I also don’t receive any email.

Is there any way to change the network mode of the docker container?


#6

Having this issue, suspect that it is because the mail server has a self-signed certificate. I think its obvious if I’m self hosting in an enterprise that my internal mail server will use a self-signed certificate and bitwarden should allow this or at least provide an option in global.override.env to where we can allow self-signed certs for the smtp server.


#7

Can you try updating to 1.30.0 and see if it works now after adding the CA to ./bwdata/ca-certificates ?


#8

Still doesn’t work, but at least the error message is now more informative, as suspected it is due to a self-signed certificate which is quite common on internal mail servers:

2019-03-18 11:52:31.752 +00:00 [Error] An error occurred while attempting to establish an SSL or TLS connection.

The SSL certificate presented by the server is not trusted by the system for one or more of the following reasons:

  1. The server is using a self-signed certificate which cannot be verified.
  2. The local system is missing a Root or Intermediate certificate needed to verify the server’s certificate.
  3. The certificate presented by the server is expired or invalid.

See https://github.com/jstedfast/MailKit/blob/master/FAQ.md#InvalidSslCertificate for possible solutions.
MailKit.Security.SslHandshakeException: An error occurred while attempting to establish an SSL or TLS connection.

The SSL certificate presented by the server is not trusted by the system for one or more of the following reasons:

  1. The server is using a self-signed certificate which cannot be verified.
  2. The local system is missing a Root or Intermediate certificate needed to verify the server’s certificate.
  3. The certificate presented by the server is expired or invalid.

See https://github.com/jstedfast/MailKit/blob/master/FAQ.md#InvalidSslCertificate for possible solutions. —> System.Security.Authenticatio
at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
— End of stack trace from previous location where exception was thrown —
at System.Net.Security.SslState.ThrowIfExceptional()
at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
at System.Net.Security.SslStream.<>c.b__46_2(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 promise, Bool
— End of stack trace from previous location where exception was thrown —
at MailKit.Net.Smtp.SmtpClient.ConnectAsync(String host, Int32 port, SecureSocketOptions options, Boolean doAsync, CancellationToken canc
— End of inner exception stack trace —
at MailKit.Net.Smtp.SmtpClient.ConnectAsync(String host, Int32 port, SecureSocketOptions options, Boolean doAsync, CancellationToken canc
at Bit.Core.Services.MailKitSmtpMailDeliveryService.SendEmailAsync(MailMessage message) in /home/appveyor/projects/core/src/Core/Services
at Bit.Core.Services.HandlebarsMailService.SendVerifyEmailEmailAsync(String email, Guid userId, String token) in /home/appveyor/projects/
at Bit.Core.Services.UserService.SendEmailVerificationAsync(User user) in /home/appveyor/projects/core/src/Core/Services/Implementations/
at Bit.Api.Controllers.AccountsController.PostVerifyEmail() in /home/appveyor/projects/core/src/Api/Controllers/AccountsController.cs:lin
at lambda_method(Closure , Object )
at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExe
at System.Threading.Tasks.ValueTask`1.get_Result()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()


#9

Not sure why it isn’t trusted if you have provided your CA correctly.

If you want to ignore the untrusted certificate failure and blindly trust the server (not recommended) you can now set the following in >= 1.30.0

in ./bwdata/env/global.override.env:

globalSettings__mail__smtp__trustServer=true

Then restart with ./bitwarden.sh restart


#10

Tried that, getting a different error now:

MailKit.Security.SslHandshakeException: An error occurred while attempting to establish an SSL or TLS connection.

See https://github.com/jstedfast/MailKit/blob/master/FAQ.md#InvalidSslCertificate for possible solutions.
MailKit.Security.SslHandshakeException: An error occurred while attempting to establish an SSL or TLS connection.

One possibility is that you are trying to connect to a port which does not support SSL/TLS.

The other possibility is that the SSL certificate presented by the server is not trusted by the system for one or more of the following reasons:

  1. The server is using a self-signed certificate which cannot be verified.
  2. The local system is missing a Root or Intermediate certificate needed to verify the server’s certificate.
  3. The certificate presented by the server is expired or invalid.

See https://github.com/jstedfast/MailKit/blob/master/FAQ.md#InvalidSslCertificate for possible solutions. —> System.IO.IOException: The handshake failed due to an unexpected packet format.
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslStream.BeginAuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken, AsyncCallback asyncCallback, Object asyncState)
at System.Net.Security.SslStream.BeginAuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation, AsyncCallback asyncCallback, Object asyncState)
at System.Net.Security.SslStream.<>c.b__46_0(String arg1, X509CertificateCollection arg2, SslProtocols arg3, AsyncCallback callback, Object state)
at System.Threading.Tasks.TaskFactory1.FromAsyncImpl[TArg1,TArg2,TArg3](Func6 beginMethod, Func2 endFunction, Action1 endAction, TArg1 arg1, TArg2 arg2, TArg3 arg3, Object state, TaskCreationOptions creationOptions)
at System.Threading.Tasks.TaskFactory.FromAsync[TArg1,TArg2,TArg3](Func6 beginMethod, Action1 endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, Object state)
at System.Net.Security.SslStream.AuthenticateAsClientAsync(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)
at MailKit.Net.Smtp.SmtpClient.ConnectAsync(String host, Int32 port, SecureSocketOptions options, Boolean doAsync, CancellationToken cancellationToken)
— End of inner exception stack trace —
at MailKit.Net.Smtp.SmtpClient.ConnectAsync(String host, Int32 port, SecureSocketOptions options, Boolean doAsync, CancellationToken cancellationToken)
at Bit.Core.Services.MailKitSmtpMailDeliveryService.SendEmailAsync(MailMessage message) in /home/appveyor/projects/core/src/Core/Services/Implementations/MailKitSmtpMailDeliveryService.cs:line 74
at Bit.Core.Services.HandlebarsMailService.SendVerifyEmailEmailAsync(String email, Guid userId, String token) in /home/appveyor/projects/core/src/Core/Services/Implementations/HandlebarsMailService.cs:line 47
at Bit.Core.Services.UserService.SendEmailVerificationAsync(User user) in /home/appveyor/projects/core/src/Core/Services/Implementations/UserService.cs:line 449
at Bit.Api.Controllers.AccountsController.PostVerifyEmail() in /home/appveyor/projects/core/src/Api/Controllers/AccountsController.cs:line 147
at lambda_method(Closure , Object )
at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at System.Threading.Tasks.ValueTask`1.get_Result()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()

The above error is when the settings are:

globalSettings__mail__smtp__ssl=true
globalSettings__mail__smtp__trustServer=true

And it appears I’ve found a bug, if the global override doesn’t have the trustServer at all in the file, or has it set to false:

globalSettings__mail__smtp__ssl=false
globalSettings__mail__smtp__trustServer=false

then it STILL tries to use SSL to connect and results in my initial problem error: System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.

I cannot get it to send in plaintext at all due to this, however if I set the global file as follows:

globalSettings__mail__smtp__ssl=false
globalSettings__mail__smtp__trustServer=true

Then it sends using STARTTLS (verified with packet capture) AND it works AND doesn’t error out. So something is messed up here, these last settings work for me but don’t make any sense.


#11

Hi,

the update to 1.30 broke something regarding TLS using self-signed certs. Before 1.30 it was possible to send mails over port 25 with STARTTLS when the certificates were present in ca-certificates, but now there are errors:

2019-03-18 14:37:15.128 +00:00 [Error] Connection id ""0HLLBLSPQO945"", Request id ""0HLLBLSPQO945:00000001"": An unhandled exception was thrown by the application.
MailKit.Security.SslHandshakeException: An error occurred while attempting to establish an SSL or TLS connection.

One possibility is that you are trying to connect to a port which does not support SSL/TLS.

The other possibility is that the SSL certificate presented by the server is not trusted by the system for one or more of the following reasons:
1. The server is using a self-signed certificate which cannot be verified.
2. The local system is missing a Root or Intermediate certificate needed to verify the server's certificate.
3. The certificate presented by the server is expired or invalid.

See https://github.com/jstedfast/MailKit/blob/master/FAQ.md#InvalidSslCertificate for possible solutions. ---> System.IO.IOException: The handshake failed due to an unexpected packet format.
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslStream.BeginAuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken, AsyncCallback asyncCallback, Object asyncState)
   at System.Net.Security.SslStream.BeginAuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation, AsyncCallback asyncCallback, Object asyncState)
   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__46_0(String arg1, X509CertificateCollection arg2, SslProtocols arg3, AsyncCallback callback, Object state)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncImpl[TArg1,TArg2,TArg3](Func`6 beginMethod, Func`2 endFunction, Action`1 endAction, TArg1 arg1, TArg2 arg2, TArg3 arg3, Object state, TaskCreationOptions creationOptions)
   at System.Threading.Tasks.TaskFactory.FromAsync[TArg1,TArg2,TArg3](Func`6 beginMethod, Action`1 endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, Object state)
   at System.Net.Security.SslStream.AuthenticateAsClientAsync(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)
   at MailKit.Net.Smtp.SmtpClient.ConnectAsync(String host, Int32 port, SecureSocketOptions options, Boolean doAsync, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at MailKit.Net.Smtp.SmtpClient.ConnectAsync(String host, Int32 port, SecureSocketOptions options, Boolean doAsync, CancellationToken cancellationToken)
   at Bit.Core.Services.MailKitSmtpMailDeliveryService.SendEmailAsync(MailMessage message) in /home/appveyor/projects/core/src/Core/Services/Implementations/MailKitSmtpMailDeliveryService.cs:line 74
   at Bit.Core.Services.HandlebarsMailService.SendPasswordlessSignInAsync(String returnUrl, String token, String email) in /home/appveyor/projects/core/src/Core/Services/Implementations/HandlebarsMailService.cs:line 218
   at Bit.Core.Identity.PasswordlessSignInManager`1.PasswordlessSignInAsync(String email, String returnUrl) in /home/appveyor/projects/core/src/Core/Identity/PasswordlessSignInManager.cs:line 41
   at Bit.Admin.Controllers.LoginController.Index(LoginModel model) in /home/appveyor/projects/core/src/Admin/Controllers/LoginController.cs:line 41
   at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ExceptionContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Builder.Extensions.UsePathBaseMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

#12

Is the “correct” way simply to put the .pem file in that directory? And would it be the root CA, root CA + intermediate(s), or just the last intermediate? I’ve run into this problem, and in the short term, have worked around it by setting trustServer=true, but as you say that isn’t a good idea (though since the mail server is also under my control, and everything’s on the same network, I’m not too concerned).