En el desarrollo de software empresarial enviar correos electrónicos con documentos adjuntos o con un diseño personalizados es un requerimiento muy frecuente, en este tutorial te mostramos enviar correos usando C# y .NET Core. Usaremos Visual Studio Code como nuestro editor de código pero si así lo prefieres puedes usar Visual Studio. Actualmente existen varias paquetes de Nuget para enviar correos como SendGrid o MailKit, sin embargo en este tutorial se utiliza la clase SmtpClient parte de .NET Standard 2.0.

Revisando el correo electrónico

Este artículo representa una guía paso a paso para enviar un correo electrónico usando C# y una cuenta de Gmail. El cuerpo del correo puede estar formateado como texto plano o HTML e incluir archivos adjuntos. Se asume que tienes instalado el SDK de .NET Core y el editor de código Visual Studio Code. Adicionalmente se creará una solución para poder abrir el proyecto con Visual Studio 2019.

Se creará una biblioteca de clases que tiene como única función enviar correos. Después se usa esta clase en un proyecto de consola. Esta clase se puede usar en cualquier otro tipo de proyectos que soporte .NET Standard. El caso de uso cubre está clase es : Una aplicación tiene asignada una cuenta de correo con la cuál envía todos los correos al destinatario especificado.

Advertencia El equipo de .NET ha marcado la clase SmtpClient como obsoleta. En su lugar recomiendan usar MailKit.

Configuración de Gmail

Es necesario permitir el acceso a aplicaciones no seguras desde la configuración de Gmail tal como se describe en la documentación de Gmail. Ya que si no lo habilitas recibirás una alerta de seguridad por parte de Google indicando que una aplicación diferente a Gmail ha accedido a tu correo y la aplicación te mostrara este mensaje.

The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.0 Authentication Required. Learn more at

Pantalla de configuracion de Gmail

La configuración necesaria para el cliente de SMTP de acuerdo a la documentación de Gmail es la siguiente:

Parámetro Valor
Servidor de correo saliente (SMTP) smtp.gmail.com
Requiere TLS Sí (si está disponible)
Requiere autenticación
Puerto para TLS/STARTTLS 587
Nombre completo o nombre mostrado Tu nombre
Nombre de la cuenta, nombre de usuario o dirección de correo electrónico Tu dirección de correo electrónico completa
Contraseña Tu contraseña de Gmail

Esta configuración se almacenará un archivo XML que la aplicación leerá al momento que se crear una instancia de la clase. Esto tiene como propósito hacer la aplicación no incluya valores que pueden cambiar en código duro configuración y en caso de ser necesario actualizar la contraseña o cambiar la cuenta no sea necesario recompilar la aplicación nuevamente.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <host>smtp.gmail.com</host>
  <port>587</port>
  <user>[email protected]</user>
  <password>contraseñagmail</password>
  <enableSsl>true</enableSsl>
</configuration>

Cliente SMTP para .NET Framework

Si requieres enviar un correo en usando el .NET Framework en lugar de .NET Core puedes ver mi articulo Enviar un correo con C# y Gmail: Windows Forms. Aquí se utiliza el archivo de configuración App.config para guardar los datos de la cuenta de gmail. Si usas un proyecto web puedes usar lo mismo en el Web.config.

Preparando el proyecto con dotnet y Visual Studio Code

Para crear la estructura del proyecto usando .NET Core ejecuta en la terminal o consola los siguientes comandos. Ejecuta línea por línea ya que se colocarón más de un comando por descripción.

Se creará una solución llamada EnviarCorreo y dos proyectos, el primero una biblioteca de clases llamada EmailService y el segundo proyecto es una aplicación de consola llamada EmailServiceCliente.

dotnet new sln -o EnviarCorreo
dotnet new classlib -o EnviarCorreo/EmailService
dotnet new console -o EnviarCorreo/EmailServiceCliente

Para agregar los proyectos a la solución ejecuta los siguientes comandos

dotnet sln EnviarCorreo/EnviarCorreo.sln add EnviarCorreo/EmailServiceCliente/EmailServiceCliente.csproj
dotnet sln EnviarCorreo/EnviarCorreo.sln add EnviarCorreo/EmailServiceCliente/EmailServiceCliente.csproj

