ASP.NET Core - Enviando emails com Mailkit em uma API


 Hoje veremos como enviar email usando o Mailkit em um projeto ASP .NET Core Web API.

O MailKit é uma biblioteca cliente de email .NET multiplataforma e de código-fonte baseada no MimeKit e otimizada para dispositivos móveis. O seu objetivo é fornecer ao mundo .NET implementações de clientes SMTP, POP3 e IMAP robustas, completas e compatíveis com RFC.


Neste artigo vou apresentar um tutorial de como usar esta biblioteca para enviar email em uma API usando o ambiente do .NET 6 e o VS Code.

Criando o projeto no VS Code

Abra uma janela de comandos e crie uma pasta onde deseja armazenar o projeto.

A seguir verifique se você possui o SDK para o .NET 6 instalado :  dotnet --version

Para criar o projeto usando o template ASP .NET Core Web API digite o comando:

dotnet new webapi --name ApiEmail

Este comando criou o projeto Web API na pasta ApiEmail.

Vamos entrar na pasta ApiEmail , listar o seu conteúdo e a seguir incluir no projeto o pacote do MailKit usando o comando:

dotnet add package MailKit



Com isso teremos o pacote do MailKit incluído no projeto. Vamos abrir o projeto no VS code digitando:  code.

Com isso veremos o projeto aberto no VS Code e selecionando o arquivo de projeto APiEmail.csproj veremos os pacotes incluídos no projeto:

Vamos remover do projeto o controlador WeatherForecast e a classe de mesmo nome, pois não vamos usá-los.

A seguir vamos criar as configurações SMTP (Simple Mail Transfer Protocol) no arquivo appsettings.json onde para este exemplo vou usar a configuração do Gmail da minha conta usando a minha senha do Gmail. Se você tiver um servidor SMTP personalizado, basta substituir a porta e o servidor, bem como outros campos necessários.

Vamos criar no projeto a pasta Entities e nesta pasta a classe StmpSettings onde vamos armazenar as configurações SMTP obtidas a partir do arquivo appsettings.json.

namespace apiemail.Entities;

public class SmtpSettings
{
    public string? Server { get; set; }
    public int Port { get; set; }
    public string? SenderName { get; set; }
    public string? SenderEmail { get; set; }
    public string? Username { get; set; }
    public string? Password { get; set; }
}

A seguir vamos criar uma pasta Services no projeto e definir uma interface ISendEmail com o contrato para enviar o email.

namespace apiemail.Services;

public interface ISendEmail
{
    Task SendEmailAsync(string email, string subject, string body);
}

A seguir vamos criar a classe concreta SendEmail que implementa esta interface:

using apiemail.Entities;
using MailKit.Net.Smtp;
using Microsoft.Extensions.Options;
using MimeKit;

namespace apiemail.Services
{
    public class SendEmail : ISendEmail
    {
        private readonly SmtpSettings _smtpSettings;
        private readonly IWebHostEnvironment _env;

        public SendEmail(IOptions<SmtpSettings> smtpSettings, IWebHostEnvironment env)
        {
            _smtpSettings = smtpSettings.Value;
            _env = env;
        }

        public async Task SendEmailAsync(string email, string subject, string body)
        {
            try
            {
                var message = new MimeMessage();

                message.From.Add(new MailboxAddress(_smtpSettings.SenderName,
                                                    _smtpSettings.SenderEmail));
                message.To.Add(new MailboxAddress("destino",email));
                message.Subject = subject;
                message.Body = new TextPart("html")
                {
                    Text = body
                };

                using (var client = new SmtpClient())
                {
                    client.ServerCertificateValidationCallback = (s, c, h, e) => true;

                    if (_env.IsDevelopment())
                    {
                        await client.ConnectAsync(_smtpSettings.Server,
                                                  _smtpSettings.Port, true);

                    }
                    else
                    {
                        await client.ConnectAsync(_smtpSettings.Server);
                    }

                    await client.AuthenticateAsync(_smtpSettings.Username,
                                                   _smtpSettings.Password);
                    await client.SendAsync(message);
                    await client.DisconnectAsync(true);

                }
            }
            catch (Exception e)
            {
                throw new InvalidOperationException(e.Message);
            }
        }
    }
}

A seguir vamos registrar o serviço no container DI na classe Program:

using apiemail.Entities;
using apiemail.Services;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.Configure<SmtpSettings>(builder.Configuration
                                         .GetSection("SmtpSettings"));
builder.Services.AddSingleton<ISendEmail, SendEmail>();

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

Aqui estamos obtendo os valores da configuração STMP a partir da seção SmtpSettings no arquivo appsettings.json e registrando o serviço para enviar o email.

Criando o Controller EmailsController

Vamos criar o controlador EmailsController e definir um endpoint para testar a nossa implementação.

using apiemail.Services;
using Microsoft.AspNetCore.Mvc;

namespace apiemail.Controllers
{
    [Route("[controller]")]
    [ApiController]
    public class EmailsController : ControllerBase
    {
        private readonly ILogger<EmailsController> _logger;
        private readonly ISendEmail _sendEmail;

        public EmailsController(ILogger<EmailsController> logger,
                                ISendEmail sendEmail)
        {
            _logger = logger;
            _sendEmail = sendEmail;
        }

        [HttpGet]
        [Route("sendemail")]

        public async Task<IActionResult> TestEmail(string email, string
                                                   subject, string body
)
        {
            try{
              await _sendEmail.SendEmailAsync(email, subject, body);
              _logger.LogInformation($"{StatusCodes.Status200OK}
                                           - Email enviado com sucesso");
              return Ok("Email enviado com sucesso !!!");
            }
            catch(Exception ex)
            {
                _logger.LogError(ex.Message);
                return BadRequest("Erro ao enviar o email");
            }
        }      
    }
}

Neste código injetamos o serviço ISendEmail no construtor e usando uma instância do serviço estamos enviando o email utilizando os parâmetros email, subject e body que serão preenchidos pelo usuário.

 await _sendEmail.SendEmailAsync(email, subject, body);


Agora podemos abrir um terminal no VS Code e digitar : dotnet run

Veremos a seguinte interface do Swagger exibida no navegador :

Vamos testar informando os dados para email , subject e body e clicar em Execute.

Fazendo isso vamos obter o resultado abaixo:

Vemos que o email foi enviado com sucesso para o endereço de destino.

Podemos conferir abrindo o email recebido:

Pegue o projeto completo aqui : ApiEmail.zip (sem as referências)

"Jesus, porém, olhando para eles, disse: Para os homens é impossível, mas não para Deus, porque para Deus todas as coisas são possíveis."
Marcos 10:27

Referências:


José Carlos Macoratti