Maileditor Docs

Django

A login-protected view that signs the user id and a template that renders the editor iframe.

Django renders on the server, so one view can sign the user and pass the finished URL to a template. The secret is read from the environment in settings.py.

Before you start

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

Open the site as http://localhost:8000, not http://127.0.0.1:8000. The origin must match the allowed domain exactly.

Configuration

settings.py
import os

MAILEDITOR_PLUGIN_ID = os.environ["MAILEDITOR_PLUGIN_ID"]
MAILEDITOR_PLUGIN_SECRET = os.environ["MAILEDITOR_PLUGIN_SECRET"]
MAILEDITOR_EDITOR_BASE_URL = os.environ.get("MAILEDITOR_EDITOR_BASE_URL", "https://maileditor.net")
MAILEDITOR_PLUGIN_VERSION = os.environ.get("MAILEDITOR_PLUGIN_VERSION", "1.0.0")

Sign on the server

views.py
import hashlib
import hmac
import time
from urllib.parse import urlencode

from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.shortcuts import render


@login_required
def editor(request):
    user_id = f"user-{request.user.pk}"
    expires = int(time.time()) + 300
    payload = f"v1|{len(user_id.encode())}:{user_id}|{expires}"
    signature = hmac.new(
        settings.MAILEDITOR_PLUGIN_SECRET.encode(), payload.encode(), hashlib.sha256
    ).hexdigest()

    query = urlencode({
        "external_user_id": user_id,
        "identity_expires": expires,
        "identity_signature": signature,
        "plugin_version": settings.MAILEDITOR_PLUGIN_VERSION,
    })
    src = f"{settings.MAILEDITOR_EDITOR_BASE_URL}/plugin-editor/v1/{settings.MAILEDITOR_PLUGIN_ID}?{query}"

    return render(request, "editor.html", {"src": src})

len(user_id.encode()) counts bytes, which is what the payload requires.

urls.py
from django.urls import path

from . import views

urlpatterns = [
    path("editor/", views.editor, name="editor"),
]

Render the iframe

templates/editor.html
<iframe
  src="{{ src }}"
  title="Email editor"
  allow="clipboard-write; fullscreen"
  style="width: 100%; height: 100vh; border: 0"
></iframe>

Django's autoescaping turns & into &amp; inside the attribute, which the browser decodes back before loading the URL.

Next steps

  • Add template_id to the query 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