MailkitTools 1.2.0

dotnet add package MailkitTools --version 1.2.0
NuGet\Install-Package MailkitTools -Version 1.2.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MailkitTools" Version="1.2.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add MailkitTools --version 1.2.0
#r "nuget: MailkitTools, 1.2.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install MailkitTools as a Cake Addin
#addin nuget:?package=MailkitTools&version=1.2.0

// Install MailkitTools as a Cake Tool
#tool nuget:?package=MailkitTools&version=1.2.0

mailkit-tools

MailkitTools provides e-mail services built on top of the popular MailKit library. These services are ideal to use within any .NET Core project that requires e-mail services, such as sending messages with an SMTP client and receiving e-mails with a POP3 client.

Simplified email services support

If you have a pre-configured email client (i.e., static configuration), you may immediately send messages using the IConfiguredEmailService. In a .NET 6 or later framework, you can initialize all email services using the following statement (in the Program.cs file of an ASP.NET Core 6+ Razor Pages project, for instance): builder.Services.AddMailkitTools(builder.Configuration.GetSection(nameof(EmailClientConfiguration)).Get<EmailClientConfiguration>());

The above statement adds a singleton service of type IEmailClientConfiguration, a transient service of type IConfiguredEmailService and the new default IEmailConfigurationProvider service, named DefaultEmailConfigurationProvider.

using MailkitTools;
using MailkitTools.DependencyInjection;

namespace MyEmailProject;

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // Add services to the container.
        builder.Services.AddRazorPages();

        // add default pre-configured email services; this statement relies
        // on a matching configuration section in the appsettings.config file
        // named EmailClientConfiguration.
        builder.Services.AddMailkitTools(builder.Configuration.GetSection(nameof(EmailClientConfiguration)).Get<EmailClientConfiguration>());

        var app = builder.Build();
        // rest of the code omitted for brevity
    }
}

Using IConfiguredEmailService

Within a controller or PageModel, you can send an email as shown in the following code sample (in a Contact.cshtml page):

using MailkitTools;
using MailkitTools.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace MyEmailProject.Pages;

public class ContactModel : PageModel
{
    private readonly ILogger<ContactModel> _logger;
    private readonly IConfiguredEmailService _emailService;
    private readonly IConfiguration _configuration;

    public ContactModel(ILogger<ContactModel> logger, IConfiguredEmailService emailService, IConfiguration configuration)
    {
        _logger = logger;
        _emailService = emailService;
        _configuration = configuration;
    }

    public async Task<IActionResult> OnPostAsync(ContactFormModel model)
    {
        try
        {
            var fromAddr = _configuration[$"{nameof(EmailClientConfiguration)}:UserName"];
            var sendto = _configuration[$"{nameof(EmailClientConfiguration)}:SendTo"];

            var message = "A contact form has been submitted on example.com<br/>" +
                $"Name : {model.Name}<br/>" +
                $"Email : {model.Email}<br/>" +
                $"Subject : {model.Subject}<br/><br/>" +
                $"{model.Message}";

            var result = await _emailService.SendMessageAsync(fromAddr, sendto, model.Subject, message);
                
            if (result)
                return Content("OK");
            else
            {
                if (_emailService.LastError != null)
                    _logger.LogError("Error while sending an email: {message}", _emailService.LastError);

                return Content("Your message has not been sent.");
            }
        }
        catch (Exception ex)
        {
            _logger.LogError("{message}", ex);
            return BadRequest(ex);
        }
    }
}

public class ContactFormModel
{
    public string Name { get; set; } = null!;
    public string Email { get; set; } = null!;
    public string Subject { get; set; } = null!;
    public string Message { get; set; } = null!;
}

The Contact.cshtml page's content may resemble the following:

<form method="post" role="form">
    <div class="row">
        <div class="form-group col-md-6">
            <label for="name">Your Name</label>
            <input type="text" name="Name" class="form-control" id="name" required>
        </div>
        <div class="form-group col-md-6">
            <label for="email">Your Email</label>
            <input type="email" class="form-control" name="Email" id="email" required>
        </div>
    </div>
    <div class="form-group">
        <label for="subject">Subject</label>
        <input type="text" class="form-control" name="Subject" id="subject" required>
    </div>
    <div class="form-group">
        <label for="message">Message</label>
        <textarea class="form-control" name="Message" id="message" rows="10" required></textarea>
    </div>
    <div class="text-center"><button type="submit">Send</button></div>
</form>

In the appsettings.json configuration file (update appropriately):

{
    "EmailClientConfiguration": {
    "Host": "smtp.example.com",
    "Port": 465,
    "UseSsl": true,
    "RequiresAuth": true,
    "UserName": "username@example.com",
    "Password": "some secure password",
    "SendTo": "info@example.com"
  }
}

Getting started with the email sender:

You can still use the IEmailSender service, and an implementation of the interface is now included in the source. Here's a simplified implementation of the MailkitTools.IEmailConfigurationProvider interface:

using MailkitTools;
using Microsoft.Extensions.Options;
using System.Threading;
using System.Threading.Tasks;

public class EmailConfigurationProvider : EmailConfigurationProviderBase
{
    private readonly IEmailClientConfiguration _clientConfig;

