-1

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.

1
  • 1) MimeKit is open source on GitHub, so you might dig into its source code. 2) The last function call on the stack is MailKit.Net.Smtp.SmtpClient.ParseMessageDataResponse, so likely the response from that SMTP server was malformed so that MimeKit couldn't parse it properly. You might want to dig further into that. Commented May 9 at 21:32

2 Answers 2

1

maybe try it like this
the duplicate

multipart.Add(multipartAlt);

may have been confusing it

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"], fromEmail ?? _configuration["Smtp:FromEmail"]));

    foreach (var email in toEmail)
    {
        mail.To.Add(new MailboxAddress("", email));
    }

    mail.Subject = subject;

    var plain = new TextPart("plain") { Text = textPart };
    var html = new TextPart("html") { Text = htmlPart };

    var multipartAlt = new MultipartAlternative();
    multipartAlt.Add(plain);
    multipartAlt.Add(html);

    mail.Body = multipartAlt; // No need for a 'mixed' container unless you're adding attachments

    using (var client = await GetSmtpClient())
    {
        await client.SendAsync(mail);
        await client.DisconnectAsync(true);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.