Enviar emails usando plantillas con sintaxis Razor

Para ser sincero, desde siempre el envío de emails ha sido una de las cosas que más he odiado del mundo de la programación No sé por qué... quizás porque siempre me fallaba algo, usar plantillas/templates era demasiado trabajoso...

Hasta ahora lo solucionaba usando NVelocity para rellenar los templates y el IIS para enviarlos... y creedme que los templates para el NVelocity eran un complejo XML difícil de tratar y con versiones para HTML y texto plano con duplicación de textos... un infierno de mantenimiento.

Así que ante un nuevo proyecto que requiere envío de emails he hecho lo que en principio parece más difícil, aunque realmente es lo más fácil: hacerle caso a Punset, desaprender.

Así que me puse a buscar librerías que me solucionaran el problema. Las premisas que me marqué son las siguientes:
- Plantillas con sintaxis Razor
- Sin dependencias con MVC
- Que la solución esté en nuget
- Extremadamente fácil de usar

El objetivo de este artículo no es sino ahorraros tiempo. He probado más de 6 librerías y definitivamente me quedo con FluentEmail (nuget / github) de lukencode.

Su uso es muy sencillo... y encima es Fluent:

Email
   .FromDefault()
   .To("email@destino.com")
   .Subject("Asunto del email")
   .UsingTemplateFromFile(Server.MapPath("~/MailTemplates/Template.cshtml"), model)
   .Send();

- FromDefault: coge los parámetros por defecto del MailSettings del web.config.
- To: los destinos a quienes va el email. Puede ser un string un listado de strings. También tenemos los métodos BB y BCC
- Subject: el asunto, surprise!
- UsingTemplateFromFile: apuntamos a un fichero .cshtml, la típica view de Razor, vamos. También tenemos la propiedad UsingTemplate, donde en lugar de la url a un fichero le damos directamente el texto.
- Send: envía el email, y SendAsync lo hace de forma asíncrona.

¿En algún momento he dicho Razor? ¡Nooop!
Con la propiedad UsingTemplateEngine podemos elegir el motor de templates que queremos usar... vale, y por defecto es Razor :D


¿Y quién hace el envío?, ¿El IIS?
Pues podríamos, sin problemas... pero personalmente me he enamorado de sendgrid. No hay más que crearse una cuenta (si lo haces desde azure tiene algunos miles de emails gratis al mes) y configurar tu web.config con algo como esto:

<system.net>
  <mailSettings>
    <smtp from="email@origen.com">
      <network host="smtp.sendgrid.net" password="sendgridpassword" userName="sendgriusername" port="587" />
    </smtp>
  </mailSettings>
</system.net>



¿Qué más me cuentas?
Lo primero es que FluentEmail no está preparado para trabajar con IoC y poder testear... pero vamos, problemas cero. Lo metemos nosotros en un servicio, le sacamos una bonita interfaz y ale, a fakear y/o mokear al gusto.

Lo segundo es que, personalmente, odio los magic strings a niveles enfermizos. Vamos, que poner "~/MailTemplates/Template.cshtml" me mata. Por eso aprovecho el T4MVC (nuget / codeplex) para acabar poniendo MailTemplates._AboutYourProject2TaC_cshtml

El único detalle es que los mailtemplates los pongo dentro del directorio "MailTemplates", y añado "<FileFolder>MailTemplates</FileFolder>" al elemento StaticFilesFolder del T4MVC.tt.settings.xml

Para los que hayáis trabajado con T4MVC sabréis que esto último solo sirve si la carpeta "MailTemplates" está en el mismo proyecto que el T4MVC. Si no es así y sacáis los templates a otro proyecto (y por tanto lo hacéis como debe ser), tendréis que inventaros algo rollo usar enums para diferenciar templates.