Mono SmtpClient - Message could not be sent

Posted by Blake on 2/11/2015
)

I was writing a program to have my Raspbery Pi send me a message a few times a day letting me know that it was up and running and connected to the network (e.g. I wouldn't get the message if it wasn't). The idea being that the headless appliance without a keyboard, mouse or monitor could let me know that everything was running fine. My program was sending mail find when I would run it manually from the terminal but would fail when I ran it from a cronjob with this exception:

Message could not be sent

After some research I found that the failures had to do with certificates and there were a few things I had to do (two terminal commands and then one change to my mono/.net code). First, here are the two commands to deal with certificate issues (you may need to sudo these):

mozroots --import --ask-remove
certmgr -ssl smtps://smtp.gmail.com:465

In my .Net/mono code I had to add before my SMTP clients sending of the message. I will include both the VB.Net and the C# calls:

VB.Net (Mono)

ServicePointManager.ServerCertificateValidationCallback = Function(s As Object, certificate As X509Certificate, chain As X509Chain, sslPolicyErrors As SslPolicyErrors) True

C# (Mono)

ServicePointManager.ServerCertificateValidationCallback = delegate(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };

To be complete, I'll include a VB.Net and C# example of a Using block that should be all you need to send a message:

VB.Net (Mono)

Using smtp As New SmtpClient("smtp.gmail.com", 587)
    smtp.EnableSsl = True
    smtp.DeliveryMethod = SmtpDeliveryMethod.Network
    smtp.UseDefaultCredentials = False
    smtp.Credentials = New NetworkCredential("youraddress@gmail.com", "yourpassword")
    Using msg As New MailMessage("youraddress@gmail.com", "somebody@somewhere.com", "Your Subject", "Your Message Body")
        ' If the body is HTML
        msg.IsBodyHtml = True

        ' this is required to fix the "Message could not be sent" exception when running in croin
        ServicePointManager.ServerCertificateValidationCallback = Function(s As Object, certificate As X509Certificate, chain As X509Chain, sslPolicyErrors As SslPolicyErrors) True
        smtp.Send(msg)
    End Using
End Using

C# (Mono)

using (SmtpClient smtp = new SmtpClient("smtp.gmail.com", 587)) 
{
    smtp.EnableSsl = true;
    smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
    smtp.UseDefaultCredentials = false;
    smtp.Credentials = new NetworkCredential("youraddress@gmail.com", "yourpassword");
    
    using (MailMessage msg = new MailMessage("youraddress@gmail.com", "somebody@somewhere.com", "Your Subject", "Your Message Body")) 
    {
        // If the body is HTML
        msg.IsBodyHtml = true;

        // this is required to fix the "Message could not be sent" exception when running in croin
        ServicePointManager.ServerCertificateValidationCallback =
                delegate(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
                { return true; };

        smtp.Send(msg);
    }
}

Both of these require if not fully referenced imports to System.Security.Cryptography.X509Certificates.