From 41ab05ca6637a2eb799ec13ef177b6954098fece Mon Sep 17 00:00:00 2001
From: Jyoti Patel <36148363+jp0707@users.noreply.github.com>
Date: Wed, 10 Mar 2021 02:18:32 -0500
Subject: [PATCH] [GH-15906][MM-22844] Redesign reset password and invite
emails (#17029)
Automatic Merge
---
app/email.go | 36 +--
i18n/en.json | 38 ++-
templates/invite_body.html | 558 ++++++++++++++++++++++++++++++----
templates/invite_body.mjml | 37 +++
templates/partials/card.mjml | 15 +
templates/partials/style.mjml | 78 ++++-
templates/reset_body.html | 480 ++++++++++++++++++++++++++---
templates/reset_body.mjml | 21 ++
templates/verify_body.html | 78 ++++-
templates/welcome_body.html | 78 ++++-
10 files changed, 1291 insertions(+), 128 deletions(-)
create mode 100644 templates/invite_body.mjml
create mode 100644 templates/partials/card.mjml
create mode 100644 templates/reset_body.mjml
diff --git a/app/email.go b/app/email.go
index e5af249ec7..9ca379dc29 100644
--- a/app/email.go
+++ b/app/email.go
@@ -308,10 +308,12 @@ func (es *EmailService) SendPasswordResetEmail(email string, token *model.Token,
bodyPage := es.newEmailTemplate("reset_body", locale)
bodyPage.Props["SiteURL"] = siteURL
bodyPage.Props["Title"] = T("api.templates.reset_body.title")
- bodyPage.Props["Info1"] = i18n.TranslateAsHTML(T, "api.templates.reset_body.info1", nil)
- bodyPage.Props["Info2"] = T("api.templates.reset_body.info2")
- bodyPage.Props["ResetUrl"] = link
+ bodyPage.Props["SubTitle"] = T("api.templates.reset_body.subTitle")
+ bodyPage.Props["Info"] = T("api.templates.reset_body.info")
+ bodyPage.Props["ButtonURL"] = link
bodyPage.Props["Button"] = T("api.templates.reset_body.button")
+ bodyPage.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
+ bodyPage.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
return false, model.NewAppError("SendPasswordReset", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
@@ -371,13 +373,13 @@ func (es *EmailService) SendInviteEmails(team *model.Team, senderName string, se
bodyPage := es.newEmailTemplate("invite_body", "")
bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = i18n.T("api.templates.invite_body.title")
- bodyPage.HTML["Info"] = i18n.TranslateAsHTML(i18n.T, "api.templates.invite_body.info",
- map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName})
+ bodyPage.Props["Title"] = i18n.T("api.templates.invite_body.title", map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName})
+ bodyPage.Props["SubTitle"] = i18n.T("api.templates.invite_body.subTitle")
bodyPage.Props["Button"] = i18n.T("api.templates.invite_body.button")
- bodyPage.HTML["ExtraInfo"] = i18n.TranslateAsHTML(i18n.T, "api.templates.invite_body.extra_info",
- map[string]interface{}{"TeamDisplayName": team.DisplayName})
- bodyPage.Props["TeamURL"] = siteURL + "/" + team.Name
+ bodyPage.Props["SenderName"] = senderName
+ bodyPage.Props["InviteFooterTitle"] = i18n.T("api.templates.invite_body_footer.title")
+ bodyPage.Props["InviteFooterInfo"] = i18n.T("api.templates.invite_body_footer.info")
+ bodyPage.Props["InviteFooterLearnMore"] = i18n.T("api.templates.invite_body_footer.learn_more")
token := model.NewToken(
TokenTypeTeamInvitation,
@@ -394,7 +396,7 @@ func (es *EmailService) SendInviteEmails(team *model.Team, senderName string, se
mlog.Error("Failed to send invite email successfully ", mlog.Err(err))
continue
}
- bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s", siteURL, url.QueryEscape(data), url.QueryEscape(token.Token))
+ bodyPage.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s", siteURL, url.QueryEscape(data), url.QueryEscape(token.Token))
if err := es.sendMail(invite, subject, bodyPage.Render()); err != nil {
mlog.Error("Failed to send invite email successfully ", mlog.Err(err))
@@ -430,19 +432,17 @@ func (es *EmailService) sendGuestInviteEmails(team *model.Team, channels []*mode
bodyPage := es.newEmailTemplate("invite_body", "")
bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = i18n.T("api.templates.invite_body.title")
- bodyPage.HTML["Info"] = i18n.TranslateAsHTML(i18n.T, "api.templates.invite_body_guest.info",
- map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName})
+ bodyPage.Props["Title"] = i18n.T("api.templates.invite_body.title", map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName})
+ bodyPage.Props["SubTitle"] = i18n.T("api.templates.invite_body_guest.subTitle")
bodyPage.Props["Button"] = i18n.T("api.templates.invite_body.button")
bodyPage.Props["SenderName"] = senderName
- bodyPage.Props["SenderId"] = senderUserId
bodyPage.Props["Message"] = ""
if message != "" {
bodyPage.Props["Message"] = message
}
- bodyPage.HTML["ExtraInfo"] = i18n.TranslateAsHTML(i18n.T, "api.templates.invite_body.extra_info",
- map[string]interface{}{"TeamDisplayName": team.DisplayName})
- bodyPage.Props["TeamURL"] = siteURL + "/" + team.Name
+ bodyPage.Props["InviteFooterTitle"] = i18n.T("api.templates.invite_body_footer.title")
+ bodyPage.Props["InviteFooterInfo"] = i18n.T("api.templates.invite_body_footer.info")
+ bodyPage.Props["InviteFooterLearnMore"] = i18n.T("api.templates.invite_body_footer.learn_more")
channelIDs := []string{}
for _, channel := range channels {
@@ -469,7 +469,7 @@ func (es *EmailService) sendGuestInviteEmails(team *model.Team, channels []*mode
mlog.Error("Failed to send invite email successfully ", mlog.Err(err))
continue
}
- bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s", siteURL, url.QueryEscape(data), url.QueryEscape(token.Token))
+ bodyPage.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s", siteURL, url.QueryEscape(data), url.QueryEscape(token.Token))
if !*es.srv.Config().EmailSettings.SendEmailNotifications {
mlog.Info("sending invitation ", mlog.String("to", invite), mlog.String("link", bodyPage.Props["Link"].(string)))
diff --git a/i18n/en.json b/i18n/en.json
index b17b2008bd..24b60595e8 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -2760,23 +2760,31 @@
},
{
"id": "api.templates.invite_body.button",
- "translation": "Join Team"
+ "translation": "Join now"
},
{
- "id": "api.templates.invite_body.extra_info",
- "translation": "Mattermost lets you share messages and files from your PC or phone, with instant search and archiving. After you’ve joined [[{{.TeamDisplayName}}]], you can sign-in to your new team and access these features anytime from the web address:"
- },
- {
- "id": "api.templates.invite_body.info",
- "translation": "[[{{.SenderName}}]], has invited you to join [[{{.TeamDisplayName}}]]."
+ "id": "api.templates.invite_body.subTitle",
+ "translation": "Start collaborating with your team on Mattermost"
},
{
"id": "api.templates.invite_body.title",
- "translation": "You've been invited"
+ "translation": "{{ .SenderName }} invited you to join the {{ .TeamDisplayName }} team."
},
{
- "id": "api.templates.invite_body_guest.info",
- "translation": "[[{{.SenderName}}]], has invited you to join team [[{{.TeamDisplayName}}]] as a guest."
+ "id": "api.templates.invite_body_footer.info",
+ "translation": "Mattermost is a flexible, open source messaging platform that enables secure team collaboration."
+ },
+ {
+ "id": "api.templates.invite_body_footer.learn_more",
+ "translation": "Learn more"
+ },
+ {
+ "id": "api.templates.invite_body_footer.title",
+ "translation": "What is Mattermost?"
+ },
+ {
+ "id": "api.templates.invite_body_guest.subTitle",
+ "translation": "You were invited as a guest to collaborate with the team"
},
{
"id": "api.templates.invite_guest_subject",
@@ -3003,16 +3011,16 @@
"translation": "Reset Password"
},
{
- "id": "api.templates.reset_body.info1",
- "translation": "To change your password, click \"Reset Password\" below."
+ "id": "api.templates.reset_body.info",
+ "translation": "The password reset link expires in 24 hours."
},
{
- "id": "api.templates.reset_body.info2",
- "translation": "If you did not mean to reset your password, please ignore this email and your password will remain the same. The password reset link expires in 24 hours."
+ "id": "api.templates.reset_body.subTitle",
+ "translation": "Click the button below to reset your password. If you didn’t request this, you can safely ignore this email."
},
{
"id": "api.templates.reset_body.title",
- "translation": "You requested a password reset"
+ "translation": "Reset Your Password"
},
{
"id": "api.templates.reset_subject",
diff --git a/templates/invite_body.html b/templates/invite_body.html
index 99361ae76a..58bd019a40 100644
--- a/templates/invite_body.html
+++ b/templates/invite_body.html
@@ -1,61 +1,515 @@
{{define "invite_body"}}
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
|
-
-
-
-
-
-
- {{.Props.Title}}
- {{.HTML.Info}}
-
- {{.Props.Button}}
-
- {{if .Props.Message}}
-
-
-
-
- |
-
- {{.Props.SenderName}}
- {{.Props.Message}}
- |
-
-
- {{end}}
-
- {{.HTML.ExtraInfo}}
{{.Props.TeamURL}}
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ {{.Props.Title}}
+ |
+
+
+ |
+ {{.Props.SubTitle}}
+ |
+
+
+ |
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+ {{if .Props.Message}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
-
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+ {{.Props.SenderName}}
+ |
+
+
+ |
+ {{.Props.Message}}
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+ {{else}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- {{template "email_info" . }}
+
+
+ |
+
- |
-
-
- {{template "email_footer" . }}
-
-
- |
-
-
- |
-
-
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+ {{end}}
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
{{end}}
diff --git a/templates/invite_body.mjml b/templates/invite_body.mjml
new file mode 100644
index 0000000000..d3e70c7f2d
--- /dev/null
+++ b/templates/invite_body.mjml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+ {{if .Props.Message}}
+
+
+
+ {{else}}
+
+
+
+
+
+ {{end}}
+
+
+
+ {{.Props.InviteFooterTitle}}
+
+
+ {{.Props.InviteFooterInfo}}
+
+
+
+ {{.Props.InviteFooterLearnMore}}
+
+
+
+
+
+
+
diff --git a/templates/partials/card.mjml b/templates/partials/card.mjml
new file mode 100644
index 0000000000..e3b0cc6aa6
--- /dev/null
+++ b/templates/partials/card.mjml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ {{.Props.SenderName}}
+
+
+ {{.Props.Message}}
+
+
+
+
\ No newline at end of file
diff --git a/templates/partials/style.mjml b/templates/partials/style.mjml
index e2345b143d..7a93d522fc 100644
--- a/templates/partials/style.mjml
+++ b/templates/partials/style.mjml
@@ -61,7 +61,11 @@
font-size:14px !important;
line-height:20px !important;
color:#3D3C40 !important;
- padding:0px !important;
+ padding:0px 48px 0px 48px !important;
+ }
+
+ .footerInfo a {
+ color:#166DE0 !important;
}
.appDownloadButton a{
@@ -82,6 +86,52 @@
padding:8px 24px 8px 24px !important;
}
+ .postCard {
+ padding:0px 24px 40px 24px !important;
+ }
+
+ .messageCard {
+ background:#FFFFFF !important;
+ border:1px solid rgba(61, 60, 64, 0.08) !important;
+ box-sizing:border-box !important;
+ box-shadow:0px 8px 24px rgba(0, 0, 0, 0.12) !important;
+ border-radius:4px !important;
+ padding:32px !important;
+ }
+
+ .messageAvatar img {
+ width:32px !important;
+ height:32px !important;
+ padding:0px !important;
+ border-radius:32px !important;
+ }
+
+ .messageAvatarCol {
+ width:32px !important;
+ }
+
+ .senderName div {
+ text-align:left !important;
+ font-weight:600 !important;
+ font-size:14px !important;
+ line-height:20px !important;
+ color:#3D3C40 !important;
+ padding:0px 0px 4px 0px !important;
+ }
+
+ .senderMessage div {
+ text-align:left !important;
+ font-size:14px !important;
+ line-height:20px !important;
+ color:#3D3C40 !important;
+ padding:0px !important;
+ }
+
+ .senderInfoCol {
+ width:394px !important;
+ padding:0px 0px 0px 12px !important;
+ }
+
@media all and (min-width: 541px) {
.emailBody {
padding:32px !important;
@@ -92,12 +142,38 @@
.emailBody {
padding:16px !important;
}
+
+ .messageCard {
+ padding:16px !important;
+ }
+
+ .senderInfoCol {
+ width:80% !important;
+ padding:0px 0px 0px 12px !important;
+ }
}
@media all and (max-width: 400px) {
.emailBody {
padding:0px !important;
}
+
+ .footerInfo div {
+ padding:0px !important;
+ }
+
+ .messageCard {
+ padding:16px !important;
+ }
+
+ .postCard {
+ padding:0px 0px 40px 0px !important;
+ }
+
+ .senderInfoCol {
+ width:80% !important;
+ padding:0px 0px 0px 12px !important;
+ }
}
diff --git a/templates/reset_body.html b/templates/reset_body.html
index 21bb756ffc..33edf1cfa1 100644
--- a/templates/reset_body.html
+++ b/templates/reset_body.html
@@ -1,46 +1,446 @@
{{define "reset_body"}}
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
|
-
-
-
-
-
-
- {{.Props.Title}}
- {{.Props.Info1}} {{.Props.Info2}}
-
- {{.Props.Button}}
-
- |
-
-
- {{template "email_info" . }}
-
-
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ {{.Props.Title}}
|
-
-
- {{template "email_footer" . }}
-
-
- |
-
-
- |
-
-
+ |
+
+ |
+ {{.Props.SubTitle}}
+ |
+
+
+ |
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+ |
+ {{.Props.Info}}
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
{{end}}
diff --git a/templates/reset_body.mjml b/templates/reset_body.mjml
new file mode 100644
index 0000000000..06bd55c508
--- /dev/null
+++ b/templates/reset_body.mjml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{.Props.Info}}
+
+
+
+
+
+ s
+
+
diff --git a/templates/verify_body.html b/templates/verify_body.html
index 67ee5dee89..d6fe66f461 100644
--- a/templates/verify_body.html
+++ b/templates/verify_body.html
@@ -137,7 +137,11 @@
font-size: 14px !important;
line-height: 20px !important;
color: #3D3C40 !important;
- padding: 0px !important;
+ padding: 0px 48px 0px 48px !important;
+ }
+
+ .footerInfo a {
+ color: #166DE0 !important;
}
.appDownloadButton a {
@@ -158,6 +162,52 @@
padding: 8px 24px 8px 24px !important;
}
+ .postCard {
+ padding: 0px 24px 40px 24px !important;
+ }
+
+ .messageCard {
+ background: #FFFFFF !important;
+ border: 1px solid rgba(61, 60, 64, 0.08) !important;
+ box-sizing: border-box !important;
+ box-shadow: 0px 8px 24px rgba(0, 0, 0, 0.12) !important;
+ border-radius: 4px !important;
+ padding: 32px !important;
+ }
+
+ .messageAvatar img {
+ width: 32px !important;
+ height: 32px !important;
+ padding: 0px !important;
+ border-radius: 32px !important;
+ }
+
+ .messageAvatarCol {
+ width: 32px !important;
+ }
+
+ .senderName div {
+ text-align: left !important;
+ font-weight: 600 !important;
+ font-size: 14px !important;
+ line-height: 20px !important;
+ color: #3D3C40 !important;
+ padding: 0px 0px 4px 0px !important;
+ }
+
+ .senderMessage div {
+ text-align: left !important;
+ font-size: 14px !important;
+ line-height: 20px !important;
+ color: #3D3C40 !important;
+ padding: 0px !important;
+ }
+
+ .senderInfoCol {
+ width: 394px !important;
+ padding: 0px 0px 0px 12px !important;
+ }
+
@media all and (min-width: 541px) {
.emailBody {
padding: 32px !important;
@@ -168,12 +218,38 @@
.emailBody {
padding: 16px !important;
}
+
+ .messageCard {
+ padding: 16px !important;
+ }
+
+ .senderInfoCol {
+ width: 80% !important;
+ padding: 0px 0px 0px 12px !important;
+ }
}
@media all and (max-width: 400px) {
.emailBody {
padding: 0px !important;
}
+
+ .footerInfo div {
+ padding: 0px !important;
+ }
+
+ .messageCard {
+ padding: 16px !important;
+ }
+
+ .postCard {
+ padding: 0px 0px 40px 0px !important;
+ }
+
+ .senderInfoCol {
+ width: 80% !important;
+ padding: 0px 0px 0px 12px !important;
+ }
}
diff --git a/templates/welcome_body.html b/templates/welcome_body.html
index 7ad55108a7..b444f6aaf0 100644
--- a/templates/welcome_body.html
+++ b/templates/welcome_body.html
@@ -137,7 +137,11 @@
font-size: 14px !important;
line-height: 20px !important;
color: #3D3C40 !important;
- padding: 0px !important;
+ padding: 0px 48px 0px 48px !important;
+ }
+
+ .footerInfo a {
+ color: #166DE0 !important;
}
.appDownloadButton a {
@@ -158,6 +162,52 @@
padding: 8px 24px 8px 24px !important;
}
+ .postCard {
+ padding: 0px 24px 40px 24px !important;
+ }
+
+ .messageCard {
+ background: #FFFFFF !important;
+ border: 1px solid rgba(61, 60, 64, 0.08) !important;
+ box-sizing: border-box !important;
+ box-shadow: 0px 8px 24px rgba(0, 0, 0, 0.12) !important;
+ border-radius: 4px !important;
+ padding: 32px !important;
+ }
+
+ .messageAvatar img {
+ width: 32px !important;
+ height: 32px !important;
+ padding: 0px !important;
+ border-radius: 32px !important;
+ }
+
+ .messageAvatarCol {
+ width: 32px !important;
+ }
+
+ .senderName div {
+ text-align: left !important;
+ font-weight: 600 !important;
+ font-size: 14px !important;
+ line-height: 20px !important;
+ color: #3D3C40 !important;
+ padding: 0px 0px 4px 0px !important;
+ }
+
+ .senderMessage div {
+ text-align: left !important;
+ font-size: 14px !important;
+ line-height: 20px !important;
+ color: #3D3C40 !important;
+ padding: 0px !important;
+ }
+
+ .senderInfoCol {
+ width: 394px !important;
+ padding: 0px 0px 0px 12px !important;
+ }
+
@media all and (min-width: 541px) {
.emailBody {
padding: 32px !important;
@@ -168,12 +218,38 @@
.emailBody {
padding: 16px !important;
}
+
+ .messageCard {
+ padding: 16px !important;
+ }
+
+ .senderInfoCol {
+ width: 80% !important;
+ padding: 0px 0px 0px 12px !important;
+ }
}
@media all and (max-width: 400px) {
.emailBody {
padding: 0px !important;
}
+
+ .footerInfo div {
+ padding: 0px !important;
+ }
+
+ .messageCard {
+ padding: 16px !important;
+ }
+
+ .postCard {
+ padding: 0px 0px 40px 0px !important;
+ }
+
+ .senderInfoCol {
+ width: 80% !important;
+ padding: 0px 0px 0px 12px !important;
+ }
}
|