Home > Net >  How to fix "Remote certificate is invalid according to the validation procedure"
How to fix "Remote certificate is invalid according to the validation procedure"

Time:05-16

I am going to try to send emails via Mailkit but ran into problems with the error from "System.Security.Authentication.AuthenticationException" which is "The remote certificate is invalid according to the validation procedure" (translated from danish) My mailserver runs SSL TLS and the TLS supports version 1.2 and 1.3. my code is as below: I do not hope that it is to much code - but I do not know where to enhance the code so it can handle SSL correctly :-(

The error occur in the line "client.Connect("servername", 587, true);"

So my question is: How to avoid this error message via Mailkit?

public void SendMail(string AFromMailAdr, string AFromName, string AToMailAdr, string AToName, string ASubject, string ABody)
{
    MimeMessage message = new MimeMessage();
    ...
    using (var client = new MailKit.Net.Smtp.SmtpClient())
    {
        client.Timeout = 30000;
        client.Connect("servername", 587, true);
        client.Authenticate("Username", "password");
        client.Send(message);
        client.Disconnect(true);
    }
}

I have googlet a lot until now without finding the correct answer - so therefore I kindly ask here on SO.

CodePudding user response:

To be fair, the underlying problem should be checked/corrected.

You can control how MailKit does the server certificate validation using a ServerCertificateValidationCallback

For debugging purposes you could return true; in the callback function.

Code from the MailKit documentation:

using (var client = new MailKit.Net.Smtp.SmtpClient())
{
    // Set our custom SSL certificate validation callback.
    client.ServerCertificateValidationCallback = MySslCertificateValidationCallback;

    client.Timeout = 30000;
    client.Connect("servername", 587, true);
    client.Authenticate("Username", "password");
    client.Send(message);
    client.Disconnect(true);
}

    static bool MySslCertificateValidationCallback (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        // If there are no errors, then everything went smoothly.
        if (sslPolicyErrors == SslPolicyErrors.None)
            return true;

        // Note: MailKit will always pass the host name string as the `sender` argument.
        var host = (string) sender;

        if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0) {
            // This means that the remote certificate is unavailable. Notify the user and return false.
            Console.WriteLine ("The SSL certificate was not available for {0}", host);
            return false;
        }

        if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0) {
            // This means that the server's SSL certificate did not match the host name that we are trying to connect to.
            var certificate2 = certificate as X509Certificate2;
            var cn = certificate2 != null ? certificate2.GetNameInfo (X509NameType.SimpleName, false) : certificate.Subject;

            Console.WriteLine ("The Common Name for the SSL certificate did not match {0}. Instead, it was {1}.", host, cn);
            return false;
        }

        // The only other errors left are chain errors.
        Console.WriteLine ("The SSL certificate for the server could not be validated for the following reasons:");

        // The first element's certificate will be the server's SSL certificate (and will match the `certificate` argument)
        // while the last element in the chain will typically either be the Root Certificate Authority's certificate -or- it
        // will be a non-authoritative self-signed certificate that the server admin created. 
        foreach (var element in chain.ChainElements) {
            // Each element in the chain will have its own status list. If the status list is empty, it means that the
            // certificate itself did not contain any errors.
            if (element.ChainElementStatus.Length == 0)
                continue;

            Console.WriteLine ("\u2022 {0}", element.Certificate.Subject);
            foreach (var error in element.ChainElementStatus) {
                // `error.StatusInformation` contains a human-readable error string while `error.Status` is the corresponding enum value.
                Console.WriteLine ("\t\u2022 {0}", error.StatusInformation);
            }
        }

        return false;
    }
  • Related