mirror of
https://github.com/bitwarden/server.git
synced 2025-07-18 16:11:28 -05:00
[PM-22423] Add MJML (#5941)
Scaffolds MJML and adds some initial templates and components. Of interest are: * src/Core/MailTemplates/Mjml/components/hero.js demonstrates how to create a custom MJML component. In our case it's a hero component with our logo, a title, a call to action button and an image. * src/Core/MailTemplates/Mjml/components/head.mjml defines some common styling. * src/Core/MailTemplates/Mjml/components/footer.mjml social links and footer.
This commit is contained in:
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
@ -33,6 +33,9 @@ util/SqliteMigrations/** @bitwarden/dept-dbops
|
||||
# Shared util projects
|
||||
util/Setup/** @bitwarden/dept-bre @bitwarden/team-platform-dev
|
||||
|
||||
# UIF
|
||||
src/Core/MailTemplates/Mjml @bitwarden/team-ui-foundation # Teams are expected to own sub-directories of this project
|
||||
|
||||
# Auth team
|
||||
**/Auth @bitwarden/team-auth-dev
|
||||
bitwarden_license/src/Sso @bitwarden/team-auth-dev
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -214,6 +214,7 @@ bitwarden_license/src/Sso/wwwroot/assets
|
||||
.idea/*
|
||||
**/**.swp
|
||||
.mono
|
||||
src/Core/MailTemplates/Mjml/out
|
||||
|
||||
src/Admin/Admin.zip
|
||||
src/Api/Api.zip
|
||||
|
5
src/Core/MailTemplates/Mjml/.mjmlconfig
Normal file
5
src/Core/MailTemplates/Mjml/.mjmlconfig
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"packages": [
|
||||
"components/hero"
|
||||
]
|
||||
}
|
19
src/Core/MailTemplates/Mjml/README.md
Normal file
19
src/Core/MailTemplates/Mjml/README.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Email templates
|
||||
|
||||
This directory contains MJML templates for emails sent by the application. MJML is a markup language designed to reduce the pain of coding responsive email templates.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
|
||||
# Build once
|
||||
npm run build
|
||||
|
||||
# To build on changes
|
||||
npm run watch
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
MJML supports components and you can create your own components by adding them to `.mjmlconfig`.
|
4
src/Core/MailTemplates/Mjml/build.sh
Executable file
4
src/Core/MailTemplates/Mjml/build.sh
Executable file
@ -0,0 +1,4 @@
|
||||
# TODO: This should probably be replaced with a node script building every file in `emails/`
|
||||
|
||||
npx mjml emails/invite.mjml -o out/invite.html
|
||||
npx mjml emails/two-factor.mjml -o out/two-factor.html
|
53
src/Core/MailTemplates/Mjml/components/footer.mjml
Normal file
53
src/Core/MailTemplates/Mjml/components/footer.mjml
Normal file
@ -0,0 +1,53 @@
|
||||
<mj-section>
|
||||
<mj-column>
|
||||
<mj-social icon-size="30px" inner-padding="10px" padding="0">
|
||||
<mj-social-element
|
||||
href="https://twitter.com/bitwarden"
|
||||
src="https://bitwarden.com/images/mail-twitter.png"
|
||||
></mj-social-element>
|
||||
|
||||
<mj-social-element
|
||||
href="https://www.reddit.com/r/Bitwarden/"
|
||||
src="https://bitwarden.com/images/mail-reddit.png"
|
||||
></mj-social-element>
|
||||
|
||||
<mj-social-element
|
||||
href="https://community.bitwarden.com/"
|
||||
src="https://bitwarden.com/images/mail-discourse.png"
|
||||
></mj-social-element>
|
||||
|
||||
<mj-social-element
|
||||
href="https://github.com/bitwarden"
|
||||
src="https://bitwarden.com/images/mail-github.png"
|
||||
></mj-social-element>
|
||||
|
||||
<mj-social-element
|
||||
href="https://www.youtube.com/channel/UCId9a_jQqvJre0_dE2lE_Rw"
|
||||
src="https://bitwarden.com/images/mail-youtube.png"
|
||||
></mj-social-element>
|
||||
|
||||
<mj-social-element
|
||||
href="https://www.linkedin.com/company/bitwarden1/"
|
||||
src="https://bitwarden.com/images/mail-linkedin.png"
|
||||
></mj-social-element>
|
||||
|
||||
<mj-social-element
|
||||
href="https://www.facebook.com/bitwarden/"
|
||||
src="https://bitwarden.com/images/mail-facebook.png"
|
||||
></mj-social-element>
|
||||
</mj-social>
|
||||
|
||||
<mj-text align="center" font-size="12px" line-height="16px" color="#5A6D91">
|
||||
<p style="margin-bottom: 5px">
|
||||
© 2025 Bitwarden Inc. 1 N. Calle Cesar Chavez, Suite 102, Santa
|
||||
Barbara, CA, USA
|
||||
</p>
|
||||
<p style="margin-top: 5px">
|
||||
Always confirm you are on a trusted Bitwarden domain before logging
|
||||
in:<br />
|
||||
<a href="#">bitwarden.com</a> |
|
||||
<a href="#">Learn why we include this</a>
|
||||
</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
16
src/Core/MailTemplates/Mjml/components/head.mjml
Normal file
16
src/Core/MailTemplates/Mjml/components/head.mjml
Normal file
@ -0,0 +1,16 @@
|
||||
<mj-attributes>
|
||||
<mj-all
|
||||
font-family="'Helvetica Neue', Helvetica, Arial, sans-serif"
|
||||
font-size="16px"
|
||||
/>
|
||||
<mj-button background-color="#175ddc" />
|
||||
<mj-text color="#333" />
|
||||
<mj-body background-color="#e6e9ef" width="660px" />
|
||||
</mj-attributes>
|
||||
<mj-style inline="inline">
|
||||
.link { text-decoration: none; color: #175ddc; font-weight: 600 }
|
||||
</mj-style>
|
||||
<mj-style>
|
||||
.border-fix > table { border-collapse:separate !important; } .border-fix >
|
||||
table > tbody > tr > td { border-radius: 3px; }
|
||||
</mj-style>
|
64
src/Core/MailTemplates/Mjml/components/hero.js
Normal file
64
src/Core/MailTemplates/Mjml/components/hero.js
Normal file
@ -0,0 +1,64 @@
|
||||
const { BodyComponent } = require("mjml-core");
|
||||
class MjBwHero extends BodyComponent {
|
||||
static dependencies = {
|
||||
// Tell the validator which tags are allowed as our component's parent
|
||||
"mj-column": ["mj-bw-hero"],
|
||||
"mj-wrapper": ["mj-bw-hero"],
|
||||
// Tell the validator which tags are allowed as our component's children
|
||||
"mj-bw-hero": [],
|
||||
};
|
||||
|
||||
static allowedAttributes = {
|
||||
"img-src": "string",
|
||||
title: "string",
|
||||
"button-text": "string",
|
||||
"button-url": "string",
|
||||
};
|
||||
|
||||
static defaultAttributes = {};
|
||||
|
||||
render() {
|
||||
return this.renderMJML(`
|
||||
<mj-section
|
||||
full-width="full-width"
|
||||
background-color="#175ddc"
|
||||
border-radius="4px 4px 0 0"
|
||||
>
|
||||
<mj-column width="70%">
|
||||
<mj-image
|
||||
align="left"
|
||||
src="https://bitwarden.com/images/logo-horizontal-white.png"
|
||||
width="150px"
|
||||
height="30px"
|
||||
></mj-image>
|
||||
<mj-text color="#fff" padding-top="0" padding-bottom="0">
|
||||
<h1 style="font-weight: normal; font-size: 24px; line-height: 32px">
|
||||
${this.getAttribute("title")}
|
||||
</h1>
|
||||
</mj-text>
|
||||
<mj-button
|
||||
href="${this.getAttribute("button-url")}"
|
||||
background-color="#fff"
|
||||
color="#1A41AC"
|
||||
border-radius="20px"
|
||||
align="left"
|
||||
>
|
||||
${this.getAttribute("button-text")}
|
||||
</mj-button
|
||||
>
|
||||
</mj-column>
|
||||
<mj-column width="30%" vertical-align="bottom">
|
||||
<mj-image
|
||||
src="${this.getAttribute("img-src")}"
|
||||
alt=""
|
||||
width="140px"
|
||||
height="140px"
|
||||
padding="0"
|
||||
/>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MjBwHero;
|
11
src/Core/MailTemplates/Mjml/components/logo.mjml
Normal file
11
src/Core/MailTemplates/Mjml/components/logo.mjml
Normal file
@ -0,0 +1,11 @@
|
||||
<mj-section>
|
||||
<mj-column>
|
||||
<mj-image
|
||||
align="center"
|
||||
padding="10px 25px"
|
||||
src="https://bitwarden.com/images/logo-horizontal-blue.png"
|
||||
width="250px"
|
||||
height="39px"
|
||||
></mj-image>
|
||||
</mj-column>
|
||||
</mj-section>
|
49
src/Core/MailTemplates/Mjml/emails/invite.mjml
Normal file
49
src/Core/MailTemplates/Mjml/emails/invite.mjml
Normal file
@ -0,0 +1,49 @@
|
||||
<mjml>
|
||||
<mj-head>
|
||||
<mj-include path="../components/head.mjml" />
|
||||
</mj-head>
|
||||
|
||||
<mj-body>
|
||||
<mj-wrapper css-class="border-fix" padding="20px 20px">
|
||||
<mj-bw-hero
|
||||
img-src="https://assets.bitwarden.com/email/v1/business.png"
|
||||
title="A Bitwarden member has invited you to Bitwarden Password Manager"
|
||||
button-text="Finish account setup"
|
||||
button-url="#"
|
||||
/>
|
||||
|
||||
<mj-section>
|
||||
<mj-column>
|
||||
<mj-button href="#">Join Organization Now</mj-button>
|
||||
|
||||
<mj-text>
|
||||
This invitation expires on
|
||||
<b>Tuesday, January 23, 2024 2:59PM UTC</b>.
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section background-color="#fbfbfb">
|
||||
<mj-column width="70%">
|
||||
<mj-text line-height="24px">
|
||||
<h3 style="font-size: 20px; margin: 0; line-height: 28px">
|
||||
We’re here for you!
|
||||
</h3>
|
||||
If you have any questions, search the Bitwarden
|
||||
<a href="#" class="link">Help</a>
|
||||
site or
|
||||
<a href="#" class="link">contact us</a>.
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="30%">
|
||||
<mj-image
|
||||
src="https://assets.bitwarden.com/email/v1/chat.png"
|
||||
height="77px"
|
||||
width="94px"
|
||||
/>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-wrapper>
|
||||
|
||||
<mj-include path="../components/footer.mjml" />
|
||||
</mj-body>
|
||||
</mjml>
|
27
src/Core/MailTemplates/Mjml/emails/two-factor.mjml
Normal file
27
src/Core/MailTemplates/Mjml/emails/two-factor.mjml
Normal file
@ -0,0 +1,27 @@
|
||||
<mjml>
|
||||
<mj-head>
|
||||
<mj-include path="../components/head.mjml" />
|
||||
</mj-head>
|
||||
|
||||
<mj-body background-color="#f6f6f6">
|
||||
<mj-include path="../components/logo.mjml" />
|
||||
|
||||
<mj-wrapper
|
||||
background-color="#fff"
|
||||
border="1px solid #e9e9e9"
|
||||
css-class="border-fix"
|
||||
padding="0"
|
||||
>
|
||||
<mj-section>
|
||||
<mj-column>
|
||||
<mj-text>
|
||||
<p>Your two-step verification code is: <b>{{Token}}</b></p>
|
||||
<p>Use this code to complete logging in with Bitwarden.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-wrapper>
|
||||
|
||||
<mj-include path="../components/footer.mjml" />
|
||||
</mj-body>
|
||||
</mjml>
|
2186
src/Core/MailTemplates/Mjml/package-lock.json
generated
Normal file
2186
src/Core/MailTemplates/Mjml/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
30
src/Core/MailTemplates/Mjml/package.json
Normal file
30
src/Core/MailTemplates/Mjml/package.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "@bitwarden/mjml-emails",
|
||||
"version": "1.0.0",
|
||||
"description": "Email templates for Bitwarden",
|
||||
"private": true,
|
||||
"type": "commonjs",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/bitwarden/server.git"
|
||||
},
|
||||
"author": "Bitwarden Inc. <hello@bitwarden.com> (https://bitwarden.com)",
|
||||
"license": "SEE LICENSE IN LICENSE.txt",
|
||||
"bugs": {
|
||||
"url": "https://github.com/bitwarden/server/issues"
|
||||
},
|
||||
"homepage": "https://bitwarden.com",
|
||||
"scripts": {
|
||||
"build": "./build.sh",
|
||||
"watch": "nodemon --exec ./build.sh --watch ./components --watch ./emails --ext js,mjml",
|
||||
"prettier": "prettier --cache --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"mjml": "4.15.3",
|
||||
"mjml-core": "4.15.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "3.1.10",
|
||||
"prettier": "3.5.3"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user