    public EmailConfigurationProvider(IOptions<EmailClientConfiguration> clientConfig)
    {
        _clientConfig = clientConfig.Value;
    }

    public override Task<IEmailClientConfiguration> GetConfigurationAsync(CancellationToken cancellationToken = default)
    {
        // normally, you would retrieve the settings from a (file or database) store;
        return Task.Run(() => _clientConfig);
    }
}

In Startup.cs:

using MailkitTools.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        // ...
        services.AddMailkitTools<EmailConfigurationProvider>();

        // Don't forget to add a section named "EmailClientConfiguration" in the appsettings.json file
        services.Configure<EmailClientConfiguration>(Configuration.GetSection(nameof(EmailClientConfiguration)));
        // ...
    }
}

In the appsettings.json configuration file (update appropriately):

{
    "EmailClientConfiguration": {
    "Host": "smtp.example.com",
    "Port": 25,
    "UseSsl": false,
    "RequiresAuth": false,
    "UserName": "username@example.com",
    "Password": "some secure password"
  }
}

Somewhere in a Models folder...


public class EmailModel
{
    public string Subject { get; set; }
    public string Body { get; set; }
    public string From { get; set; }
    [System.ComponentModel.DataAnnotations.Required]
    public string To { get; set; }
}

public class TestEmailModel
{
    public EmailModel Message { get; set; }
    public EmailClientConfiguration Config { get; set; }
}

... and a controller (if applicable):

using System.Threading.Tasks;
using MailkitTools;
using MailkitTools.Services;
using Microsoft.AspNetCore.Mvc;

public class EmailController : Controller
{
    private readonly IEmailClientService _emailClient;
    private readonly IEmailConfigurationProvider _emailConfigProvider;

    public EmailController(IEmailClientService emailClient, IEmailConfigurationProvider emailConfigProvider)
    {
        _emailClient = emailClient;
        _emailConfigProvider = emailConfigProvider;
    }

    [HttpPost]
    public Task<IActionResult> Send([FromBody] EmailModel model)
    {
        return SendMessageAsync(model);
    }

    [HttpPost]
    public Task<IActionResult> Test([FromBody] TestEmailModel model)
    {
        return SendMessageAsync(model.Message, model.Config);
    }

    protected async Task<IActionResult> SendMessageAsync(EmailModel model, IEmailClientConfiguration config = null)
    {
        if (config == null)
            config = await _emailConfigProvider.GetConfigurationAsync();
        _emailClient.Configuration = config;

        // check the ControllerExtensions class below
        return await this.SendEmailAsync(model, _emailClient);
    }
}

You can even improve reusability using an extension method:

using System;
using System.Net.Sockets;
using System.Threading.Tasks;
using MailKit;
using MailKit.Security;
using MailkitTools.Services;
using Microsoft.AspNetCore.Mvc;

/// <summary>
/// Provides extension methods for instances of the <see cref="Controller"/> class.
/// </summary>
public static class ControllerExtensions
{
    private static string SmtpServerRequiresAuth = "The SMTP server requires authentication.";
    private static string SmtpServerDoesNotSupportSsl = "The SMTP server does not support SSL.";
    private static string SmtpHostUnreachable = "The SMTP host {0} is not reachable.";

    /// <summary>
    /// Asynchronously sends an e-mail on behalf of the given controller using the specified parameters.
    /// </summary>
    /// <param name="controller">The controller that initiated the action.</param>
    /// <param name="model">An object used to create the message to send.</param>
    /// <param name="emailClient">An object used to send the e-mail.</param>
    /// <returns></returns>
    public static async Task<IActionResult> SendEmailAsync(this Controller controller, EmailModel model, IEmailClientService emailClient)
    {
        var config = emailClient.Configuration;
        try
        {
            var message = EmailClientService.CreateMessage(
                model.Subject,
                model.Body,
                model.From,
                model.To
            );

            await emailClient.SendEmailAsync(message);
            return controller.Ok();
        }
        catch (ServiceNotAuthenticatedException ex)
        {
            if (true == config?.RequiresAuth)
                return controller.BadRequest(new ServiceNotAuthenticatedException(SmtpServerRequiresAuth));
            return controller.BadRequest(ex);
        }
        catch (SslHandshakeException ex)
        {
            if (true == config?.UseSsl)
                return controller.BadRequest(new SslHandshakeException(SmtpServerDoesNotSupportSsl));
            return controller.BadRequest(ex);
        }
        catch (SocketException)
        {
            return controller.BadRequest(new Exception(string.Format(SmtpHostUnreachable, config?.Host)));
        }
        catch (Exception ex)
        {
            return controller.BadRequest(ex);
        }
    }
}
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

NuGet packages (1)

Showing the top 1 NuGet packages that depend on MailkitTools:

Package Downloads
MailkitTools.DependencyInjection

Provides MailkitTools extension methods for the Microsoft.Extensions.DependencyInjection.IServiceCollection type.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.2.0 438 8/12/2023
1.1.2 862 12/12/2021
1.1.1 683 7/8/2020
1.1.0 377 7/8/2020
1.0.0 420 7/7/2020

1.1.0: Lower target framework from netcoreapp3.1 to netstandard2.0
1.2.0: Add simplified default email services.