Skip to main content

Plain HTML

The editor on a page with no bundler and no framework: one script tag. Two files in all, served by one small Express server that also mints the editor's tokens.

You need a project's two test keys from lettrove.com → Settings → Embed (step 1 of the Quickstart), and Node.js 20.19 or newer.

1. Make a folder and install two packages​

mkdir lettrove-html
cd lettrove-html
npm init -y
npm install express @lettrove/node

Create a file called .env in that folder with your secret key in it:

.env
LETTROVE_SECRET_KEY=lt_sk_test_paste_yours_here

2. The server: one file​

The editor opens with a short-lived token. Your server mints it with the secret key, so the secret key never reaches a browser. Create server.mjs:

server.mjs
import express from 'express';
import { Lettrove } from '@lettrove/node';

const lettrove = new Lettrove({ secretKey: process.env.LETTROVE_SECRET_KEY });
const app = express();

// Serves public/index.html, the page with the editor.
app.use(express.static('public'));

// The page asks this route for a token whenever the editor needs one.
app.post('/lettrove-token', async (req, res) => {
// In your product: your own id for the signed-in person, from your session.
const userId = 'demo-user';
try {
const { token } = await lettrove.tokens.create({
user: { id: userId },
origin: req.get('origin'), // the page the editor opens on
});
res.set('Cache-Control', 'no-store').json({ token });
} catch (error) {
console.error(error);
res.status(500).json({ error: error.message, code: error.code });
}
});

app.listen(3000, () => console.log('Open http://localhost:3000'));

3. The page: one file​

Create a folder called public, and in it index.html. Replace lt_pk_test_paste_yours_here with your publishable key.

public/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My email editor</title>
<style>
body { margin: 0; }
#editor { height: 100vh; } /* the editor fills its box, so give the box a height */
</style>
</head>
<body>
<div id="editor"></div>

<script src="https://cdn.jsdelivr.net/npm/@lettrove/embed@1/dist/lettrove.iife.js"></script>
<script>
async function getToken() {
const response = await fetch('/lettrove-token', { method: 'POST' });
return (await response.json()).token;
}

Lettrove.createEditor({
container: '#editor',
publishableKey: 'lt_pk_test_paste_yours_here',
getToken,
on: {
'design:saved': ({ designId }) => console.log('saved', designId),
},
}).then((editor) => {
window.editor = editor; // so you can try it from the browser console
});
</script>
</body>
</html>

@1 follows the newest 1.x of the loader. To pin an exact version, write it in full (@lettrove/embed@1.0.0).

4. Run it​

node --env-file=.env server.mjs

Open http://localhost:3000. The editor loads in the page.

  1. In the panel on the left, click Heading (or drag it onto the email). A heading appears; click it to type your own words.

  2. Open your browser's console (in Chrome: View → Developer → JavaScript Console). Within a moment of your edit it shows:

    saved 01J9ZQ3W8D2K7M5T1V4XG6HB0R

That id is the design. Lettrove saves as your user works; in your product you store the id with your own record and pass it back as designId to open the same design again.

5. Get the email out​

In the same console, type:

const email = await editor.exportHtml();
email.html;

That is the whole email as HTML, compiled for Gmail, Outlook and Apple Mail, ready to send with any email provider. email.subject is its subject, and email.mergeTags lists tags such as {{unsubscribe_url}} for you to fill before sending (Merge tags).

Next​