Browse Source
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.pull/6091/head
13 changed files with 2468 additions and 0 deletions
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
{ |
||||
"packages": [ |
||||
"components/hero" |
||||
] |
||||
} |
||||
@ -0,0 +1,19 @@
@@ -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`. |
||||
@ -0,0 +1,4 @@
@@ -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 |
||||
@ -0,0 +1,53 @@
@@ -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> |
||||
@ -0,0 +1,16 @@
@@ -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> |
||||
@ -0,0 +1,64 @@
@@ -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; |
||||
@ -0,0 +1,11 @@
@@ -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> |
||||
@ -0,0 +1,49 @@
@@ -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> |
||||
@ -0,0 +1,27 @@
@@ -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> |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,30 @@
@@ -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" |
||||
} |
||||
} |
||||
Loading…
Reference in new issue