Merge branch 'feature/transactional_email_#44'

Closes #44
This commit is contained in:
cleverbeagle 2017-09-07 17:39:00 -05:00
commit 2b45fd5842
17 changed files with 2234 additions and 804 deletions

View file

@ -5,7 +5,7 @@ import editProfile from './edit-profile';
import rateLimit from '../../../modules/rate-limit';
Meteor.methods({
'users.sendVerificationEmail': function usersResendVerification() {
'users.sendVerificationEmail': function usersSendVerificationEmail() {
return Accounts.sendVerificationEmail(this.userId);
},
'users.editProfile': function usersEditProfile(profile) {

View file

@ -0,0 +1,25 @@
import sendEmail from '../../../modules/server/send-email';
import getOAuthProfile from '../../../modules/get-oauth-profile';
export default (options, user) => {
const OAuthProfile = getOAuthProfile(options, user);
const applicationName = 'Application Name';
const firstName = OAuthProfile ? OAuthProfile.name.first : options.profile.name.first;
const emailAddress = OAuthProfile ? OAuthProfile.email : options.email;
return sendEmail({
to: emailAddress,
from: `${applicationName} <support@application.com>`,
subject: `[${applicationName}] Welcome, ${firstName}!`,
template: 'welcome',
templateVars: {
applicationName,
firstName,
welcomeUrl: Meteor.absoluteUrl('documents'), // e.g., returns http://localhost:3000/documents
},
})
.catch((error) => {
throw new Meteor.Error('500', `${error}`);
});
};

View file

@ -0,0 +1,42 @@
const parseGoogleData = service => {
return {
email: service.email,
name: {
first: service.given_name,
last: service.family_name,
},
};
};
const parseGithubData = (profile, service) => {
const name = profile.name.split(' ');
return {
email: service.email,
name: {
first: name[0],
last: name[1],
},
};
};
const parseFacebookData = service => {
return {
email: service.email,
name: {
first: service.first_name,
last: service.last_name,
},
};
};
const getDataForService = (profile, services) => {
if (services.facebook) return parseFacebookData(services.facebook);
if (services.github) return parseGithubData(profile, services.github);
if (services.google) return parseGoogleData(services.google);
};
export default (options, user) => {
const isOAuth = !options.password;
const serviceData = isOAuth ? getDataForService(options.profile, user.services) : null;
return isOAuth ? serviceData : null;
};

View file

@ -0,0 +1,11 @@
import handlebars from 'handlebars';
import juice from 'juice';
export default (handlebarsMarkup, context, options) => {
if (handlebarsMarkup && context) {
const template = handlebars.compile(handlebarsMarkup);
return options && !options.inlineCss ? template(context) : juice(template(context)); // Use juice to inline CSS <style></style> styles from <head> unless disabled.
}
throw new Error('Please pass Handlebars markup to compile and a context object with data mapping to the Handlebars expressions used in your template.');
};

View file

@ -0,0 +1,10 @@
import handlebars from 'handlebars';
export default (handlebarsMarkup, context) => {
if (handlebarsMarkup && context) {
const template = handlebars.compile(handlebarsMarkup);
return template(context);
}
throw new Error('Please pass Handlebars markup to compile and a context object with data mapping to the Handlebars expressions used in your template.');
};

View file

@ -0,0 +1,26 @@
import { Email } from 'meteor/email';
import getPrivateFile from './get-private-file';
import templateToText from './handlebars-email-to-text';
import templateToHTML from './handlebars-email-to-html';
const sendEmail = (options, { resolve, reject }) => {
try {
Meteor.defer(() => Email.send(options));
if (callback) resolve();
} catch (exception) {
reject(exception);
}
};
export default ({ text, html, template, templateVars, ...rest }, callback) => {
if (text || html || template) {
return new Promise((resolve, reject) => {
sendEmail({
...rest,
text: template ? templateToText(getPrivateFile(`email-templates/${template}.txt`), (templateVars || {})) : text,
html: template ? templateToHTML(getPrivateFile(`email-templates/${template}.html`), (templateVars || {})) : html,
}, { resolve, reject });
});
}
throw new Error('Please pass an HTML string, text, or template name to compile for your message\'s body.');
};

View file

@ -1,5 +1,8 @@
import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import getPrivateFile from '../../../modules/server/get-private-file';
import templateToHTML from '../../../modules/server/handlebars-email-to-html';
import templateToText from '../../../modules/server/handlebars-email-to-text';
const name = 'Application Name';
const email = '<support@application.com>';
@ -13,11 +16,21 @@ emailTemplates.verifyEmail = {
subject() {
return `[${name}] Verify Your Email Address`;
},
html(user, url) {
return templateToHTML(getPrivateFile('email-templates/verify-email.html'), {
applicationName: name,
firstName: user.profile.name.first,
verifyUrl: url.replace('#/', '')
});
},
text(user, url) {
const userEmail = user.emails[0].address;
const urlWithoutHash = url.replace('#/', '');
if (Meteor.isDevelopment) console.info(`Verify Email Link: ${urlWithoutHash}`); // eslint-disable-line
return `Hey, ${user.profile.name.first}! Welcome to ${name}.\n\nTo verify your email address (${userEmail}), click the link below:\n\n${urlWithoutHash}\n\nIf you feel something is wrong, please contact our support team: ${email}.`;
return templateToText(getPrivateFile('email-templates/verify-email.txt'), {
applicationName: name,
firstName: user.profile.name.first,
verifyUrl: urlWithoutHash,
});
},
};
@ -25,10 +38,22 @@ emailTemplates.resetPassword = {
subject() {
return `[${name}] Reset Your Password`;
},
html(user, url) {
return templateToHTML(getPrivateFile('email-templates/reset-password.html'), {
firstName: user.profile.name.first,
applicationName: name,
emailAddress: user.emails[0].address,
resetUrl: url.replace('#/', ''),
});
},
text(user, url) {
const userEmail = user.emails[0].address;
const urlWithoutHash = url.replace('#/', '');
if (Meteor.isDevelopment) console.info(`Reset Password Link: ${urlWithoutHash}`); // eslint-disable-line
return `A password reset has been requested for the account related to this address (${userEmail}).\n\nTo reset the password, visit the following link: \n\n${urlWithoutHash}\n\n If you did not request this reset, please ignore this email. If you feel something is wrong, please contact our support team: ${email}.`;
return templateToText(getPrivateFile('email-templates/reset-password.txt'), {
firstName: user.profile.name.first,
applicationName: name,
emailAddress: user.emails[0].address,
resetUrl: urlWithoutHash,
});
},
};

View file

@ -1,7 +1,9 @@
import { Accounts } from 'meteor/accounts-base';
import sendWelcomeEmail from '../../../api/Users/server/send-welcome-email';
Accounts.onCreateUser((options, user) => {
const userToCreate = user;
if (options.profile) userToCreate.profile = options.profile;
sendWelcomeEmail(options, user);
return userToCreate;
});

View file

@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Alert } from 'react-bootstrap';
import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import { Bert } from 'meteor/themeteorchef:bert';
@ -20,7 +21,7 @@ class VerifyEmail extends React.Component {
setTimeout(() => {
Bert.alert('All set, thanks!', 'success');
history.push('/documents');
}, 2000);
}, 1500);
}
});
}

