When is it necessary to enable SSL on MailKit - c#

I read on the Microsoft website that the SmtpClient was obsolete and they recommended using the MailKit for it's replacement.
I'm in the process of writing an application to make use of the MailKit.
This is what I have so far:
// *************** SEND EMAIL *******************
using (var client = new MailKit.Net.Smtp.SmtpClient())
{
//accept all SSL certificates
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.Connect(emailSettings.SmtpServer, emailSettings.SmtpPort, emailSettings.IsSslEnabled);
if (emailSettings.IsAuthenticationRequired)
{
// Note: only needed if the SMTP server requires authentication
client.Authenticate(emailSettings.SmtpUsername, emailSettings.SmtpPassword);
}
// timeout = 20 seconds
client.Timeout = 20000;
client.Send(message);
client.Disconnect(true);
}
When I set this part:
client.Connect(emailSettings.SmtpServer, emailSettings.SmtpPort, emailSettings.IsSslEnabled);
the last parameter is bool useSSL, which I set to true. My email server is hosted by Rackspace so I know that it uses SSL. When I set this option to true, it fails to send but if I set this option to false, it sends fine.
Shouldn't this line catch the certificate type:
client.ServerCertificateValidationCallback
If so, why wouldn't useSSL on the connect not work? Do I need to set the useSSL to false? I'm confused on how the useSSL works when I have the line above.

