Appearance
1. Get an API key
Sign up at app.maillune.com and create an API key from the Keys page.
Keep your API key on the server
Your API key grants full access to your account. Never put it in client-side code, a public env var, or the browser DOM. Use short-lived session tokens for the browser SDK — see step 3.
2. Install
bash
npm install @maillune/sdkbash
yarn add @maillune/sdkbash
pnpm add @maillune/sdkhtml
<script src="https://cdn.jsdelivr.net/npm/@maillune/sdk/dist/email-builder.umd.js"></script>3. Exchange for a session token (your server)
Before rendering the editor, your backend exchanges the secret API key for a short-lived session token scoped to the current user. The token lives for 2 hours and is safe to use in the browser.
js
// Node / Express — called once per page load, per user
app.get('/api/editor-session', requireAuth, async (req, res) => {
const { sessionToken } = await fetch('https://api.maillune.com/v1/sessions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.MAILLUNE_SECRET_KEY}`, // server-only env var
'Content-Type': 'application/json',
},
body: JSON.stringify({ userId: req.user.id }),
}).then(r => r.json());
res.json({ sessionToken });
});4. Embed the builder (your frontend)
Pass the session token — not your secret key — to the api-key attribute:
html
<!doctype html>
<html>
<head>
<script type="module">
import '@maillune/sdk';
// 1. Fetch the token from your own backend
const { sessionToken } = await fetch('/api/editor-session').then(r => r.json());
// 2. Set it on the element
document.getElementById('builder').setAttribute('api-key', sessionToken);
</script>
</head>
<body>
<div style="height: 700px;">
<email-builder id="builder" user-id="user_123"></email-builder>
</div>
</body>
</html>jsx
'use client';
import { useEffect, useState } from 'react';
import '@maillune/sdk';
export default function EmailEditor({ userId }) {
const [sessionToken, setSessionToken] = useState('');
useEffect(() => {
fetch('/api/editor-session')
.then(r => r.json())
.then(({ sessionToken }) => setSessionToken(sessionToken));
}, []);
if (!sessionToken) return <div>Loading…</div>;
return (
<div style={{ height: 700 }}>
<email-builder api-key={sessionToken} user-id={userId} />
</div>
);
}vue
<script setup>
import { ref, onMounted } from 'vue';
import '@maillune/sdk';
const props = defineProps({ userId: String });
const sessionToken = ref('');
onMounted(async () => {
const { sessionToken: token } = await fetch('/api/editor-session').then(r => r.json());
sessionToken.value = token;
});
</script>
<template>
<div style="height: 700px">
<email-builder
v-if="sessionToken"
:api-key="sessionToken"
:user-id="userId"
/>
</div>
</template>INFO
The component requires a fixed height. It will fill its container — use height: 100vh or a specific pixel value. Minimum recommended height is 640px.
5. Handle save
Listen for the eb:save event to receive the user's design as a BlockTree JSON object. Store it in your database and pass it back when the user re-opens the editor.
js
const builder = document.querySelector('email-builder');
// Called when the user clicks Save
builder.addEventListener('eb:save', async (e) => {
const { json } = e.detail;
await fetch('/api/save-template', {
method: 'POST',
body: JSON.stringify(json),
});
});
// Load a previously saved design
builder.load(savedBlockTree);6. Export HTML (Pro+)
js
builder.addEventListener('eb:export', (e) => {
const { html } = e.detail;
// Send to your email service provider (SendGrid, Postmark, etc.)
await sendEmail({ html, to: 'user@example.com' });
});