Updates after finding a better template to use and adding some real email testing with Ethereal platform.

This commit is contained in:
mike12345567 2021-04-26 14:14:51 +01:00
parent 73ad093a50
commit 84e66f826b
14 changed files with 693 additions and 340 deletions

View File

@ -50,6 +50,7 @@ class TestConfiguration {
request.config = { jwtSecret: env.JWT_SECRET } request.config = { jwtSecret: env.JWT_SECRET }
request.appId = this.appId request.appId = this.appId
request.user = { appId: this.appId } request.user = { appId: this.appId }
request.query = {}
request.request = { request.request = {
body: config, body: config,
} }

View File

@ -34,7 +34,7 @@ exports.save = async function(ctx) {
} }
try { try {
const response = await db.post(config) const response = await db.put(config)
ctx.body = { ctx.body = {
type, type,
_id: response.id, _id: response.id,

View File

@ -16,6 +16,7 @@ const TYPE = TemplateTypes.EMAIL
const FULL_EMAIL_PURPOSES = [ const FULL_EMAIL_PURPOSES = [
EmailTemplatePurpose.INVITATION, EmailTemplatePurpose.INVITATION,
EmailTemplatePurpose.PASSWORD_RECOVERY, EmailTemplatePurpose.PASSWORD_RECOVERY,
EmailTemplatePurpose.WELCOME,
] ]
async function buildEmail(purpose, email, user) { async function buildEmail(purpose, email, user) {

View File

@ -27,6 +27,7 @@ function settingValidation() {
return Joi.object({ return Joi.object({
platformUrl: Joi.string().valid("", null), platformUrl: Joi.string().valid("", null),
logoUrl: Joi.string().valid("", null), logoUrl: Joi.string().valid("", null),
docsUrl: Joi.string().valid("", null),
company: Joi.string().required(), company: Joi.string().required(),
}).unknown(true) }).unknown(true)
} }

View File

@ -0,0 +1,60 @@
const setup = require("./utilities")
const { EmailTemplatePurpose } = require("../../../constants")
const nodemailer = require("nodemailer")
const fetch = require("node-fetch")
describe("/api/admin/email", () => {
let request = setup.getRequest()
let config = setup.getConfig()
beforeAll(async () => {
await config.init()
})
afterAll(setup.afterAll)
async function sendRealEmail(purpose) {
await config.saveEtherealSmtpConfig()
await config.saveSettingsConfig()
const res = await request
.post(`/api/admin/email/send`)
.send({
email: "test@test.com",
purpose,
})
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body.message).toBeDefined()
const testUrl = nodemailer.getTestMessageUrl(res.body)
expect(testUrl).toBeDefined()
const response = await fetch(testUrl)
const text = await response.text()
let toCheckFor
switch (purpose) {
case EmailTemplatePurpose.WELCOME:
toCheckFor = `Thanks for getting started with Budibase's Budibase platform.`
break
case EmailTemplatePurpose.INVITATION:
toCheckFor = `Use the button below to set up your account and get started:`
break
case EmailTemplatePurpose.PASSWORD_RECOVERY:
toCheckFor = `You recently requested to reset your password for your Budibase account in your Budibase platform`
break
}
expect(text).toContain(toCheckFor)
}
it("should be able to send a welcome email", async () => {
await sendRealEmail(EmailTemplatePurpose.WELCOME)
})
it("should be able to send a invitation email", async () => {
await sendRealEmail(EmailTemplatePurpose.INVITATION)
})
it("should be able to send a password recovery email", async () => {
const res = await sendRealEmail(EmailTemplatePurpose.PASSWORD_RECOVERY)
})
})

View File

@ -3,7 +3,7 @@ const controllers = require("./controllers")
const supertest = require("supertest") const supertest = require("supertest")
const { jwt } = require("@budibase/auth").auth const { jwt } = require("@budibase/auth").auth
const { Cookies } = require("@budibase/auth").constants const { Cookies } = require("@budibase/auth").constants
const { Configs } = require("../../../../constants") const { Configs, LOGO_URL } = require("../../../../constants")
class TestConfiguration { class TestConfiguration {
constructor(openServer = true) { constructor(openServer = true) {
@ -26,6 +26,7 @@ class TestConfiguration {
request.config = { jwtSecret: env.JWT_SECRET } request.config = { jwtSecret: env.JWT_SECRET }
request.appId = this.appId request.appId = this.appId
request.user = { appId: this.appId } request.user = { appId: this.appId }
request.query = {}
request.request = { request.request = {
body: config, body: config,
} }
@ -62,18 +63,34 @@ class TestConfiguration {
} }
} }
async deleteConfig(type) {
try {
const cfg = await this._req(null,{
type,
}, controllers.config.find)
if (cfg) {
await this._req(null, {
id: cfg._id,
rev: cfg._rev,
}, controllers.config.destroy)
}
} catch (err) {}
}
async saveSettingsConfig() { async saveSettingsConfig() {
await this.deleteConfig(Configs.SETTINGS)
await this._req({ await this._req({
type: Configs.SETTINGS, type: Configs.SETTINGS,
config: { config: {
platformUrl: "http://localhost:10000", platformUrl: "http://localhost:10000",
logoUrl: "http://localhost:10000/logo", logoUrl: LOGO_URL,
company: "TestCompany", company: "Budibase",
} }
}, null, controllers.config.save) }, null, controllers.config.save)
} }
async saveSmtpConfig() { async saveSmtpConfig() {
await this.deleteConfig(Configs.SMTP)
await this._req({ await this._req({
type: Configs.SMTP, type: Configs.SMTP,
config: { config: {
@ -84,6 +101,22 @@ class TestConfiguration {
} }
}, null, controllers.config.save) }, null, controllers.config.save)
} }
async saveEtherealSmtpConfig() {
await this.deleteConfig(Configs.SMTP)
await this._req({
type: Configs.SMTP,
config: {
port: 587,
host: "smtp.ethereal.email",
secure: false,
auth: {
user: "don.bahringer@ethereal.email",
pass: "yCKSH8rWyUPbnhGYk9",
},
}
}, null, controllers.config.save)
}
} }
module.exports = TestConfiguration module.exports = TestConfiguration

View File

@ -26,6 +26,7 @@ const EmailTemplatePurpose = {
STYLES: "styles", STYLES: "styles",
PASSWORD_RECOVERY: "password_recovery", PASSWORD_RECOVERY: "password_recovery",
INVITATION: "invitation", INVITATION: "invitation",
WELCOME: "welcome",
CUSTOM: "custom", CUSTOM: "custom",
} }
@ -39,6 +40,9 @@ const TemplateBindings = {
EMAIL: "email", EMAIL: "email",
RESET_URL: "resetUrl", RESET_URL: "resetUrl",
USER: "user", USER: "user",
REQUEST: "request",
DOCS_URL: "docsUrl",
LOGIN_URL: "loginUrl",
} }
const TemplateMetadata = { const TemplateMetadata = {

View File

@ -1,83 +1,32 @@
<!doctype html> <!-- Based on templates: https://github.com/wildbit/postmark-templates/blob/master/templates/plain -->
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="x-apple-disable-message-reformatting" />
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<head> <meta name="color-scheme" content="light dark" />
<meta charset="utf-8"> <meta name="supported-color-schemes" content="light dark" />
<meta name="viewport" content="width=device-width"> <title></title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <style type="text/css" rel="stylesheet" media="all">
<meta name="x-apple-disable-message-reformatting">
<style>
{{ styles }} {{ styles }}
</style> </style>
</head> <!--[if mso]>
<style type="text/css">
.f-fallback {
font-family: Arial, sans-serif;
}
</style>
<![endif]-->
</head>
<body> <body>
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin: auto;"> {{ body }}
<tbody> <table class="email-footer" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
<tr> <tr>
<td class="bg_white logo" style="padding: 1em 2.5em; text-align: center"> <td class="content-cell" align="center">
<h1><a href="{{ companyUrl }}">{{ company }}</a></h1> <p class="f-fallback sub align-center">&copy; 2021 {{ company }}. All rights reserved.</p>
</td> </td>
</tr> </tr>
<tr>
<td class="bg_white logo" style="padding: 1em 2.5em; text-align: center">
{{ body }}
</td>
</tr>
<tr>
<td class="bg_white logo" style="padding: 1em 2.5em; text-align: center">
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin: auto;">
<tbody><tr>
<td valign="middle" class="bg_black footer email-section">
<table>
<tbody><tr>
<td valign="top" width="50%" style="padding-top: 20px;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tbody><tr>
<td style="text-align: left; padding-right: 10px;">
<h3 class="heading">{{ company }}</h3>
<p>Company information.</p>
</td>
</tr>
</tbody></table>
</td>
<td valign="top" width="50%" style="padding-top: 20px;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tbody><tr>
<td style="text-align: left; padding-left: 10px;">
<h3 class="heading"><a href="{{ platformUrl }}">Budibase Platform</a></h3>
</td>
</tr>
</tbody></table>
</td>
</tr>
</tbody></table>
</td>
</tr>
<tr>
<td valign="middle" class="bg_black footer email-section">
<table>
<tbody><tr>
<td valign="top" width="50%">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tbody><tr>
<td style="text-align: left; padding-right: 10px;">
<p>© 2021 {{ company }}. All Rights Reserved</p>
</td>
</tr>
</tbody></table>
</td>
</tr>
</tbody></table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table> </table>
</body> </body>
</html> </html>

View File

@ -20,6 +20,7 @@ exports.EmailTemplates = {
[EmailTemplatePurpose.STYLES]: readStaticFile( [EmailTemplatePurpose.STYLES]: readStaticFile(
join(__dirname, "style.hbs") join(__dirname, "style.hbs")
), ),
[EmailTemplatePurpose.WELCOME]: readStaticFile(join(__dirname, "welcome.hbs")),
} }
exports.addBaseTemplates = (templates, type = null) => { exports.addBaseTemplates = (templates, type = null) => {

View File

@ -1,14 +1,67 @@
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"> <!-- Based on template: https://github.com/wildbit/postmark-templates/blob/master/templates/plain/user-invitation/content.html -->
<tbody> <span class="preheader">You've been invited to use {{ company }}'s Budibase platform!</span>
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr> <tr>
<td class="bg_dark email-section" style="text-align:center;"> <td align="center">
<div class="heading-section heading-section-white"> <table class="email-content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<span class="subheading">Budibase Invitation</span> <tr>
<h2>You've been invited to join {{ company }}'s Budibase platform!</h2> <td class="email-masthead">
<p>Please follow the below link to finish your registration.</p> <a href="{{ platformUrl }}" class="f-fallback email-masthead_name">
<p><a href="{{ registrationUrl }}" class="btn btn-primary">Finish registration</a></p> {{ company }}
</a>
</td>
</tr>
<!-- Email Body -->
<tr>
<td class="email-body" width="570" cellpadding="0" cellspacing="0">
<table class="email-body_inner" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
<!-- Body content -->
<tr>
<td class="content-cell">
<div class="f-fallback">
<h1>Hi, {{ email }}!</h1>
<p>
{{#if request}}
{{ request.inviter }} has invited you to use {{ company }}'s Budibase platform.<
{{else}}
You've been invited to use {{ company }}'s Budibase platform.
{{/if}}
Use the button below to set up your account and get started:
</p>
<!-- Action -->
<table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table width="100%" border="0" cellspacing="0" cellpadding="0" role="presentation">
<tr>
<td align="center">
<a href="{{ registrationUrl }}" class="f-fallback button" target="_blank">Set up account</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p>If you have any questions contact your Budibase platform administrator.</p>
<p>Welcome aboard,
<br>The {{ company }} Team</p>
<p><strong>P.S.</strong> Need help getting started? Check out our <a href="{{ docsUrl }}">help documentation</a>.</p>
<!-- Sub copy -->
<table class="body-sub" role="presentation">
<tr>
<td>
<p class="f-fallback sub">If youre having trouble with the button above, copy and paste the URL below into your web browser.</p>
<p class="f-fallback sub">{{ registrationUrl }}</p>
</td>
</tr>
</table>
</div> </div>
</td> </td>
</tr> </tr>
</tbody> </table>
</td>
</tr>
</table>
</td>
</tr>
</table> </table>

View File

@ -1,15 +1,62 @@
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"> <!-- Based on template: https://github.com/wildbit/postmark-templates/blob/master/templates/plain/password-reset/content.html -->
<tbody> <span class="preheader">Use this link to reset your password. The link is only valid for 24 hours.</span>
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr> <tr>
<td class="bg_dark email-section" style="text-align:center;"> <td align="center">
<div class="heading-section heading-section-white"> <table class="email-content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<span class="subheading">Budibase Password reset</span> <tr>
<h2>Please follow the below link to reset your password.</h2> <td class="email-masthead">
<p><a href="{{ resetUrl }}" class="btn btn-primary">Reset password</a></p> <a href="{{ platformUrl }}" class="f-fallback email-masthead_name">
<p>This password reset was required for {{ email }} if you did not {{ company }}
request this then please contact your administrator.</p> </a>
</td>
</tr>
<!-- Email Body -->
<tr>
<td class="email-body" width="570" cellpadding="0" cellspacing="0">
<table class="email-body_inner" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
<!-- Body content -->
<tr>
<td class="content-cell">
<div class="f-fallback">
<h1>Hi {{ email }},</h1>
<p>You recently requested to reset your password for your {{ company }} account in your Budibase platform. Use the button below to reset it. <strong>This password reset is only valid for the next 24 hours.</strong></p>
<!-- Action -->
<table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table width="100%" border="0" cellspacing="0" cellpadding="0" role="presentation">
<tr>
<td align="center">
<a href="{{ resetUrl }}" class="f-fallback button button--green" target="_blank">Reset your password</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
{{#if request}}
<p>For security, this request was received from a {{ request.os }} device.</p>
{{/if}}
<p>If you did not request a password reset, please ignore this email or contact support if you have questions.</p>
<p>Thanks,
<br>The {{ company }} Team</p>
<!-- Sub copy -->
<table class="body-sub" role="presentation">
<tr>
<td>
<p class="f-fallback sub">If youre having trouble with the button above, copy and paste the URL below into your web browser.</p>
<p class="f-fallback sub">{{ resetUrl }}</p>
</td>
</tr>
</table>
</div> </div>
</td> </td>
</tr> </tr>
</tbody> </table>
</td>
</tr>
</table>
</td>
</tr>
</table> </table>

View File

@ -1,269 +1,408 @@
@font-face { /* Based on templates: https://github.com/wildbit/postmark-templates/blob/master/templates/plain */
font-family: 'Playfair Display'; /* Base ------------------------------ */
font-style: italic;
font-weight: 400;
src: url(/fonts.gstatic.com/s/playfairdisplay/v22/nuFkD-vYSZviVYUb_rj3ij__anPXDTnohkk72xU.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
html,
body {
margin: 0 auto !important;
padding: 0 !important;
height: 100% !important;
width: 100% !important;
background: #f1f1f1;
}
* {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
div[style*="margin: 16px 0"] {
margin: 0 !important;
}
table,
td {
mso-table-lspace: 0pt !important;
mso-table-rspace: 0pt !important;
}
table {
border-spacing: 0 !important;
border-collapse: collapse !important;
table-layout: fixed !important;
margin: 0 auto !important;
}
img {
-ms-interpolation-mode:bicubic;
}
a {
text-decoration: none;
}
*[x-apple-data-detectors], /* iOS */
.unstyle-auto-detected-links *,
.aBn {
border-bottom: 0 !important;
cursor: default !important;
color: inherit !important;
text-decoration: none !important;
font-size: inherit !important;
font-family: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
}
.a6S {
display: none !important;
opacity: 0.01 !important;
}
.im {
color: inherit !important;
}
img.g-img + div {
display: none !important;
}
@media only screen and (min-device-width: 320px) and (max-device-width: 374px) {
u ~ div .email-container {
min-width: 320px !important;
}
}
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
u ~ div .email-container {
min-width: 375px !important;
}
}
@media only screen and (min-device-width: 414px) {
u ~ div .email-container {
min-width: 414px !important;
}
}
.primary{
background: #f3a333;
}
.bg_white{
background: #ffffff;
}
.bg_light{
background: #fafafa;
}
.bg_black{
background: #000000;
}
.bg_dark{
background: rgba(0,0,0,.8);
}
.email-section{
padding:2.5em;
}
.btn{
padding: 10px 15px;
}
.btn.btn-primary{
border-radius: 30px;
background: #f3a333;
color: #ffffff;
}
h1,h2,h3,h4,h5,h6{
font-family: 'Playfair Display', serif;
color: #000000;
margin-top: 0;
}
body{
font-family: 'Montserrat', sans-serif;
font-weight: 400;
font-size: 15px;
line-height: 1.8;
color: rgba(0,0,0,.4);
}
a{
color: #f3a333;
}
table{
}
.logo h1{
margin: 0;
}
.logo h1 a{
color: #000;
font-size: 20px;
font-weight: 700;
text-transform: uppercase;
font-family: 'Montserrat', sans-serif;
}
.hero{
position: relative;
}
.hero img{
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro&display=swap');
body {
width: 100% !important;
height: 100%;
margin: 0;
-webkit-text-size-adjust: none;
} }
.hero .text{
color: rgba(255,255,255,.8); a {
color: #3869D4;
} }
.hero .text h2{
color: #ffffff; a img {
font-size: 30px; border: none;
margin-bottom: 0;
} }
.heading-section{
td {
word-break: break-word;
} }
.heading-section h2{
color: #000000; .preheader {
font-size: 28px; display: none !important;
margin-top: 0; visibility: hidden;
line-height: 1.4; mso-hide: all;
font-size: 1px;
line-height: 1px;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
} }
.heading-section .subheading{ /* Type ------------------------------ */
margin-bottom: 20px !important;
display: inline-block; body,
font-size: 13px; td,
text-transform: uppercase; th {
letter-spacing: 2px; font-family: "Source Sans Pro", Helvetica, Arial, sans-serif;
color: rgba(0,0,0,.4);
position: relative;
} }
.heading-section .subheading::after{
position: absolute; h1 {
left: 0; margin-top: 0;
right: 0; color: #333333;
bottom: -10px; font-size: 22px;
content: ''; font-weight: bold;
width: 100%; text-align: left;
height: 2px;
background: #f3a333;
margin: 0 auto;
} }
.heading-section-white{
color: rgba(255,255,255,.8); h2 {
margin-top: 0;
color: #333333;
font-size: 16px;
font-weight: bold;
text-align: left;
} }
.heading-section-white h2{
font-size: 28px; h3 {
line-height: 1; margin-top: 0;
padding-bottom: 0; color: #333333;
font-size: 14px;
font-weight: bold;
text-align: left;
} }
.heading-section-white h2{
color: #ffffff; td,
th {
font-size: 16px;
} }
.heading-section-white .subheading{
margin-bottom: 0; p,
display: inline-block; ul,
font-size: 13px; ol,
text-transform: uppercase; blockquote {
letter-spacing: 2px; margin: .4em 0 1.1875em;
color: rgba(255,255,255,.4); font-size: 16px;
line-height: 1.625;
} }
.icon{
text-align: center; p.sub {
font-size: 13px;
} }
.icon img{ /* Utilities ------------------------------ */
.align-right {
text-align: right;
} }
.text-services{
padding: 10px 10px 0; .align-left {
text-align: center; text-align: left;
} }
.text-services h3{
font-size: 20px; .align-center {
text-align: center;
} }
.text-services .meta{ /* Buttons ------------------------------ */
text-transform: uppercase;
font-size: 14px; .button {
background-color: #3869D4;
border-top: 10px solid #3869D4;
border-right: 18px solid #3869D4;
border-bottom: 10px solid #3869D4;
border-left: 18px solid #3869D4;
display: inline-block;
color: #FFF;
text-decoration: none;
border-radius: 3px;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16);
-webkit-text-size-adjust: none;
box-sizing: border-box;
} }
.img{
width: 100%; .button--green {
height: auto; background-color: #22BC66;
position: relative; border-top: 10px solid #22BC66;
border-right: 18px solid #22BC66;
border-bottom: 10px solid #22BC66;
border-left: 18px solid #22BC66;
} }
.img .icon{
position: absolute; .button--red {
top: 50%; background-color: #FF6136;
left: 0; border-top: 10px solid #FF6136;
right: 0; border-right: 18px solid #FF6136;
bottom: 0; border-bottom: 10px solid #FF6136;
margin-top: -25px; border-left: 18px solid #FF6136;
} }
.img .icon a{
display: block; @media only screen and (max-width: 500px) {
width: 60px; .button {
position: absolute; width: 100% !important;
top: 0; text-align: center !important;
left: 50%;
margin-left: -25px;
} }
.counter-text{
text-align: center;
} }
.counter-text .num{ /* Attribute list ------------------------------ */
display: block;
color: #ffffff; .attributes {
font-size: 34px; margin: 0 0 21px;
font-weight: 700;
} }
.counter-text .name{
display: block; .attributes_content {
color: rgba(255,255,255,.9); background-color: #F4F4F7;
font-size: 13px; padding: 16px;
} }
.footer{
color: rgba(255,255,255,.5); .attributes_item {
padding: 0;
} }
.footer .heading{ /* Related Items ------------------------------ */
color: #ffffff;
font-size: 20px; .related {
width: 100%;
margin: 0;
padding: 25px 0 0 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
} }
.footer ul{
margin: 0; .related_item {
padding: 0; padding: 10px 0;
color: #CBCCCF;
font-size: 15px;
line-height: 18px;
} }
.footer ul li{
list-style: none; .related_item-title {
margin-bottom: 10px; display: block;
margin: .5em 0 0;
} }
.footer ul li a{
color: rgba(255,255,255,1); .related_item-thumb {
display: block;
padding-bottom: 10px;
} }
@media screen and (max-width: 500px) {
.icon{ .related_heading {
text-align: left; border-top: 1px solid #CBCCCF;
} text-align: center;
.text-services{ padding: 25px 0 10px;
padding-left: 0; }
padding-right: 20px; /* Discount Code ------------------------------ */
text-align: left;
} .discount {
width: 100%;
margin: 0;
padding: 24px;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
background-color: #F4F4F7;
border: 2px dashed #CBCCCF;
}
.discount_heading {
text-align: center;
}
.discount_body {
text-align: center;
font-size: 15px;
}
/* Social Icons ------------------------------ */
.social {
width: auto;
}
.social td {
padding: 0;
width: auto;
}
.social_icon {
height: 20px;
margin: 0 8px 10px 8px;
padding: 0;
}
/* Data table ------------------------------ */
.purchase {
width: 100%;
margin: 0;
padding: 35px 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.purchase_content {
width: 100%;
margin: 0;
padding: 25px 0 0 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.purchase_item {
padding: 10px 0;
color: #51545E;
font-size: 15px;
line-height: 18px;
}
.purchase_heading {
padding-bottom: 8px;
border-bottom: 1px solid #EAEAEC;
}
.purchase_heading p {
margin: 0;
color: #85878E;
font-size: 12px;
}
.purchase_footer {
padding-top: 15px;
border-top: 1px solid #EAEAEC;
}
.purchase_total {
margin: 0;
text-align: right;
font-weight: bold;
color: #333333;
}
.purchase_total--label {
padding: 0 15px 0 0;
}
body {
background-color: #FFF;
color: #333;
}
p {
color: #333;
}
.email-wrapper {
width: 100%;
margin: 0;
padding: 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.email-content {
width: 100%;
margin: 0;
padding: 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
/* Masthead ----------------------- */
.email-masthead {
padding: 25px 0;
text-align: center;
}
.email-masthead_logo {
width: 94px;
}
.email-masthead_name {
font-size: 16px;
font-weight: bold;
color: #A8AAAF;
text-decoration: none;
text-shadow: 0 1px 0 white;
}
/* Body ------------------------------ */
.email-body {
width: 100%;
margin: 0;
padding: 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.email-body_inner {
width: 570px;
margin: 0 auto;
padding: 0;
-premailer-width: 570px;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
}
.email-footer {
width: 570px;
margin: 0 auto;
padding: 0;
-premailer-width: 570px;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
text-align: center;
}
.email-footer p {
color: #A8AAAF;
}
.body-action {
width: 100%;
margin: 30px auto;
padding: 0;
-premailer-width: 100%;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
text-align: center;
}
.body-sub {
margin-top: 25px;
padding-top: 25px;
border-top: 1px solid #EAEAEC;
}
.content-cell {
padding: 35px;
}
/*Media Queries ------------------------------ */
@media only screen and (max-width: 600px) {
.email-body_inner,
.email-footer {
width: 100% !important;
}
}
@media (prefers-color-scheme: dark) {
body {
background-color: #333333 !important;
color: #FFF !important;
}
p,
ul,
ol,
blockquote,
h1,
h2,
h3,
span,
.purchase_item {
color: #FFF !important;
}
.attributes_content,
.discount {
background-color: #222 !important;
}
.email-masthead_name {
text-shadow: none !important;
}
}
:root {
color-scheme: light dark;
supported-color-schemes: light dark;
} }

View File

@ -0,0 +1,62 @@
<!-- Based on template: https://github.com/wildbit/postmark-templates/blob/master/templates/plain/welcome/content.html -->
<span class="preheader">Thanks for trying out [Product Name]. Weve pulled together some information and resources to help you get started.</span>
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table class="email-content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="email-masthead">
<a href="https://example.com" class="f-fallback email-masthead_name">
{{ company }}
</a>
</td>
</tr>
<!-- Email Body -->
<tr>
<td class="email-body" width="570" cellpadding="0" cellspacing="0">
<table class="email-body_inner" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
<!-- Body content -->
<tr>
<td class="content-cell">
<div class="f-fallback">
<h1>Welcome, {{ email }}!</h1>
<p>Thanks for getting started with {{ company }}'s Budibase platform.</p>
<p>For reference, here's your login information:</p>
<table class="attributes" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="attributes_content">
<table width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="attributes_item">
<span class="f-fallback">
<strong>Login Page:</strong> <a href="{{ loginUrl }}">{{ loginUrl }}</a>
</span>
</td>
</tr>
{{#if request}}
<tr>
<td class="attributes_item">
<span class="f-fallback">
<strong>Username:</strong> {{ request.loginUsername }}
</span>
</td>
</tr>
{{/if}}
</table>
</td>
</tr>
</table>
<p>If you have any questions get in contact with your {{ company }}'s Budibase platform administration team.</p>
<p>Thanks,
<br>The {{ company }} Team</p>
<p><strong>P.S.</strong> Need immediate help getting started? Check out our <a href="{{ docsUrl }}">help documentation</a>.</p>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>

View File

@ -28,5 +28,7 @@ exports.getSettingsTemplateContext = async () => {
), ),
[TemplateBindings.RESET_URL]: checkSlashesInUrl(`${URL}/reset`), [TemplateBindings.RESET_URL]: checkSlashesInUrl(`${URL}/reset`),
[TemplateBindings.COMPANY]: settings.company || BASE_COMPANY, [TemplateBindings.COMPANY]: settings.company || BASE_COMPANY,
[TemplateBindings.DOCS_URL]: settings.docsUrl || "https://docs.budibase.com/",
[TemplateBindings.LOGIN_URL]: checkSlashesInUrl(`${URL}/login`),
} }
} }