PluginPlatform guides
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
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
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.
from django.urls import path
from . import views
urlpatterns = [
path("editor/", views.editor, name="editor"),
]Render the iframe
<iframe
src="{{ src }}"
title="Email editor"
allow="clipboard-write; fullscreen"
style="width: 100%; height: 100vh; border: 0"
></iframe>Django's autoescaping turns & into & inside the attribute, which the browser decodes back before loading the URL.
Next steps
- Add
template_idto the query to open one of the user's saved templates. See Embedding the editor. - If the iframe shows "Plugin editor unavailable", read
result.errorin thesessionresponse. See Error codes.

.png)