2

I have a server (Centos 7) setup to be used as mail server. Using postfix/dovecot/opendkim/opendmarc.. It works as it should, users are able to connect their emails using gmail for example. Able to send and receive mail.

Also when I use MailKit and test my .NET Core application from my home pc MailKit connects fine and the emails are send.

However, when I deploy the application to my server MailKit fails to connect.

If I look in the logs I see the following

postfix/submission/smtpd[4486]: match_hostname: unknown ~? 127.0.0.1/32
postfix/submission/smtpd[4486]: match_hostaddr: MY_SERVER_IP ~? 127.0.0.1/32
postfix/submission/smtpd[4486]: match_hostname: unknown ~? MY_SERVER_IP/32
postfix/submission/smtpd[4486]: match_hostaddr: MY_SERVER_IP  ~? MY_SERVER_IP/32
postfix/submission/smtpd[4486]: lost connection after STARTTLS from unknown[MY_SERVER_IP]

But if I look a bit higher in the logs I see

Anonymous TLS connection established from unknown[MY_SERVER_IP]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)

My MailKit (which works fine from outside of the server):

using (SmtpClient emailClient = new SmtpClient())
{
    await emailClient.ConnectAsync(emailConfiguration.SmtpServer, emailConfiguration.SmtpPort, SecureSocketOptions.StartTls);
    emailClient.AuthenticationMechanisms.Remove("XOAUTH2");  

    await emailClient.AuthenticateAsync(emailConfiguration.SmtpUsername, emailConfiguration.SmtpPassword);
    await emailClient.SendAsync(message);

    await emailClient.DisconnectAsync(true);
}

edit: The exception from MailKit (certificate is proper and not self-signed):

MailKit.Security.SslHandshakeException: An error occurred while attempting to establish an SSL or TLS connection.
May 19 16:07:37 domain.com NETCoreApp[4452]: The server's SSL certificate could not be validated for the following reasons:
May 19 16:07:37 domain.com NETCoreApp[4452]: • The server certificate has the following errors:
May 19 16:07:37 domain.com NETCoreApp[4452]: • unable to get certificate CRL
May 19 16:07:37 domain.com NETCoreApp[4452]: • The root certificate has the following errors:
May 19 16:07:37 domain.com NETCoreApp[4452]: • unable to get certificate CRL
May 19 16:07:37 domain.com NETCoreApp[4452]: • unable to get local issuer certificate
May 19 16:07:37 domain.com NETCoreApp[4452]: ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
jstedfast
  • 35,744
  • 5
  • 97
  • 110
Somaar
  • 135
  • 2
  • 8

3 Answers3

1

The unable to get certificate CRL error sounds like SslStream was unable to get the CRL, perhaps because the CRL server is unreachable for some reason.

You could try adding emailClient.CheckCertificateRevocation = false; before the ConnectAsync to check if that's the issue.

The other error, unable to get local issuer certificate, might be because the server that MailKit is running on doesn't have the Root CA certificate in its X509Store but your home PC does.

Update:

The problem is that LetsEncrypt SSL certificates do not include a CRL location which means that certificate revocation checks will fail.

To bypass this, you need to set client.CheckCertificateRevocation = false; before connecting.

jstedfast
  • 35,744
  • 5
  • 97
  • 110
  • Thanks for the response! The certificate on my server is installed with Letsencrypt's certbot, it should be good since I don't have browsers (and gmail) complaining. It might be worth a try to turn it off tho. However, I think, because MailKit tries to connect to the same server from inside.. that there is something going wrong with firewall/rights. I haven't tried your answer yet, but found a solution. See my answer. – Somaar May 19 '20 at 19:54
  • 1
    Okay, so the problem is that LetsEncrypt SSL certificates do not include a CRL server location which causes SslStream to fail to validate them. – jstedfast May 22 '20 at 23:23
  • 1
    You need to specify `client.CheckCertificateRevocation = false;` – jstedfast May 22 '20 at 23:24
  • Ah ok, I understand now. Didn't know this. Turning that option off makes sense then. Thanks! – Somaar May 24 '20 at 13:29
1

I have the same problem on ubuntu 20.04 with .NET core 3.1

and after 3 hours of trial and error, I finally found the solution.
I've just ignored the Certificate Validation CallBack.

using var client = new SmtpClient(new ProtocolLogger("smtp.log"));
client.CheckCertificateRevocation = false;
client.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
client.Connect("your.smtp.host", 587, SecureSocketOptions.StartTls);

I hope this would be helpful :)

Søren
  • 6,517
  • 6
  • 43
  • 47
  • This is a security risk as all certificate validation is disabled. It makes a man-in-the-middle attack possible. – Thrasher Mar 31 '23 at 11:29
0

I found an answer which works but isn't my preferred method since I wanted to be able to use MailKit for more that just my own server (make it configurable from within the app itself)

I came to the solution because I thought it had to do with some internal traffic going wrong..

By using the old SmtpClient from System.Net.Mail I was able to use the DefaultCredentials.

using (SmtpClient client = new SmtpClient("127.0.0.1"))
{
    client.UseDefaultCredentials = true;

    MailAddress from = new MailAddress(emailMessage.FromAddress.Address, emailMessage.FromAddress.Name);

    foreach (IEmailAddress emailAddress in emailMessage.ToAddresses)
    {
        MailAddress to = new MailAddress(emailAddress.Address, emailAddress.Name);

        MailMessage email = new MailMessage(from, to)
        {
            Subject = emailMessage.Subject,
            Body = emailMessage.Content
        };

        await client.SendMailAsync(email);
    }
}
Somaar
  • 135
  • 2
  • 8