From d086a99e5bf6cb4f3c27f82904c5619f8325d53b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Garc=C3=ADa?=
 <dani-garcia@users.noreply.github.com>
Date: Sun, 10 Feb 2019 19:12:34 +0100
Subject: [PATCH] Implemented HTML emails with text alternative

---
 src/config.rs | 14 +++++++++-----
 src/mail.rs   | 33 +++++++++++++++++++--------------
 2 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/src/config.rs b/src/config.rs
index c6c0e18e..d7839a8e 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -426,14 +426,18 @@ fn load_templates(path: &str) -> Handlebars {
             let template = include_str!(concat!("static/templates/", $name, ".hbs"));
             hb.register_template_string($name, template).unwrap();
         }};
+        ($name:expr, $ext:expr) => {{
+            reg!($name);
+            reg!(concat!($name, $ext));
+        }};
     }
 
     // First register default templates here
-    reg!("email/invite_accepted");
-    reg!("email/invite_confirmed");
-    reg!("email/pw_hint_none");
-    reg!("email/pw_hint_some");
-    reg!("email/send_org_invite");
+    reg!("email/invite_accepted", ".html");
+    reg!("email/invite_confirmed", ".html");
+    reg!("email/pw_hint_none", ".html");
+    reg!("email/pw_hint_some", ".html");
+    reg!("email/send_org_invite", ".html");
 
     reg!("admin/base");
     reg!("admin/login");
diff --git a/src/mail.rs b/src/mail.rs
index 468fa37d..fb4cb9c4 100644
--- a/src/mail.rs
+++ b/src/mail.rs
@@ -36,8 +36,14 @@ fn mailer() -> SmtpTransport {
         .transport()
 }
 
-fn get_text(template_name: &'static str, data: serde_json::Value) -> Result<(String, String), Error> {
-    let text = CONFIG.render_template(template_name, &data)?;
+fn get_text(template_name: &'static str, data: serde_json::Value) -> Result<(String, String, String), Error> {
+    let (subject_html, body_html) = get_template(&format!("{}.html", template_name), &data)?;
+    let (_subject_text, body_text) = get_template(template_name, &data)?;
+    Ok((subject_html, body_html, body_text))
+}
+
+fn get_template(template_name: &str, data: &serde_json::Value) -> Result<(String, String), Error> {
+    let text = CONFIG.render_template(template_name, data)?;
     let mut text_split = text.split("<!---------------->");
 
     let subject = match text_split.next() {
@@ -60,9 +66,9 @@ pub fn send_password_hint(address: &str, hint: Option<String>) -> EmptyResult {
         "email/pw_hint_none"
     };
 
-    let (subject, body) = get_text(template_name, json!({ "hint": hint }))?;
-
-    send_email(&address, &subject, &body)
+    let (subject, body_html, body_text) = get_text(template_name, json!({ "hint": hint }))?;
+ 
+    send_email(&address, &subject, &body_html, &body_text)
 }
 
 pub fn send_invite(
@@ -82,7 +88,7 @@ pub fn send_invite(
     );
     let invite_token = encode_jwt(&claims);
 
-    let (subject, body) = get_text(
+    let (subject, body_html, body_text) = get_text(
         "email/send_org_invite",
         json!({
             "url": CONFIG.domain(),
@@ -94,11 +100,11 @@ pub fn send_invite(
         }),
     )?;
 
-    send_email(&address, &subject, &body)
+    send_email(&address, &subject, &body_html, &body_text)
 }
 
 pub fn send_invite_accepted(new_user_email: &str, address: &str, org_name: &str) -> EmptyResult {
-    let (subject, body) = get_text(
+    let (subject, body_html, body_text) = get_text(
         "email/invite_accepted",
         json!({
             "url": CONFIG.domain(),
@@ -107,11 +113,11 @@ pub fn send_invite_accepted(new_user_email: &str, address: &str, org_name: &str)
         }),
     )?;
 
-    send_email(&address, &subject, &body)
+    send_email(&address, &subject, &body_html, &body_text)
 }
 
 pub fn send_invite_confirmed(address: &str, org_name: &str) -> EmptyResult {
-    let (subject, body) = get_text(
+    let (subject, body_html, body_text) = get_text(
         "email/invite_confirmed",
         json!({
             "url": CONFIG.domain(),
@@ -119,16 +125,15 @@ pub fn send_invite_confirmed(address: &str, org_name: &str) -> EmptyResult {
         }),
     )?;
 
-    send_email(&address, &subject, &body)
+    send_email(&address, &subject, &body_html, &body_text)
 }
 
-fn send_email(address: &str, subject: &str, body: &str) -> EmptyResult {
+fn send_email(address: &str, subject: &str, body_html: &str, body_text: &str) -> EmptyResult {
     let email = EmailBuilder::new()
         .to(address)
         .from((CONFIG.smtp_from().as_str(), CONFIG.smtp_from_name().as_str()))
         .subject(subject)
-        .header(("Content-Type", "text/html"))
-        .body(body)
+        .alternative(body_html, body_text)
         .build()
         .map_err(|e| Error::new("Error building email", e.to_string()))?;
 
-- 
GitLab