El proyecto EmailServiceCliente necesita una referencia al proyecto EmailService para poder utilizarlo.

 dotnet add EnviarCorreo/EmailServiceCliente/EmailServiceCliente.csproj reference EnviarCorreo/EmailService/EmailService.csproj

Abrir la carpeta EnviarCorreo\EmailService (cd EnviarCorreo\EmailService) y agregar la referencia al paquete de Nuget Microsoft.Extensions.Configuration.Xml esta es necesaria para poder leer el archivo XML.

dotnet add package Microsoft.Extensions.Configuration.Xml

Crear un nuevo archivo llamado Configuracion.xml xml (Windows type NUL > Configuration.xml , Linux touch Configuracion.xml).

Abrir la carpeta EnviarCorreo con Visual Studio Code. Los .. especifican el directorio un directorio arriba del actual EnviarCorreo\EmailService.

code ..

Editar el archivo del proyecto EmailService/EmailService.csproj para agregar el siguiente código antes de la etiqueta de cierre de </Project>. Este hace que siempre coloque el archivo de configuración en la carpeta de salida del proceso de compilación

<ItemGroup>
    <None Update="Configuracion.xml">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
</ItemGroup>

Código biblioteca de clases

Esta clase esta compuesta por 2 campos y una propiedad. En el constructor se inicializa la propiedad Configuration responsable de leer los archivos de configuración XML y se inicialize el cliente SMTP con los parámetros de configuración.

El método EnviarCorreo(string , string , string ,bool esHtlm = false) utiliza un parámetro opcional que define si el mensaje es HTML. Por default enviá texto. El método EnviarCorreo(MailMessage) esta pensado para poder construir un objecto MailMessage y poder aprovechar todas las capacidades este objecto como adjuntar archivos

using Microsoft.Extensions.Configuration;
using System;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;

namespace EnviarCorreoElectronico
{
    public class GestorCorreo
    {
        private SmtpClient cliente;
        private static IConfiguration Configuration { get; set; }
        private MailMessage email;
        public GestorCorreo()
        {
            InicializaConfiguracion();
            cliente = new SmtpClient(Configuration["host"], Int32.Parse(Configuration["port"]))
            {
                EnableSsl = Boolean.Parse(Configuration["enableSsl"]),
                DeliveryMethod = SmtpDeliveryMethod.Network,
                UseDefaultCredentials = false,
                Credentials = new NetworkCredential(Configuration["user"], Configuration["password"])
            };
        }
        private static void InicializaConfiguracion()
        {
            var builder = new ConfigurationBuilder()
                                    .SetBasePath(Directory.GetCurrentDirectory())
                                    .AddXmlFile("Configuracion.xml");
            Configuration = builder.Build();
        }
        public void EnviarCorreo(string destinatario, string asunto, string mensaje,bool esHtlm = false)
        {
            email = new MailMessage(Configuration["user"], destinatario, asunto, mensaje);
            email.IsBodyHtml = esHtlm;
            cliente.Send(email);
        }
        public void EnviarCorreo(MailMessage message)
        {
            cliente.Send(message);
        }
        public async Task EnviarCorreoAsync(MailMessage message)
        {
            await cliente.SendMailAsync(message);
        }
    }
}

Código Aplicación de consola

En la aplicación de consola se muestra como usar la clase GestorCorreo para enviar un correo con datos adjuntos, uno con solo texto y otro con formato HTML. Puedes utilizar un archivo HTML como plantilla personalizar con el nombre del cliente e invocar este método para enviar correo.

using System;
using EmailService;
using System.Net.Mail;
using System.Net.Mime;

namespace EmailServiceCliente
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                GestorCorreo gestor = new GestorCorreo();
                
                //Correo con archivos adjuntos
                MailMessage correo = new MailMessage("[email protected]",
                                                     "[email protected]",
                                                     "Archivo de configuracíon",
                                                     "Por favor verificar adjunto.");

                string ruta = "Configuracion.xml";
                Attachment adjunto = new Attachment(ruta, MediaTypeNames.Application.Xml);
                correo.Attachments.Add(adjunto);
                gestor.EnviarCorreo(correo);

                // Correo con HTML
                gestor.EnviarCorreo("[email protected]",
                                    "Prueba",
                                    "Mensaje en texto plano");
                // Correo de texto  
                gestor.EnviarCorreo("[email protected]",
                                    "Prueba",
                                    "<h1>Mensaje en HTML<h1><p>Contenido</p>",
                                    true);
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

