Maileditor Docs

Next.js

Sign the user id in a server component and render the editor iframe on the same request.

In the App Router a server component can sign and render in one pass. The Plugin Secret is read from process.env on the server and never reaches the browser.

Before you start

Follow the first three steps of the quickstart: create a plugin, add localhost:3000 to its allowed domains, and copy the Plugin ID and Secret.

Configuration

.env.local
MAILEDITOR_PLUGIN_ID=9f3c1e7a-4b21-4c8e-9a77-1d2f5b6c8e10
MAILEDITOR_PLUGIN_SECRET=your_plugin_secret
MAILEDITOR_EDITOR_BASE_URL=https://maileditor.net
MAILEDITOR_PLUGIN_VERSION=1.0.0

Do not prefix these with NEXT_PUBLIC_. That would ship the secret to the browser.

Sign and render

app/editor/page.tsx
import { createHmac } from 'node:crypto'

export const dynamic = 'force-dynamic'

export default function EditorPage() {
  const userId = 'customer-user-4471'
  const expires = Math.floor(Date.now() / 1000) + 300
  const payload = `v1|${Buffer.byteLength(userId)}:${userId}|${expires}`
  const signature = createHmac('sha256', process.env.MAILEDITOR_PLUGIN_SECRET!)
    .update(payload)
    .digest('hex')

  const params = new URLSearchParams({
    external_user_id: userId,
    identity_expires: String(expires),
    identity_signature: signature,
    plugin_version: process.env.MAILEDITOR_PLUGIN_VERSION!,
  })
  const src = `${process.env.MAILEDITOR_EDITOR_BASE_URL}/plugin-editor/v1/${process.env.MAILEDITOR_PLUGIN_ID}?${params}`

  return (
    <iframe
      src={src}
      title="Email editor"
      allow="clipboard-write; fullscreen"
      style={{ width: '100%', height: '100vh', border: 0 }}
    />
  )
}

Replace userId with the id of the signed-in user from your own session. force-dynamic makes Next.js render the page on every request, so the signature is always fresh and is never baked in at build time.

If you would rather sign in a route handler and build the URL in a client component, that variant is in the quickstart.

Next steps

  • Add template_id to the query string to open one of the user's saved templates. See Embedding the editor.
  • If the iframe shows "Plugin editor unavailable", read result.error in the session response. See Error codes.

On this page