0

I'm working in ASP.NET Core and using MailKit for email functionality. The method I've previously used is no longer working.

I have an SmtpOptions.cs class:

public class SmtpOptions
    {
        public string Server { get; set; } = "smtp.gmail.com";  //Gmail limited to 2000 emails per day
        public int Port { get; set; } = 465; //default for SSL using GMail
        public string User { get; set; } = "myEmail@gmail.com"; //must match server domain
        public string Password { get; set; } = "myPwd";
        public bool UseSsl { get; set; } = true; //gmail requires SSL
        public bool RequiresAuthentication { get; set; } = true; //gmail requires authentication
        public string PreferredEncoding { get; set; } = string.Empty;
    }

and EmailSender.cs class:

 public class EmailSender
    {
        public EmailSender()
        {
        }

        public async Task SendEmailAsync(
            SmtpOptions smtpOptions,
            string to,
            string from,
            string subject,
            string plainTextMessage,
            string htmlMessage,
            string replyTo = null)
        {
            if (string.IsNullOrWhiteSpace(to))
            {
                throw new ArgumentException("no to address provided");
            }

            if (string.IsNullOrWhiteSpace(from))
            {
                throw new ArgumentException("no from address provided");
            }

            if (string.IsNullOrWhiteSpace(subject))
            {
                throw new ArgumentException("no subject provided");
            }

            var hasPlainText = !string.IsNullOrWhiteSpace(plainTextMessage);
            var hasHtml = !string.IsNullOrWhiteSpace(htmlMessage);
            if (!hasPlainText && !hasHtml)
            {
                throw new ArgumentException("no message provided");
            }

            var m = new MimeMessage();

            m.From.Add(new MailboxAddress("", from));
            if (!string.IsNullOrWhiteSpace(replyTo))
            {
                m.ReplyTo.Add(new MailboxAddress("", replyTo));
            }
            m.To.Add(new MailboxAddress("", to));
            m.Subject = subject;

            //m.Importance = MessageImportance.Normal;
            //Header h = new Header(HeaderId.Precedence, "Bulk");
            //m.Headers.Add()

            BodyBuilder bodyBuilder = new BodyBuilder();
            if (hasPlainText)
            {
                bodyBuilder.TextBody = plainTextMessage;
            }

            if (hasHtml)
            {
                bodyBuilder.HtmlBody = htmlMessage;
            }

            m.Body = bodyBuilder.ToMessageBody();

            using (var client = new SmtpClient())
            {
                await client.ConnectAsync(
                    smtpOptions.Server,
                    smtpOptions.Port,
                    smtpOptions.UseSsl)
                    .ConfigureAwait(false);

                // Note: since we don't have an OAuth2 token, disable
                // the XOAUTH2 authentication mechanism.
                client.AuthenticationMechanisms.Remove("XOAUTH2");

                // Note: only needed if the SMTP server requires authentication
                if (smtpOptions.RequiresAuthentication)
                {
                    await client.AuthenticateAsync(smtpOptions.User, smtpOptions.Password)
                        .ConfigureAwait(false);
                }

                await client.SendAsync(m).ConfigureAwait(false);
                await client.DisconnectAsync(true).ConfigureAwait(false);
            }

        }

        public async Task SendMultipleEmailAsync(
            SmtpOptions smtpOptions,
            string toCsv,
            string from,
            string subject,
            string plainTextMessage,
            string htmlMessage)
        {
            if (string.IsNullOrWhiteSpace(toCsv))
            {
                throw new ArgumentException("no to addresses provided");
            }

            if (string.IsNullOrWhiteSpace(from))
            {
                throw new ArgumentException("no from address provided");
            }

            if (string.IsNullOrWhiteSpace(subject))
            {
                throw new ArgumentException("no subject provided");
            }

            var hasPlainText = !string.IsNullOrWhiteSpace(plainTextMessage);
            var hasHtml = !string.IsNullOrWhiteSpace(htmlMessage);
            if (!hasPlainText && !hasHtml)
            {
                throw new ArgumentException("no message provided");
            }

            var m = new MimeMessage();
            m.From.Add(new MailboxAddress("", from));
            string[] adrs = toCsv.Split(',');

            foreach (string item in adrs)
            {
                if (!string.IsNullOrEmpty(item)) { m.To.Add(new MailboxAddress("", item)); ; }
            }

            m.Subject = subject;
            m.Importance = MessageImportance.High;

            BodyBuilder bodyBuilder = new BodyBuilder();
            if (hasPlainText)
            {
                bodyBuilder.TextBody = plainTextMessage;
            }

            if (hasHtml)
            {
                bodyBuilder.HtmlBody = htmlMessage;
            }

            m.Body = bodyBuilder.ToMessageBody();

            using (var client = new SmtpClient())
            {
                await client.ConnectAsync(
                    smtpOptions.Server,
                    smtpOptions.Port,
                    smtpOptions.UseSsl).ConfigureAwait(false);

                // Note: since we don't have an OAuth2 token, disable
                // the XOAUTH2 authentication mechanism.
                client.AuthenticationMechanisms.Remove("XOAUTH2");

                // Note: only needed if the SMTP server requires authentication
                if (smtpOptions.RequiresAuthentication)
                {
                    await client.AuthenticateAsync(
                        smtpOptions.User,
                        smtpOptions.Password).ConfigureAwait(false);
                }

                await client.SendAsync(m).ConfigureAwait(false);
                await client.DisconnectAsync(true).ConfigureAwait(false);
            }

        }

    }

