.netasp.net-web-apimimekit

Issue with sending emails with MimeKit


I've been trying to send a 'forgot password' email for my website. I am using a template html file with replaced text to send new randomized credentials to a user. I have so far been unable to send any emails out. I am fairly certain my credentials are okay as we are using the same to send emails in multiple applications that are in production. However, these applications are using other methods to send the mails (they are quite old).

This is my MailService.cs class:

using MimeKit;
using WebApi.Data;
using WebApi.Interfaces;

namespace WebApi.Services;
public class MailService : IMailService
{
    private readonly IConfiguration _configuration;
    private readonly OperationsManagerDbContext _context;
    public MailService(OperationsManagerDbContext operationsManagerDbContext, IConfiguration configuration)
    {
        _context = operationsManagerDbContext;
        _configuration = configuration;
    }

    private async Task<MailKit.Net.Smtp.SmtpClient> GetSmtpClient()
    {
        var smtpClient = new MailKit.Net.Smtp.SmtpClient();
        await smtpClient.ConnectAsync(_configuration["Smtp:Host"], Convert.ToInt32(_configuration["Smtp:Port"]), MailKit.Security.SecureSocketOptions.StartTls);
        await smtpClient.AuthenticateAsync(_configuration["Smtp:Username"], _configuration["Smtp:Password"]);
        return smtpClient;
    }

    async Task IMailService.SendEmailAsync(List<string> toEmail, string subject, string textPart, string htmlPart, string? fromEmail)
    {
        var mail = new MimeMessage();
        mail.From.Add(new MailboxAddress(_configuration["Smtp:FromName"], _configuration["Smtp:FromEmail"]));
        foreach (var email in toEmail)
        {
            mail.To.Add(new MailboxAddress("", email));
        }

        mail.Subject = subject;
        
        var multipart = new Multipart("mixed");
        var multipartAlt = new MultipartAlternative();

        var plain = new TextPart("plain");
        plain.SetText(System.Text.Encoding.UTF8, textPart);
        multipartAlt.Add(plain);

        var html = new TextPart("html");
        html.SetText(System.Text.Encoding.UTF8, htmlPart);
        multipartAlt.Add(html);
  
        multipart.Add(multipartAlt);

        multipart.Add(multipartAlt);

        mail.Body = multipart;

        using (var client = await GetSmtpClient())
        {
            await client.SendAsync(mail);
            await client.DisconnectAsync(true);
        }
    }

}

The error is as follows:

2025-05-09 23:18:32.951 [ 1:    Error]
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware - An unhandled exception has occurred while executing the request.
Stack Trace:
   at MailKit.Net.Smtp.SmtpClient.ParseMessageDataResponse(MimeMessage message, SmtpResponse response)
   at MailKit.Net.Smtp.SmtpClient.MessageDataAsync(FormatOptions options, MimeMessage message, Int64 size, CancellationToken cancellationToken, ITransferProgress progress)
   at MailKit.Net.Smtp.SmtpClient.SendAsync(FormatOptions options, MimeMessage message, MailboxAddress sender, IList`1 recipients, CancellationToken cancellationToken, ITransferProgress progress)
   at MailKit.Net.Smtp.SmtpClient.SendAsync(FormatOptions options, MimeMessage message, MailboxAddress sender, IList`1 recipients, CancellationToken cancellationToken, ITransferProgress progress)
   at WebApi.Services.MailService.WebApi.Interfaces.IMailService.SendEmailAsync(List`1 toEmail, String subject, String textPart, String htmlPart, String fromEmail) in F:\Work\Repos\Dev_Web\Angular\Emqube\operationsmanager\WebApi\Services\MailService.cs:line 55
   at WebApi.Services.AuthService.ForgotPassword(SiteUserForgotPasswordRequest siteUserForgotPasswordRequest) in F:\Work\Repos\Dev_Web\Angular\Emqube\operationsmanager\WebApi\Services\AuthService.cs:line 207
   at WebApi.Controllers.AuthController.ForgotPassword(SiteUserForgotPasswordRequest siteUserForgotPasswordRequest) in F:\Work\Repos\Dev_Web\Angular\Emqube\operationsmanager\WebApi\Controllers\AuthController.cs:line 53
   at lambda_method240(Closure, Object)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

My guess is that somehow I am providing the wrong format. I have tried passing a simple string using the following:

mail.Body = new TextPart("plain")
{
    Text = "some text"
};

However, I get the same error. Any resources to point me in the right direction would be appreciated.


Solution

  • As the comment from @Lex Li suggested. The issue was due to a malformed response from the SMTP server. For some reason I had it stuck in my head that the issue was the request and did not think to blame it on bad configuration as my client was connecting without errors. Long story short, I was using an Office365 which did not play nicely with the package. I switched to a Gmail account and things worked with no further changes to the code.