Imagen del correo enviado

Para ejecutar el proyecto abre la terminal en la carpeta EmailServiceCliente y ejecuta el comando

dotnet run

Enviar correos en ASP.NET Core

En el caso de que requieras enviar correos en un aplicacion de ASP.NET Core es necesario usar la inyección de dependencias que viene integrada en el mismo framework y usar el archivo appsettins.json para manejar la configuración. Aquí muestro una forma de hacerlo en un proyecto web haciendo uso del patrón opciones

Agregar la configuración del correo en el archivo appsettings.json

"EmailSenderOptions": {
    "Port": "587",
    "Password": "contraseñagmail",
    "EnableSsl": "true",
    "Email": "[email protected]",
    "Host": "smtp.gmail.com"
  }

Posteriormente creamos una clase en la carpeta Services llamada EmailSenderOptions. Esta clase nos ayudara a leer los datos de configuración del archivo json

namespace App.Services
{
    public class EmailSenderOptions
    {
        public int Port { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public bool EnableSsl { get; set; }
        public string Host { get; set; }
    }
}

Posteriormente creamos una interfaz para el servicio de envío de correos y una implementación de la misma. En este caso la interfaz esta en una carpeta llamada interfaces

namespace App.Interfaces
{
    public interface IEmailSender
    {
        Task SendEmailAsync(string email, string subject, string message);
    }
}

La clase que implementa esta interfaz se encuentra en la carpeta Services. Nota el constructor de la clase

using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using App.Interfaces;

namespace App.Services
{
    public class EmailSender : IEmailSender
    {
        private SmtpClient Cliente { get; }
        private EmailSenderOptions Options { get; }

        public EmailSender(IOptions<EmailSenderOptions> options)
        {
            Options = options.Value;
            Cliente = new SmtpClient()
            {
                Host = Options.Host,
                Port = Options.Port,
                DeliveryMethod = SmtpDeliveryMethod.Network,
                UseDefaultCredentials = false,
                Credentials = new NetworkCredential(Options.Email, Options.Password),
                EnableSsl = Options.EnableSsl,
            };
        }

        public Task SendEmailAsync(string email, string subject, string message)
        {
            var correo = new MailMessage(from:Options.Email,to:email,subject: subject, body:message);
            correo.IsBodyHtml = true;
            return Cliente.SendMailAsync(correo);
        }
    }
}

En la clase Startuphay que agregar y configura este servicio al contendedor de dependencias para que este disponible en nuestra aplicación web.

services.AddTransient<IEmailSender, EmailSender>();
services.Configure<EmailSenderOptions>(Configuration.GetSection("EmailSenderOptions"));

Con lo anterior el servicio para enviar correos ya esta disponible solo debemos especificar en el constructor la dependencia que necesitamos. Por ejemplo en un controlador:

 public class HomeController : Controller
{
    private readonly IEmailSender _emailSender;
    public HomeController(IEmailSender emailSender,)
    {
        _emailSender = emailSender;
    }
}

Finalmente para enviar un correo en un método de acción de forma asíncrona.

public async Task<IActionResult> Index()
{
    await _emailSender
        .SendEmailAsync("[email protected]", "Asunto","Mensaje")
        .ConfigureAwait(false);

    return View();
}

Clonar el repositorio usando Visual Studio 2019 Community Edition

Si estas apurado y necesitas revisar rápidamente el código te dejo una guia de como clonarlo usando Visual Studio 2019.

  1. En la ventana de inicio de Visual Studio seleccionar la opción Clonar un repositorio.
  2. Ingresar la URL https://github.com/jahbenjah/CodigoBlog en el cuadro de texto Ubicación del repositorio.
  3. Elegir la ruta donde se desea copiar el repositorio. En este caso es C:\Users\benjaminc\Source\Repos
  4. Abrir la solución EnviarCorreo.

Versión en video

Si prefiere ver un video que usa .NET 6 y una aplicación de consola puedes ver:

Conclusión

Puedes encontrar el código fuente el el repositorio de Github.