That are used in a function call:

public async void ContactMessage(string title, string message, string toEmail)
        {
            string thisMessage = "No Message Provided";
            if (!String.IsNullOrEmpty(message)) { thisMessage = message; } //in case empty form
            string thisTitle = title;
            //create email objects
            EmailSender emailSender = new EmailSender();
            SmtpOptions smtpOptions = new SmtpOptions(); //default settings ok
            string fromEmail = smtpOptions.User;

            string subjectLine = "Message Title";

            await emailSender.SendEmailAsync(smtpOptions, toEmail, fromEmail, subjectLine, thisMessage, "");
        }

As stated, this method has worked before but now I'm getting a failure of Gmail to respond. I've checked and have IMAP and POP enabled.

The specific exception reads: "System.Net.Internals.SocketExceptionFactory.ExtendedSocketE‌​xception: 'A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond'"

This code has not been deployed but causes this error in the test environment. Moving to a differently firewalled system causes the error "Mailkit.Security.Authentication; MailKit authentication is too weak"

Testing with Yahoo! smtp allows the above code to work so it seems like the compatibility between Mailkit and Gmail has changed. What is the appropriate Mailkit configuration for using Gmail?

coolhand
  • 1,876
  • 5
  • 25
  • 46
  • If it worked before and now doesn't and you didn't change anything on your code or gmail settings, don't you think you should contact the google support about it? StackOverflow is for programming related questions and you did not even provide the exact errors that you get – Tseng Dec 28 '17 at 21:54
  • Sorry if I wasn't clear enough. This is an instance of code reuse; it worked before in a WebForms application but now I am trying it asp.net core MVC. I'm asking here because I'm new to ASP.NET Core and thought it may have to do with difference between frameworks. The exact exception is: "System.Net.Internals.SocketExceptionFactory.ExtendedSocketException: 'A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond'" – coolhand Dec 28 '17 at 22:03
  • Better update the exception in the answer, not everyone reads every single comment when reading your question. Also there is too much information missing, does that happen when you test locally, or after deploying? Does your Webform application still run with the exact same code? Also WinForms run on .NET Framework whereas ASP.NET Core runs on .NET Core by default. Does the same error happens when you run ASP.NET Core 2.0 targeting .NET Framework? – Tseng Dec 28 '17 at 23:17
  • It’s likely to be a firewall issue or something. – jstedfast Dec 28 '17 at 23:37

2 Answers2

1

The email account settings were not configured to allow use of less-secure apps. The two solutions are:

1) Obtain OAuth 2.0 credentials within the EmailSender.cs class, or 2) Change email account settings to allow less secure apps

There are more details at: How to send email by using MailKit?

coolhand
  • 1,876
  • 5
  • 25
  • 46
0

Generally, when you get an AuthenticationException saying that the AUTH mechanism was too weak, it means that the client tried to use the PLAIN or LOGIN mechanisms and the server only allows those mechanisms to be used over SSL.

Make sure you are connecting on port 465 with SSL enabled or on port 587 with SecureSocketOptions.StartTls as the third argument.

jstedfast
  • 35,744
  • 5
  • 97
  • 110