Mail protocols (SMTP, IMAP, and POP3) all have 2 different ways of doing SSL.
System.Net.Mail.SmtpClient only implemented support for the STARTTLS way of doing SSL whereas MailKit does both.
When you specify useSsl as true in MailKit's Connect method, it assumes that you meant to use an SSL-wrapped connection (which is different from STARTTLS).
To make this less confusing, MailKit has a Connect method that takes a SecureSocketOptions argument instead of a bool.
The options are as follows:
None: Don't use any form of SSL (or TLS).
Auto: Automatically decides which type of SSL mode to use based on the specified port. Note: This only works reliable when the port is a standard defined port (e.g. 25, 587 or 465 for SMTP).
SslOnConnect: This specifies that MailKit should connect via an SSL-wrapped connection.
StartTls: Use the STARTTLS method for SSL/TLS encryption. If the server doesn't support the STARTTLS command, abort the connection.
StartTlsWhenAvailable: Use the STARTTLS method for SSL/TLS encryption if the server supports it, otherwise continue using an unencrypted channel.
Since you are using SMTP, you might find this useful:
Port 25 was the original port used for SMTP and it originally only supported unencrypted communications.
Later, administrators and users demanded SSL encryption so admins and mail clients started supporting SSL-wrapped connections on port 465 because this was very easy to do for admins (no server software needed to be upgraded and clients that didn't support SSL-wrapped connections could continue connecting on port 25).
After a few years of this, mail protocol authors introduced the STARTTLS command extension for IMAP, SMTP and POP3 (well, for POP3, the command is STLS but it is otherwise the same thing) that clients could optionally use if they supported it. This extension only made sense on the original (non-SSL-wrapped) ports.
These days STARTTLS is the preferred method for encrypting communications between a client and a mail server, but SSL-wrapped ports are still in wide use as well.
MailKit treats port 587 the same as it treats 25. In other words, it treats port 25 and 587 as a plain-text connection port but will switch to SSL/TLS if requested to do so via STARTTLS.

Related

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

I'm trying to access gmail emails using imap and the code is failing at the ssl handshake without showing me any errors. Really appreciate if anyone could please help with this. I've built this using xunit, .NET Core 2.1. I'm using MailKit Nuget
public GMailHandler(string mailServer, int port, bool ssl, string login, string password)
//mailServer = imap.gmail.com
//port = 993
//ssl = true
{
if (ssl)
Client.Connect(mailServer, port);
else
Client.Connect(mailServer, port);
Client.Authenticate(login, password);
Client.Inbox.Open(FolderAccess.ReadOnly);
}
Here's a copy & paste from the MailKit FAQ:
Q: Why do I get "MailKit.Security.SslHandshakeException: An error occurred while attempting to establish an SSL or TLS connection." when I try to Connect?
When you get an exception with that error message, it usually means that you are encountering
one of the following scenarios:
1. The mail server does not support SSL on the specified port.
There are 2 different ways to use SSL/TLS encryption with mail servers.
The first way is to enable SSL/TLS encryption immediately upon connecting to the
SMTP, POP3 or IMAP server. This method requires an "SSL port" because the standard
port defined for the protocol is meant for plain-text communication.
The second way is via a STARTTLS command (aka STLS for POP3) that is optionally
supported by the server.
Below is a table of the protocols supported by MailKit and the standard plain-text ports
(which either do not support any SSL/TLS encryption at all or only via the STARTTLS
command extension) and the SSL ports which require SSL/TLS encryption immediately upon a
successful connection to the remote host.
|Protocol|Standard Port|SSL Port|
|:------:|:-----------:|:------:|
| SMTP | 25 or 587 | 465 |
| POP3 | 110 | 995 |
| IMAP | 143 | 993 |
It is important to use the correct SecureSocketOptions for the port that you are connecting to.
If you are connecting to one of the standard ports above, you will need to use SecureSocketOptions.None,
SecureSocketOptions.StartTls or SecureSocketOptions.StartTlsWhenAvailable.
If you are connecting to one of the SSL ports, you will need to use SecureSocketOptions.SslOnConnect.
You could also try using SecureSocketOptions.Auto which works by choosing the appropriate option to use
by comparing the specified port to the ports in the above table.
2. The mail server that you are connecting to is using an expired (or otherwise untrusted) SSL certificate.
Often times, mail servers will use self-signed certificates instead of using a certificate that
has been signed by a trusted Certificate Authority. Another potential pitfall is when locally
installed anti-virus software replaces the certificate in order to scan web traffic for viruses.
When your system is unable to validate the mail server's certificate because it is not signed
by a known and trusted Certificate Authority, the above error will occur.
You can work around this problem by supplying a custom RemoteCertificateValidationCallback
and setting it on the client's ServerCertificateValidationCallback
property.
In the simplest example, you could do something like this (although I would strongly recommend against it in
production use):
using (var client = new SmtpClient ()) {
client.ServerCertificateValidationCallback = (s,c,h,e) => true;
client.Connect (hostName, port, SecureSocketOptions.Auto);
// ...
}
Most likely you'll want to instead compare the certificate's Thumbprint
property to a known value that you have verified at a prior date.
You could also use this callback to prompt the user (much like you have probably seen web browsers do)
as to whether or not the certificate should be trusted.
3. A Certificate Authority CRL server for one or more of the certificates in the chain is temporarily unavailable.
Most Certificate Authorities are probably pretty good at keeping their CRL and/or OCSP servers up 24/7, but occasionally
they do go down or are otherwise unreachable due to other network problems between you and the server. When this happens,
it becomes impossible to check the revocation status of one or more of the certificates in the chain.
To ignore revocation checks, you can set the
CheckCertificateRevocation
property of the IMAP, POP3 or SMTP client to false before you connect:
using (var client = new SmtpClient ()) {
client.CheckCertificateRevocation = false;
client.Connect (hostName, port, SecureSocketOptions.Auto);
// ...
}
4. The server does not support the same set of SSL/TLS protocols that the client is configured to use.
MailKit attempts to keep up with the latest security recommendations and so is continuously removing older SSL and TLS
protocols that are no longer considered secure from the default configuration. This often means that MailKit's SMTP,
POP3 and IMAP clients will fail to connect to servers that are still using older SSL and TLS protocols. Currently,
the SSL and TLS protocols that are not supported by default are: SSL v2.0, SSL v3.0, and TLS v1.0.
You can override MailKit's default set of supported
SSL and TLS protocols
by setting the value of the SslProtocols
property on your SMTP, POP3 or IMAP client.
For example:
using (var client = new SmtpClient ()) {
// Allow SSLv3.0 and all versions of TLS
client.SslProtocols = SslProtocols.Ssl3 | SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;
client.Connect ("smtp.gmail.com", 465, true);
// ...
}
await client.ConnectAsync(_emailConfig.SmtpServer, _emailConfig.Port, false);
just set the "useSsl" option to false in the client configuration
Disbaled Avast antivorus software .
This works for me
I solved a similar problem by going through the protocols. As a result, I found out that the MS Exchange server uses Tls 1.0 for backward compatibility. I explicitly set the protocol and the connection passed.
var client = new ImapClient();
client.SslProtocols = System.Security.Authentication.SslProtocols.Tls;
client.Connect("servername", 993, SecureSocketOptions.SslOnConnect);

How to check if a recipient email address domain has TLS implemented?

We are trying to check if a recipient email id (domain of a given email id) has TLS implemented or not. If not implemented we cannot send the email. Is there any way in C# to check it? e.g. Following is a service where we can enter any email id and it will tell us if that email domain has TLS implemented or not. https://www.checktls.com/TestReceiver How to do this in C#? C# email client comes with the property smtpClient.EnableSsl = true; question is what will happen if at the recipient side the TLS is not implemented? Will it fail or it will go through? If it fails that's what we want. Our SMTP server has TLS implemented.
I tried STARTTLS command and EHLO from telnet. It gives 250 STARTTLS, which tells me that the destination server has TLS implemented. How to do it programmatically?
smtpClient.EnableSsl = true;
If you use a library like MailKit, you can do this:
bool supportsStartTls;
using (var client = new SmtpClient ()) {
client.Connect ("smtp.host.com", 587, SecureSocketOptions.None);
supportsStartTls = client.Capabilities.HasFlag (SmtpCapabilities.StartTls);
client.Disconnect (true);
}
If you want to use MailKit to send mail, you have full control over what happens if STARTTLS is not available.
For example, if you wanted it to fail if STARTTLS is not supported, then use SecureSocketOptions.StartTls as the third argument to the Connect method.
If you want MailKit to use STARTTLS when it is available but not fail if it isn't, then use SecureSocketOptions.StartTlsWhenAvailable instead.

Getting an error when trying to connect to SMTP server "199.201.221.19"

I am using the following code and getting an error when trying to connect to SMTP server. I am not giving any authentication credentials to access that.
var client = new SmtpClient()
await client.ConnectAsync("199.201.221.19", 587, false);
client.Send(mail);
Host:199.201.221.19
Port:587
Error: System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
What is the actual issue and what is the possible solution for this?
The error refers to an SSL/TLS certificate validation error. It means that your server's SSL certificate does not verify using .NET's standard Root CA certificates.
Even though you have specified useSsl as false in your ConnectAsync() method call, MailKit will still toggle into TLS-mode if the server supports STARTTLS. The useSsl parameter is really only useul in telling MailKit whether or not the port requires SSL from the very start (as in ssl-wrapped ports such as 993 for IMAP/S, 995 for POP/S and 465 for SMTP/S).
You have 2 options for fixing this problem:
Follow the directions for this error in the FAQ: https://github.com/jstedfast/MailKit/blob/master/FAQ.md#InvalidSslCertificate
use a different ConnectAsync method that allows you to specify not to try STARTTLS: client.ConnectAsync (host, port, SecureSocketOptions.None);

How can I send E-mail with a ssl type connection cryptography

I'm trying to send an e-mail with MailMessage and smtpclient class with enablessl = true, but I receive timeout on every connection.
setting it in outlook, there is an option "use de following type of connection cryptography", which have the following options: none, ssl, tls or automatic.
choosing the option ssl I can send e-mail throught the outlook.
How can I do it in C#?
You probably need to set Port property to match the protocol used.
You can probably get along with STARTTLS on port 25, while for SMTPS (encrypted connection from start, that is, "SSL") you need port 465.
EDIT:
As it turns out, SmtpClient does not support this method of SSL.
From the documentation:
An alternate connection method is where an SSL session is established
up front before any protocol commands are sent. This connection method
is sometimes called SMTP/SSL, SMTP over SSL, or SMTPS and by default
uses port 465. This alternate connection method using SSL is not
currently supported.
See here
So that you SHOULD use STARTTLS, which involves switching back to port 25.
You might also try port 587.

Sending email from a .net application via a mail server with a self-signed SSL certificate

I installed hmailserver 5.3.2 and configured it. It receives and sends
emails normally, but I wanted to use it to send emails from a .net/C#
application located in another server, and for that I wanted to use
SSL communication. Before, the application was configured to send
emails via gmail, on port 587 and it worked ok, but now we want to use
our own mail server. We first configured the application to connect on
smtp.domain.com on port 25 and that works, it sends the email.
Then we
created a self signed certificate to test the if we could send the
message through a secure channel.I created the certificate with
openSSL setting common name as: mail.domain.com, smtp.domain.com,
*.domain.com, domain.com. I opened port 587 on the firewall and
configured hmailserver to use a certificate for inbound connections on
that port.
None of the certificates I created worked (I tried one and then
created another one and so on), generating the following (generic) exception in the
application:
System.Exception: _COMPlusExceptionCode = -532459699
Of course I also tried to connect via telnet: telnet smtp.domain.com
587, and I just got a blank screen. It is not a firewall issue since
when I disable the ssl on port 587 I can connect normally.
Looking at the log doesn't even show an attempt to connect when using
587 with SSL.
I already checked these questions: Getting SmtpClient to work with a self signed SSL certificate and Using a self-signed certificate with .NET’s HttpWebRequest/Response, but it didn't solve my problem. The approach with ServerCertificateValidationCallback didn't have any influence.
I tried with ports 25 (which is also proposed in one of the questions above), 465, 587, and with all 3 it happens the same: The initial handshake (SYN / SYN-ACK / ACK) and after about 80s the connection is closed (FIN), nothing in between.
Do I have to install that certificate somewhere so the .net application sees it as trusted? I mean, I already installed it as a Trusted Root Certification Authority and could check by running mmc, so I have no idea where to go now...
Thanks for the help!
PS: Not sure if this belongs to ServerFault since it concerns a C# application but also a mail server...
EDIT: Code sample:
ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, sslPolicyErrors) => true;
SmtpClient mailClient = new SmtpClient("smtp.domain.com");
mailClient.Credentials = new NetworkCredential("username#domain.com", "pwd");
mailClient.Port = 587;
mailClient.EnableSsl = true;
MailMessage mailMessage = new MailMessage("mailAddressFrom", "mailAddressTo", "subject", "body");
mailMessage.IsBodyHtml = true;
mailClient.Send(mailMessage);
EDIT 2: Log (Based on Ramunas' suggestion):
"TCPIP" 3588 "2010-06-23 10:02:49.685" "TCPConnection - Posting AcceptEx on 0.0.0.0:465"
"DEBUG" 3588 "2010-06-23 10:02:49.809" "Creating session 24039"
"TCPIP" 772 "2010-06-23 10:04:29.639" "TCPConnection - SSL handshake with client failed. Error code: 2, Message: End of file, Remote IP: X"
"DEBUG" 772 "2010-06-23 10:04:29.639" "Ending session 24039"
currently, you can not send mail using c# 4/.NET 4 to a hMailServer regardless whether the certificate used by hMailServer is purchased or self-signed.
the problem is two part AFAIK ... c# 4/.NET 4 will only send using TLS and port 587; hMailServer does not currently support STARTTLS. c# 4/.NET 4 does not support the alternative of 465/SSL.
see this thread "configuring SSL confusion ..." at hMailServer's forum.
"SmtpClient.EnableSsl Property ":
"An alternate connection method is where an SSL session is established up front before any protocol commands are sent. This connection method is sometimes called SMTP/SSL, SMTP over SSL, or SMTPS and by default uses port 465. This alternate connection method using SSL is not currently supported." -- MSDN
As gerryLowry said:
c# 4/.NET 4 will only send using TLS and port 587;
hMailServer does not currently support STARTTLS
You can update your hMailServer to hMailServer 5.5.1 (BETA) here
It now supports STARTTLS and with port 587 all is working correctly.
This is a sophisticated mechanism but in simple words client (computer you're making connection from) should know about WHO is certificate issuer (in your case your server is certificate issuer). If it does not find it in it's Trusted Root Certificate Authorities list then it considers this connection to be unsafe. (I bet you've seen browser warning you about unsafe request to some https://.... site).
Open Certificates snap-in in your Microsoft management console on a client computer and try to add the same self signed certificate to a Trusted Root Certificate Authorities list.
I installed hMailServer, created self signed certificate, added it to hMailServer and was not able to send mail via it, too. Though I was successful while sending emails without certificate.
I enabled logging on hMailServer (for everything) and tried again with no luck. But I saw an error in a log file stating
"Severity: 2 (High), Code: HM5113,
Source: TCPServer::Run(), Description:
Failed to load certificate file. Path:
<...>test.cer,
Address: 0.0.0.0, Port: 25, Error: An
invalid argument was supplied"
Maybe this is a case on your hMailServer also?
I have port 25 as normal SMTP open on my hMailServer as well as port 465 for SSL, so I had to change my code to point to the normal SMTP configuration. It should work after that. As for SSL, sorry, it won't work on hMailServer...
MailMessage message = new MailMessage();
message.From = new MailAddress("me#myself.home", "Me");
message.Body = "hello, World!";
message.To.Add(new MailAddress("you#myself.home", "You"));
SmtpClient client = new SmtpClient("secure.myself.home", 25);
client.EnableSsl = false;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential("me#myself.home", "pwd");
client.Send(message);

Categories