I'm facing an issue when trying to send emails using the MailKit library in an ASP.NET Core application. The emails are sent successfully on my local machine, but when I deploy the application to a remote server (IIS), I encounter the following exception:
Exception: Failed to send the email: The SMTP server has unexpectedly disconnected. EmailSender Class:
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options;
using MimeKit;
using MimeKit.Text;
using System;
using System.Threading.Tasks;
using MailKit.Security;
namespace syngri_web_app.Services
{
public class EmailSender : IEmailSender
{
private readonly MailgunSettings _mailgunSettings;
public EmailSender(IOptions<MailgunSettings> mailgunSettings)
{
_mailgunSettings = mailgunSettings.Value;
}
public async Task SendEmailAsync(string email, string subject, string htmlMessage)
{
try
{
var mimeMessage = new MimeMessage();
mimeMessage.From.Add(new MailboxAddress("Excited Admin", "foo@" + _mailgunSettings.Domain));
mimeMessage.To.Add(new MailboxAddress("Excited User", email));
mimeMessage.Subject = subject;
mimeMessage.Body = new TextPart(TextFormat.Html)
{
Text = htmlMessage
};
using (var client = new MailKit.Net.Smtp.SmtpClient())
{
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
await client.ConnectAsync("smtp.mailgun.org", 587, SecureSocketOptions.StartTls);
client.AuthenticationMechanisms.Remove("XOAUTH2");
await client.AuthenticateAsync("postmaster@"+_mailgunSettings.Domain+"", _mailgunSettings.ApiKey);
await client.SendAsync(mimeMessage);
await client.DisconnectAsync(true);
}
}
catch (Exception ex)
{
// Log the exception details
Console.WriteLine("An exception occurred while sending the email: " + ex.ToString());
if (ex.InnerException != null)
{
Console.WriteLine("Inner Exception: " + ex.InnerException.ToString());
}
throw new Exception("Failed to send the email: " + ex.Message);
}
}
}
}
Controller Code:
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Forget(UserDto request)
{
if (ModelState.IsValid)
{
var user = await userManager.FindByEmailAsync(request.Email);
if (user != null && !user.EmailConfirmed)
{
ModelState.AddModelError("message", "Email not confirmed yet");
ItoastNotification.Error("Something went Wrong");
return View(request);
}
if (user == null) {
ModelState.AddModelError("message", "Email not Exist");
ItoastNotification.Error("Something went Wrong, Please inter valid email");
return View(request);
}
var code = await userManager.GeneratePasswordResetTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Action(
"ResetPassword",
"Account",
new { area = "", code, request.Email },
protocol: Request.Scheme
);
var emailMessage = $"Please reset your password by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.";
await emailSender.SendEmailAsync(request.Email, "Reset Password", emailMessage);
ItoastNotification.Success("Reset Email Has been Sent Please Check your Email");
return RedirectToAction("Login");
}
foreach (var error in ModelState.Values.SelectMany(v => v.Errors))
{
// Handle or log the validation error messages
var errorMessage = error.ErrorMessage;
ItoastNotification.Error("Something went Wrong: "+errorMessage);
break;
}
return View(request);
}
I've verified that the SMTP server settings are correct, and the emails are successfully sent from my local machine. However, the issue arises only when deploying to the remote server.
I resolved my issue by updating my emailSender class with the following code:
var smtpClient = new SmtpClient("smtp.mailgun.org")
{
Port = 587,
Credentials = new NetworkCredential(_mailgunSettings.UserName, _mailgunSettings.Password),
EnableSsl = false
};
var mailMessage = new MailMessage
{
From = new MailAddress("hello@gmail.io"),
Subject = subject,
Body = formattedHtmlMessage,
IsBodyHtml = true
};
mailMessage.To.Add(email);
await smtpClient.SendMailAsync(mailMessage);