Skip to content

Install

bash
npm install @maillune/sdk

How authentication works

The api-key attribute must be a session token — not your secret API key. Your backend calls POST /v1/sessions server-side and returns a 2-hour JWT that's safe to pass to the browser. See Authentication for details.

Server-side endpoint (Nitro / Express)

ts
// server/api/editor-session.get.ts  (Nuxt 3 server route)
export default defineEventHandler(async (event) => {
  const user = await requireUserSession(event); // your auth

  const { sessionToken } = await $fetch('https://api.maillune.com/v1/sessions', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.MAILLUNE_SECRET_KEY}`, // server-only
    },
    body: { userId: user.id },
  });

  return { sessionToken };
});

EmailEditor component

vue
<!-- components/EmailEditor.vue -->
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import '@maillune/sdk';
import type { EmailBuilderElement, BlockTree } from '@maillune/sdk';

const props = defineProps<{
  userId: string;
  initialTemplate?: BlockTree;
}>();

const emit = defineEmits<{
  save: [json: BlockTree];
}>();

const builderRef = ref<EmailBuilderElement | null>(null);
const sessionToken = ref('');

onMounted(async () => {
  // 1. Fetch the session token from your backend
  const data = await fetch('/api/editor-session').then(r => r.json());
  sessionToken.value = data.sessionToken;

  // 2. Wire up the save event once the token is ready
  await nextTick();
  const el = builderRef.value;
  if (!el) return;

  el.addEventListener('eb:save', (e) => {
    emit('save', (e as CustomEvent).detail.json);
  });

  if (props.initialTemplate) {
    el.load(props.initialTemplate);
  }
});

watch(() => props.initialTemplate, (template) => {
  if (template) builderRef.value?.load(template);
});
</script>

<template>
  <div style="height: 100vh">
    <email-builder
      v-if="sessionToken"
      ref="builderRef"
      :api-key="sessionToken"
      :user-id="userId"
      theme="auto"
    />
    <div v-else>Loading editor…</div>
  </div>
</template>

Nuxt 3

The SDK uses browser APIs — wrap it in a <ClientOnly> component or register it as a client plugin:

ts
// plugins/email-builder.client.ts
import '@maillune/sdk';
vue
<!-- pages/editor.vue -->
<template>
  <ClientOnly>
    <EmailEditor :user-id="userId" @save="handleSave" />
  </ClientOnly>
</template>

Vue global component types

Add to env.d.ts:

ts
declare module 'vue' {
  interface GlobalComponents {
    EmailBuilder: {
      new(): {
        $props: {
          'api-key': string;
          'user-id': string;
          'template-id'?: string;
          theme?: 'light' | 'dark' | 'auto';
        };
      };
    };
  }
}