34

I'm developing a mail client for a school project. I have managed to send e-mails using the SmtpClient in C#. This works perfectly with any server but it doesn't work with Gmail. I believe it's because of Google using TLS. I have tried setting EnableSsl to true on the SmtpClient but this doesn't make a difference.

This is the code I am using to create the SmtpClient and send an e-mail.

this.client = new SmtpClient("smtp.gmail.com", 587);
this.client.EnableSsl = true;
this.client.UseDefaultCredentials = false;
this.client.Credentials = new NetworkCredential("username", "password");

try
{
    // Create instance of message
    MailMessage message = new MailMessage();

    // Add receiver
    message.To.Add("myemail@mydomain.com");

    // Set sender
    // In this case the same as the username
    message.From = new MailAddress("username@gmail.com");

    // Set subject
    message.Subject = "Test";

    // Set body of message
    message.Body = "En test besked";

    // Send the message
    this.client.Send(message);

    // Clean up
    message = null;
}
catch (Exception e)
{
    Console.WriteLine("Could not send e-mail. Exception caught: " + e);
}

This is the error I am getting when I try to send an e-mail.

Could not send e-mail. Exception caught: System.Net.Mail.SmtpException: Message could not be sent. ---> System.IO.IOException: The authentication or decryption has failed. ---> System.InvalidOperationException: SSL authentication error: RemoteCertificateNotAvailable, RemoteCertificateChainErrors
  at System.Net.Mail.SmtpClient.<callback>m__4 (System.Object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, SslPolicyErrors sslPolicyErrors) [0x00000] in <filename unknown>:0 
  at System.Net.Security.SslStream+<BeginAuthenticateAsClient>c__AnonStorey7.<>m__A (System.Security.Cryptography.X509Certificates.X509Certificate cert, System.Int32[] certErrors) [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.SslClientStream.OnRemoteCertificateValidation (System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Int32[] errors) [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.SslStreamBase.RaiseRemoteCertificateValidation (System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Int32[] errors) [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.SslClientStream.RaiseServerCertificateValidation (System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Int32[] certificateErrors) [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.validateCertificates (Mono.Security.X509.X509CertificateCollection certificates) [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.ProcessAsTls1 () [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.Handshake.HandshakeMessage.Process () [0x00000] in <filename unknown>:0 
  at (wrapper remoting-invoke-with-check) Mono.Security.Protocol.Tls.Handshake.HandshakeMessage:Process ()
  at Mono.Security.Protocol.Tls.ClientRecordProtocol.ProcessHandshakeMessage (Mono.Security.Protocol.Tls.TlsStream handMsg) [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0 
  --- End of inner exception stack trace ---
  at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0 
  --- End of inner exception stack trace ---
  at System.Net.Mail.SmtpClient.Send (System.Net.Mail.MailMessage message) [0x00000] in <filename unknown>:0 
  at P2Mailclient.SMTPClient.send (P2Mailclient.Email email) [0x00089] in /path/to/my/project/SMTPClient.cs:57 

Does anyone have an idea why I might be getting this error?

simonbs
  • 7,932
  • 13
  • 69
  • 115

6 Answers6

25

Gmail's SMTP server requires you to authenticate your request with a valid gmail email/password combination. You do need SSL enabled as well. Without actually being able to see a dump of all your variables being passed in the best guess I can make is that your Credentials are invalid, make sure you're using a valid GMAIL email/password combination.

You might want to read here for a working example.

EDIT: Okay here's something I wrote and tested just then and it worked fine for me:

public static bool SendGmail(string subject, string content, string[] recipients, string from) {
    if (recipients == null || recipients.Length == 0)
        throw new ArgumentException("recipients");

    var gmailClient = new System.Net.Mail.SmtpClient {
        Host = "smtp.gmail.com",
        Port = 587,
        EnableSsl = true,
        UseDefaultCredentials = false,
        Credentials = new System.Net.NetworkCredential("******", "*****")
    };

    using (var msg = new System.Net.Mail.MailMessage(from, recipients[0], subject, content)) {
        for (int i = 1; i < recipients.Length; i++)
            msg.To.Add(recipients[i]);

        try {
            gmailClient.Send(msg);
            return true;
        }
        catch (Exception) {
            // TODO: Handle the exception
            return false;
        }
    }
}

If you need any more info there's a similar SO article here

Community
  • 1
  • 1
Jason Larke
  • 5,289
  • 25
  • 28
  • I'm sure that my credentials are write. I have tried copy/pasting them into the Gmail log in box and was able to log in. I have updated my question to show a simplified version of my code with the values of the variables hard coded. – simonbs Mar 21 '12 at 09:15
  • @SimonBS are you using just your google username or the full email address for your Credentials? I believe logging in from a non-Google domain requires the full email address to log in – psubsee2003 Mar 21 '12 at 09:22
  • I am using the entire email. E.g. `myusername@gmail.com`. – simonbs Mar 21 '12 at 09:25
  • 1
    @SimonBS and you have POP enabled in your gmail account? – psubsee2003 Mar 21 '12 at 09:27
  • I am at work at the moment so I don't have C# right now to play around with. When I get home I'll have a look and see if I can write you a working example and edit my answer appropriately. – Jason Larke Mar 21 '12 at 09:28
  • @JasonLarke That sounds great! Thank you very much. I have been struggling with this for days. – simonbs Mar 21 '12 at 09:30
  • @psubsee2003 Yes, both POP and IMAP is activated but would that matter when I'm only using SMTP at the moment? – simonbs Mar 21 '12 at 09:44
  • @SimonBS it probably shouldn't, but since I was able to make your code work without an exception, it seemed like a possibility – psubsee2003 Mar 21 '12 at 09:48
  • @JasonLarke Thank you, but sadly this gives me exactly the same. – simonbs Mar 21 '12 at 15:26
  • Perfect answer. Works too. – Tejasvi Hegde Nov 19 '15 at 13:35
23

Try running this:

mozroots --import --ask-remove

in your system (just in bash or from Mono Command Prompt if it is on Windows). And then run the code again.

EDIT:

I forgot you also should run

certmgr -ssl smtps://smtp.gmail.com:465

(and answer yes on questions). This works for me on Mono 2.10.8, Linux (with your example).

konrad.kruczynski
  • 46,413
  • 6
  • 36
  • 47
  • 1
    This adds 140 "new root certificates" to my "trust store" but it doesn't solve the issue but thanks for your answer. – simonbs Mar 21 '12 at 15:12
  • I'm sorry for the late response. This did the trick! Thank you very much. I just gotta make sure. If anyone runs my software, will they have to runs these commands to use the software? That's not really ideal. For a school project, it doesn't matter much, but I would like to know so that I can put it in my rapport :-) – simonbs Mar 28 '12 at 07:48
  • @SimonBS: They will have or not - that depends specifically on the OS/distribution used and their policy. Everything is quite well described (with reasons :)) here: http://www.mono-project.com/FAQ:_Security – konrad.kruczynski Mar 28 '12 at 20:32
  • Thanks, both, for this little tidbit ... very helpful and accurate on OSX and Ubuntu. Best to both ... – Tom Winans Nov 08 '12 at 22:18
7

You need to enable 2-Step Verification in your gmail account and create an app password (https://support.google.com/accounts/answer/185833?hl=en). Once you replace your password with the new app password, it should work.

Credentials = new System.Net.NetworkCredential("your email address", "your app password");
Poet
  • 71
  • 1
  • 1
  • For me, this was the actual solution, as Google Accounts, specifically, don't allow an application to log in on user's behalf to send an email. Thank you. – Max Sorin Aug 06 '17 at 13:30
4

I think, you need to validate the server certificate that is used to establish the SSL connections.....

Use following code to send mail with validating server certificate.....

            this.client = new SmtpClient(_account.SmtpHost, _account.SmtpPort);
            this.client.EnableSsl = _account.SmtpUseSSL;
            this.client.Credentials = new NetworkCredential(_account.Username, _account.Password);

        try
        {
            // Create instance of message
            MailMessage message = new MailMessage();

            // Add receivers
            for (int i = 0; i < email.Receivers.Count; i++)
                message.To.Add(email.Receivers[i]);

            // Set sender
            message.From = new MailAddress(email.Sender);

            // Set subject
            message.Subject = email.Subject;

            // Send e-mail in HTML
            message.IsBodyHtml = email.IsBodyHtml;

            // Set body of message
            message.Body = email.Message;

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


            // Send the message
            this.client.Send(message);

            // Clean up
            message = null;
        }
        catch (Exception e)
        {
            Console.WriteLine("Could not send e-mail. Exception caught: " + e);
        }

Import System.Security.Cryptography.X509Certificates namespace to use ServicePointManager

  • Yeah, when I tried the code without validating X509Certificates,it worked fine for me too.....But sometime,when trying ssl connection, it need the validation of certificates..... –  Mar 21 '12 at 10:23
  • colleague of mine just had trouble sending an e-mail from a Mono application on Android through our e-mail server. This fixed the problem. Awesome! – Steffen Winkler Mar 18 '14 at 10:06
  • This was the fix for me also. I could run my Mono app and send mail from the command prompt but once it went to cron it stopped working. The x509 line fixed that issue when running from cron. – b.pell Feb 10 '15 at 21:57
3

This code works fine for me, try pasting this into LinqPad, edit the mail addresses and password and tell us what you see:

var client = new System.Net.Mail.SmtpClient("smtp.gmail.com", 587);
client.EnableSsl = true;
client.UseDefaultCredentials = false;
client.Credentials = new System.Net.NetworkCredential("me@gmail.com", "xxxxxxx");

try
{
    // Create instance of message
    System.Net.Mail.MailMessage message = new System.Net.Mail.MailMessage();

    // Add receiver
    message.To.Add("me@gmail.com");

    // Set sender
    // In this case the same as the username
    message.From = new System.Net.Mail.MailAddress("me@gmail.com");

    // Set subject
    message.Subject = "Test";

    // Set body of message
    message.Body = "En test besked";

    // Send the message
    client.Send(message);

    // Clean up
    message = null;
}
catch (Exception e)
{
    Console.WriteLine("Could not send e-mail. Exception caught: " + e);
}
rasmusvhansen
  • 1,452
  • 1
  • 12
  • 13
  • I'm on a Mac and don't have LinqPad. All I use is MonoDevelop. Using the code above gives me the exact same. – simonbs Mar 21 '12 at 10:43
  • @SimonBS you might want to retag the question with Mono. That could be part of the problem since it seems multiple people have managed to get the same code working in VS. – psubsee2003 Mar 21 '12 at 11:23
  • @psubsee2003 You might be right. I didn't think of that. I'm still very new to C# and didn't think the IDE would matter. I have retagged it now. – simonbs Mar 21 '12 at 11:28
  • @SimonBS I've never used done any work outside of VisualStudio, so I don't know if the fact that you are using MonoDevelop would matter, but given the facts, it seems like the next thing to check – psubsee2003 Mar 21 '12 at 11:31
1

I started getting this with GMail in May 2013 after working for 6 momths. The Mono project's Using Trusted Roots Respectfully document provided guidance on work around. I chose option #1:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

It is too disruptive to have e-mail for my service stop working without warning.

Update Aug 26 2016: user Chico suggested the following complete implementation of the ServerCertificateValidationCallback callback. I have not tested.

ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;

bool MyRemoteCertificateValidationCallback(System.Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
    bool isOk = true;
    // If there are errors in the certificate chain, look at each error to determine the cause.
    if (sslPolicyErrors != SslPolicyErrors.None) {
        for (int i=0; i<chain.ChainStatus.Length; i++) {
            if (chain.ChainStatus [i].Status != X509ChainStatusFlags.RevocationStatusUnknown) {
                chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
                chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan (0, 1, 0);
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
                bool chainIsValid = chain.Build ((X509Certificate2)certificate);
                if (!chainIsValid) {
                    isOk = false;
                }
            }
        }
    }
    return isOk;

}
t9mike
  • 1,546
  • 2
  • 19
  • 31
  • Whilst this would indeed get around the service issue and provide a method by which you would not have an interrupted service, it also removes all aspects of security by saying I don't care about the certificate. Thus, a MITM attack could quite easily listen in on your communication without additional checks in the callback to verify the "untrusted" certificate is definitely one you want to trust. – netniV Apr 30 '15 at 14:55