plain.support
Provides support forms for your application.
Overview
You can add support forms to your application to collect user feedback, bug reports, and other messages. When a form is submitted, an email is sent to your support team.
# app/urls.py
from plain.urls import include, path, Router
from plain.support.urls import SupportRouter
class AppRouter(Router):
namespace = "app"
urls = [
path("support/", include(SupportRouter)),
# ...
]
# app/settings.py
SUPPORT_EMAIL = "[email protected]"
This creates a support form at /support/form/default/ that users can fill out. When submitted, an email is sent to your SUPPORT_EMAIL address with the user's name, email, and message.
Configuration
Settings
SUPPORT_EMAIL(required): The email address where support requests are sentSUPPORT_FORMS: A dictionary mapping form slugs to form classes (defaults to{"default": "plain.support.forms.SupportForm"})
Custom forms
You can create custom support forms by extending SupportForm. The form uses ModelForm from plain.models.forms.
# app/forms.py
from plain.support.forms import SupportForm
from plain.support.models import SupportFormEntry
from plain import forms
class BugReportForm(SupportForm):
browser = forms.CharField(max_length=100, required=False)
class Meta:
model = SupportFormEntry
fields = ["name", "email", "message", "browser"]
Then register it in your settings:
# app/settings.py
SUPPORT_FORMS = {
"default": "plain.support.forms.SupportForm",
"bug-report": "app.forms.BugReportForm",
}
The form will be available at /support/form/bug-report/.
You can also customize the email notification by overriding the notify method:
class BugReportForm(SupportForm):
# ...
def notify(self, instance):
# Send to a different channel, create a ticket, etc.
pass
Views
You can use the following views for different scenarios:
SupportFormView: Renders the support form on a full pageSupportIFrameView: Renders the form in an iframe-friendly formatSupportFormJSView: Serves JavaScript for embedded forms
Embedded forms
Support forms can be embedded in other sites using an iframe:
<iframe src="https://example.com/support/form/default/iframe/" width="100%" height="600"></iframe>
Or using the provided JavaScript embed:
<div id="support-form"></div>
<script src="https://example.com/support/form/default.js"></script>
Security considerations
Most support forms allow users to type in any email address. Be careful, because anybody can pretend to be anybody else. Conversations either need to continue over email (which confirms they have access to the email account), or include a verification step (emailing a code to the email address, for example).
The SupportForm.find_user() method attempts to associate entries with existing users by email, but this does not confirm the submitter's identity.
FAQs
How do I customize the form templates?
You can override the default templates by creating your own templates at:
support/page.html: The full page templatesupport/iframe.html: The iframe-friendly templatesupport/forms/<form_slug>.html: The form rendering templatesupport/success/<form_slug>.html: The success message template
How do I view support form entries?
Support form entries are stored in the SupportFormEntry model. You can query them directly or use the admin interface if you have plain.admin installed with the SupportFormEntryAdmin registered.
Can I associate support entries with logged-in users?
Yes. When a user is logged in, the form automatically associates the entry with their account. If the user is not logged in (common with iframe embeds), the form will try to find an existing user by email address using find_user().
Installation
Install the plain.support package from PyPI:
uv add plain.support
Add plain.support to your INSTALLED_PACKAGES in app/settings.py:
# app/settings.py
INSTALLED_PACKAGES = [
# ...
"plain.support",
]
Set the required SUPPORT_EMAIL setting:
# app/settings.py
SUPPORT_EMAIL = "[email protected]"
Include the support URLs in your app's URL configuration:
# app/urls.py
from plain.urls import include, path, Router
from plain.support.urls import SupportRouter
class AppRouter(Router):
namespace = "app"
urls = [
path("support/", include(SupportRouter)),
# ...
]
Run migrations to create the SupportFormEntry table:
uv run plain migrate
Create the required templates. At minimum, you need a form template:
<!-- app/templates/support/forms/default.html -->
{{ form.as_fields }}
<button type="submit">Send message</button>
And a success template:
<!-- app/templates/support/success/default.html -->
<p>Thank you for your message! We'll get back to you soon.</p>
You also need to create an email template for notifications. See the plain.email package for template setup instructions:
<!-- app/emails/support_form_entry.html -->
<p>New support request from {{ support_form_entry.name }} ({{ support_form_entry.email }})</p>
<p>{{ support_form_entry.message }}</p>
Visit /support/form/default/ to see your support form.