nextmail
v0.4.3
Published
Craft emails in React and MJML. Inspired by Next.js.
Downloads
6
Readme
Nextmail makes it easy to leverage React
and MJML
to craft custom, dynamic email templates.
- Declarative, component-based model with React
- Responsive out of the box with MJML
- Iterate quickly with browser previews
- Unit test with
jest
or however you choose, the same way you test your front end - Fetch asynchronous data with
getInitialProps
, inspired by Next.js - File based API, inspired by the
pages
model in Next.js
How to use
Setup
Install it:
npm install --save nextmail react react-dom
and add a script to your package.json like this:
{
"scripts": {
"dev": "nextmail dev",
"build": "nextmail build"
}
}
After that, the file system is the main API. Every .js
file becomes an email that gets automatically processed and rendered.
Populate ./emails/demo.js
inside your project:
import React from 'react';
import {
Mjml, MjmlBody, MjmlColumn, MjmlSection, MjmlText,
} from 'nextmail/mjml-react';
function Demo() {
return (
<Mjml>
<MjmlBody>
<MjmlSection>
<MjmlColumn>
<MjmlText align="center">Welcome to Nextmail!</MjmlText>
</MjmlColumn>
</MjmlSection>
</MjmlBody>
</Mjml>
);
}
export default Demo;
and then just run npm run dev
and go to http://localhost:6100
to view a preview.
API
Renderer
Generate email data with a single function call.
const renderer = new Renderer();
const { html, text, subject } = await renderEmail('demo', {});
Arguments
- template (string): The name of the email template.
- payload (Object): Any dynamic data you need to interpolate in the email template (e.g. a user's name).
Returns
An Object
with the following properties:
- html (string): The fully rendered html.
- text (string): The converted text of the email.
nextmail
uses html-to-text for this conversion. - subject (string): The fully rendered subject line.
Fetch asynchronous data with getInitialProps
In similar fashion to Next.js, you can implement getInitialProps
to asynchronously fetch data at render time.
function Demo() {
...
}
// payload = { userId: 1 }
Demo.getInitialProps = async ({ payload }) => {
const { userId } = payload;
const resp = await axios.get(`https://jsonplaceholder.typicode.com/users/${userId}`);
return { user: resp.data };
};
Be careful with this functionality. In many systems, emails are sent asynchronously. The underlying data store can change from when the email was triggered to when it is rendered. If you need the data to be locked in when the email is triggered, be sure that makes its way into the payload
. If you are okay with using data that is later updated (e.g. the user changes their name), you can use getInitialProps
.
Render email subjects with getSubject
Implement getSubject
to hydrate the subject
of the response to renderEmail
. getSubject
is called after getInitialProps
and will have access to the initial props.
function Demo() {
...
}
// props = { user: { name: 'Leanne Graham' } }
Demo.getSubject = async ({ props }) => {
const { user } = props;
return `${user.name}! Act now!`; // Leanne Graham! Act now!
}
Custom components
Custom React
components allow you to implement reusable elements in your email templates. Since Nextmail
is compiling emails in your emails
directory, you need to place your components in a special directory called src
.
/emails
/src
Header.js <---- This will compile
demo.js
/other
NotCompiled.js <---- This will not
Q: Why not just include Header.js
inside the emails
directory?
A: Nextmail
needs the ability to distinguish email templates from other components. For example, the preview index lists all available email templates to preview.
Previews
The nextmail dev
script allows you to view a preview of your email template.
The preview route follows this format: /preview/:format/:template
format
can be eitherhtml
ortext
template
is the file path for your template, e.g. if your file is found at./emails/demo.js
, thetemplate
would bedemo
Test payloads with query strings
If your email template requires payload data, you can add the payload via query string:
http://localhost:6100/html/demo?firstName=Lisa
-> { firstName: 'Lisa'}
Nested objects and arrays are also supported. See qs for formatting options.
Configuration
You can configure Nextmail
by adding a nextmail.config.js
file to the root of your project directory and exporting a configuration object.
// nextmail.config.js
module.exports = { ... };
Configuring nodemailer for test sends
Configure options for nodemailer.createTransport(...)
. See Sending Previews.
// nextmail.config.js
module.exports = {
send: {
smtpConfig: {
host: 'smtp.mailtrap.io',
port: 2525,
auth: {
user: '****',
pass: '****',
},
},
}
};
Configuring mailOptions for test sends
Override the mailOptions
sent to nodemailer's transport.sendMail(...)
// nextmail.config.js
module.exports = {
send: {
mailOptions: {
from: '[email protected]',
to: '[email protected]',
},
}
};
Configuring payloads for testing
Test payloads are used when Sending Previews and are also used to dynamically build links in the preview index page for convenience.
// nextmail.config.js
// This configures 2 test payloads for the "demo" email
module.exports = {
payloads: {
demo: {
default: {
userId: 1,
},
user2: {
userId: 2,
},
},
},
};
Sending Previews
Mailtrap is an excellent service that helps you capture test emails. Once configured, you can add an additional script to your package.json
: "send": "nodemailer send"
. Then run one of the following commands.
# Sends the demo.js email with a default payload
npm run send demo
# Sends the demo.js email with the named "user2" payload
npm run send demo user2
Static assets
Add static assets to the /static
directory:
/emails
demo.js
/static
/bicycle.jpeg
Then you can reference them in your components:
<MjmlImage src="/static/bicycle.jpeg" />
For production, you will need to publish your assets to a known host and use absolute URLs in your components. One way you can do this is to add a config.js
file under your src
directory.
const isProd = process.env.NODE_ENV === 'production';
export default {
assetPrefix: isProd ? 'https://nextmail-latest.now.sh' : '',
};
Then reference the config
in your component.
import config from '../config';
function WithImage() {
...
<MjmlImage src={`${config.assetPrefix}/static/bicycle.jpeg`} />
...
}
See the with-image example.
Exporting nextmail
templates as a package
You can build and export email templates as an npm
package. In order to do this, you need to tell nextmail
where to find the build templates with the rootDirectory
option.
const path = require('path');
const { Renderer } = require('nextmail');
const renderer = new Renderer({ rootDirectory: path.resolve(__dirname) });
async function renderEmail(...args) {
// You can also implement custom post-processing logic here too.
return renderer.renderEmail(...args);
}
module.exports = { renderEmail };
Debugging
To see verbose log output, including captured payload, initial props, etc. when developing: DEBUG=nextmail npm run dev