1880
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -12,8 +12,11 @@
"bcrypt": "^1.0.3",
"commonmark": "^0.28.1",
"core-js": "^2.5.1",
"fs": "0.0.1-security",
"handlebars": "^4.0.10",
"jquery": "^2.2.4",
"jquery-validation": "^1.17.0",
"juice": "^4.1.1",
"lodash": "^4.17.4",
"meteor-node-stubs": "^0.2.11",
"prop-types": "^15.5.10",

View file

@ -0,0 +1,322 @@
<!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>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>[{{applicationName}}] Reset Your Password</title>
<style>
/* -------------------------------------
GLOBAL
A very basic CSS reset
------------------------------------- */
* {
margin: 0;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
box-sizing: border-box;
font-size: 14px;
}
img {
max-width: 100%;
}
body {
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: none;
width: 100% !important;
height: 100%;
line-height: 1.6em;
/* 1.6em * 14px = 22.4px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 22px;*/
}
/* Let's make sure all tables have defaults */
table td {
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
body {
background-color: #f6f6f6;
}
.body-wrap {
background-color: #f6f6f6;
width: 100%;
}
.container {
display: block !important;
max-width: 600px !important;
margin: 0 auto !important;
/* makes it centered */
clear: both !important;
}
.content {
max-width: 600px;
margin: 0 auto;
display: block;
padding: 20px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background-color: #fff;
border: 1px solid #e9e9e9;
border-radius: 3px;
}
.content-wrap {
padding: 20px;
}
.content-block {
padding: 0 0 20px;
}
.header {
width: 100%;
margin-bottom: 20px;
}
.footer {
width: 100%;
clear: both;
color: #999;
padding: 20px;
}
.footer p, .footer a, .footer td {
color: #999;
font-size: 12px;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1, h2, h3 {
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
color: #000;
margin: 40px 0 0;
line-height: 1.2em;
font-weight: 400;
}
h1 {
font-size: 32px;
font-weight: 500;
/* 1.2em * 32px = 38.4px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 38px;*/
}
h2 {
font-size: 24px;
/* 1.2em * 24px = 28.8px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 29px;*/
}
h3 {
font-size: 18px;
/* 1.2em * 18px = 21.6px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 22px;*/
}
h4 {
font-size: 14px;
font-weight: 600;
}
p, ul, ol {
margin-bottom: 10px;
font-weight: normal;
}
p li, ul li, ol li {
margin-left: 5px;
list-style-position: inside;
}
/* -------------------------------------
LINKS & BUTTONS
------------------------------------- */
a {
color: #348eda;
text-decoration: underline;
}
.btn-primary {
text-decoration: none;
color: #FFF;
background-color: #4285F4;
border: solid #4285F4;
border-width: 10px 20px;
line-height: 2em;
/* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 28px;*/
font-weight: bold;
text-align: center;
cursor: pointer;
display: inline-block;
border-radius: 2px;
text-transform: capitalize;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.aligncenter {
text-align: center;
}
.alignright {
text-align: right;
}
.alignleft {
text-align: left;
}
.clear {
clear: both;
}
/* -------------------------------------
ALERTS
Change the class depending on warning email, good email or bad email
------------------------------------- */
.alert {
font-size: 16px;
color: #fff;
font-weight: 500;
padding: 20px;
text-align: center;
border-radius: 3px 3px 0 0;
}
.alert a {
color: #fff;
text-decoration: none;
font-weight: 500;
font-size: 16px;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 640px) {
body {
padding: 0 !important;
}
h1, h2, h3, h4 {
font-weight: 800 !important;
margin: 20px 0 5px !important;
}
h1 {
font-size: 22px !important;
}
h2 {
font-size: 18px !important;
}
h3 {
font-size: 16px !important;
}
.container {
padding: 0 !important;
width: 100% !important;
}
.content {
padding: 0 !important;
}
.content-wrap {
padding: 10px !important;
}
.invoice {
width: 100% !important;
}
}
</style>
</head>
<body itemscope itemtype="http://schema.org/EmailMessage">
<table class="body-wrap">
<tr>
<td></td>
<td class="container" width="600">
<div class="content">
<table class="main" width="100%" cellpadding="0" cellspacing="0" itemprop="action" itemscope itemtype="http://schema.org/UpdateAction">
<tr>
<td class="content-wrap">
<meta itemprop="name" content="Reset Password"/>
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
Hey, {{firstName}}!
</td>
</tr>
<tr>
<td class="content-block">
A password reset has been requested for the account related to this email address ({{emailAddress}}).
</td>
</tr>
<tr>
<td class="content-block">
To reset the password, visit the following link:
</td>
</tr>
<tr>
<td class="content-block" itemprop="handler" itemscope itemtype="http://schema.org/HttpActionHandler">
<a href="{{resetUrl}}" class="btn-primary" itemprop="url">Reset Password</a>
</td>
</tr>
<tr>
<td class="content-block">
Cheers, <br />
{{applicationName}} Team
</td>
</tr>
</table>
</td>
</tr>
</table>
<div class="footer">
<table width="100%">
<tr>
<td class="aligncenter content-block">Follow <a href="http://twitter.com/application">@application</a> on Twitter.</td>
</tr>
</table>
</div></div>
</td>
<td></td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,10 @@
Hey, {{firstName}}!
A password reset has been requested for the account related to this email address ({{emailAddress}}).
To reset the password, visit the following link:
[Reset Password]({{resetUrl}})
Cheers,
{{applicationName}} Team

View file

@ -0,0 +1,317 @@
<!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>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>[{{applicationName}}] Verify Your Email Address</title>
<style>
/* -------------------------------------
GLOBAL
A very basic CSS reset
------------------------------------- */
* {
margin: 0;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
box-sizing: border-box;
font-size: 14px;
}
img {
max-width: 100%;
}
body {
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: none;
width: 100% !important;
height: 100%;
line-height: 1.6em;
/* 1.6em * 14px = 22.4px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 22px;*/
}
/* Let's make sure all tables have defaults */
table td {
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
body {
background-color: #f6f6f6;
}
.body-wrap {
background-color: #f6f6f6;
width: 100%;
}
.container {
display: block !important;
max-width: 600px !important;
margin: 0 auto !important;
/* makes it centered */
clear: both !important;
}
.content {
max-width: 600px;
margin: 0 auto;
display: block;
padding: 20px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background-color: #fff;
border: 1px solid #e9e9e9;
border-radius: 3px;
}
.content-wrap {
padding: 20px;
}
.content-block {
padding: 0 0 20px;
}
.header {
width: 100%;
margin-bottom: 20px;
}
.footer {
width: 100%;
clear: both;
color: #999;
padding: 20px;
}
.footer p, .footer a, .footer td {
color: #999;
font-size: 12px;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1, h2, h3 {
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
color: #000;
margin: 40px 0 0;
line-height: 1.2em;
font-weight: 400;
}
h1 {
font-size: 32px;
font-weight: 500;
/* 1.2em * 32px = 38.4px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 38px;*/
}
h2 {
font-size: 24px;
/* 1.2em * 24px = 28.8px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 29px;*/
}
h3 {
font-size: 18px;
/* 1.2em * 18px = 21.6px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 22px;*/
}
h4 {
font-size: 14px;
font-weight: 600;
}
p, ul, ol {
margin-bottom: 10px;
font-weight: normal;
}
p li, ul li, ol li {
margin-left: 5px;
list-style-position: inside;
}
/* -------------------------------------
LINKS & BUTTONS
------------------------------------- */
a {
color: #348eda;
text-decoration: underline;
}
.btn-primary {
text-decoration: none;
color: #FFF;
background-color: #4285F4;
border: solid #4285F4;
border-width: 10px 20px;
line-height: 2em;
/* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 28px;*/
font-weight: bold;
text-align: center;
cursor: pointer;
display: inline-block;
border-radius: 2px;
text-transform: capitalize;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.aligncenter {
text-align: center;
}
.alignright {
text-align: right;
}
.alignleft {
text-align: left;
}
.clear {
clear: both;
}
/* -------------------------------------
ALERTS
Change the class depending on warning email, good email or bad email
------------------------------------- */
.alert {
font-size: 16px;
color: #fff;
font-weight: 500;
padding: 20px;
text-align: center;
border-radius: 3px 3px 0 0;
}
.alert a {
color: #fff;
text-decoration: none;
font-weight: 500;
font-size: 16px;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 640px) {
body {
padding: 0 !important;
}
h1, h2, h3, h4 {
font-weight: 800 !important;
margin: 20px 0 5px !important;
}
h1 {
font-size: 22px !important;
}
h2 {
font-size: 18px !important;
}
h3 {
font-size: 16px !important;
}
.container {
padding: 0 !important;
width: 100% !important;
}
.content {
padding: 0 !important;
}
.content-wrap {
padding: 10px !important;
}
.invoice {
width: 100% !important;
}
}
</style>
</head>
<body itemscope itemtype="http://schema.org/EmailMessage">
<table class="body-wrap">
<tr>
<td></td>
<td class="container" width="600">
<div class="content">
<table class="main" width="100%" cellpadding="0" cellspacing="0" itemprop="action" itemscope itemtype="http://schema.org/ConfirmAction">
<tr>
<td class="content-wrap">
<meta itemprop="name" content="Verify Email Address"/>
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
Hey, {{firstName}}!
</td>
</tr>
<tr>
<td class="content-block">
Can you do us a favor and verify your email address?
</td>
</tr>
<tr>
<td class="content-block" itemprop="handler" itemscope itemtype="http://schema.org/HttpActionHandler">
<a href="{{verifyUrl}}" class="btn-primary" itemprop="url">Verify Email Address</a>
</td>
</tr>
<tr>
<td class="content-block">
Thanks! <br />
{{applicationName}} Team
</td>
</tr>
</table>
</td>
</tr>
</table>
<div class="footer">
<table width="100%">
<tr>
<td class="aligncenter content-block">Follow <a href="http://twitter.com/application">@application</a> on Twitter.</td>
</tr>
</table>
</div></div>
</td>
<td></td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,8 @@
Hey, {{firstName}}!
Can you do us a favor and verify your email address?
[Verify Email Address]({{verifyUrl}})
Thanks!
{{applicationName}} Team

View file

@ -0,0 +1,322 @@
<!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>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Welcome! | {{applicationName}}</title>
<style>
/* -------------------------------------
GLOBAL
A very basic CSS reset
------------------------------------- */
* {
margin: 0;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
box-sizing: border-box;
font-size: 14px;
}
img {
max-width: 100%;
}
body {
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: none;
width: 100% !important;
height: 100%;
line-height: 1.6em;
/* 1.6em * 14px = 22.4px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 22px;*/
}
/* Let's make sure all tables have defaults */
table td {
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
body {
background-color: #f6f6f6;
}
.body-wrap {
background-color: #f6f6f6;
width: 100%;
}
.container {
display: block !important;
max-width: 600px !important;
margin: 0 auto !important;
/* makes it centered */
clear: both !important;
}
.content {
max-width: 600px;
margin: 0 auto;
display: block;
padding: 20px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background-color: #fff;
border: 1px solid #e9e9e9;
border-radius: 3px;
}
.content-wrap {
padding: 20px;
}
.content-block {
padding: 0 0 20px;
}
.header {
width: 100%;
margin-bottom: 20px;
}
.footer {
width: 100%;
clear: both;
color: #999;
padding: 20px;
}
.footer p, .footer a, .footer td {
color: #999;
font-size: 12px;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1, h2, h3 {
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
color: #000;
margin: 40px 0 0;
line-height: 1.2em;
font-weight: 400;
}
h1 {
font-size: 32px;
font-weight: 500;
/* 1.2em * 32px = 38.4px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 38px;*/
}
h2 {
font-size: 24px;
/* 1.2em * 24px = 28.8px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 29px;*/
}
h3 {
font-size: 18px;
/* 1.2em * 18px = 21.6px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 22px;*/
}
h4 {
font-size: 14px;
font-weight: 600;
}
p, ul, ol {
margin-bottom: 10px;
font-weight: normal;
}
p li, ul li, ol li {
margin-left: 5px;
list-style-position: inside;
}
/* -------------------------------------
LINKS & BUTTONS
------------------------------------- */
a {
color: #348eda;
text-decoration: underline;
}
.btn-primary {
text-decoration: none;
color: #FFF;
background-color: #4285F4;
border: solid #4285F4;
border-width: 10px 20px;
line-height: 2em;
/* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */
/*line-height: 28px;*/
font-weight: bold;
text-align: center;
cursor: pointer;
display: inline-block;
border-radius: 2px;
text-transform: capitalize;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.aligncenter {
text-align: center;
}
.alignright {
text-align: right;
}
.alignleft {
text-align: left;
}
.clear {
clear: both;
}
/* -------------------------------------
ALERTS
Change the class depending on warning email, good email or bad email
------------------------------------- */
.alert {
font-size: 16px;
color: #fff;
font-weight: 500;
padding: 20px;
text-align: center;
border-radius: 3px 3px 0 0;
}
.alert a {
color: #fff;
text-decoration: none;
font-weight: 500;
font-size: 16px;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 640px) {
body {
padding: 0 !important;
}
h1, h2, h3, h4 {
font-weight: 800 !important;
margin: 20px 0 5px !important;
}
h1 {
font-size: 22px !important;
}
h2 {
font-size: 18px !important;
}
h3 {
font-size: 16px !important;
}
.container {
padding: 0 !important;
width: 100% !important;
}
.content {
padding: 0 !important;
}
.content-wrap {
padding: 10px !important;
}
.invoice {
width: 100% !important;
}
}
</style>
</head>
<body itemscope itemtype="http://schema.org/EmailMessage">
<table class="body-wrap">
<tr>
<td></td>
<td class="container" width="600">
<div class="content">
<table class="main" width="100%" cellpadding="0" cellspacing="0" itemprop="action" itemscope itemtype="http://schema.org/JoinAction">
<tr>
<td class="content-wrap">
<meta itemprop="name" content="Welcome"/>
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
Hey, {{firstName}}!
</td>
</tr>
<tr>
<td class="content-block">
Welcome to {{applicationName}}. We're excited to have you on board.
</td>
</tr>
<tr>
<td class="content-block">
Ready to get started?
</td>
</tr>
<tr>
<td class="content-block" itemprop="handler" itemscope itemtype="http://schema.org/HttpActionHandler">
<a href="{{welcomeUrl}}" class="btn-primary" itemprop="url">View Your Documents</a>
</td>
</tr>
<tr>
<td class="content-block">
Cheers, <br />
{{applicationName}} Team
</td>
</tr>
</table>
</td>
</tr>
</table>
<div class="footer">
<table width="100%">
<tr>
<td class="aligncenter content-block">Follow <a href="http://twitter.com/application">@application</a> on Twitter.</td>
</tr>
</table>
</div></div>
</td>
<td></td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,10 @@
Hey, {{firstName}}!
Welcome to Application Name. We're excited to have you on board.
Ready to get started?
[View Your Documents]({{welcomeUrl}})
Cheers,
Application Name Team