feat: Add rich text composing support using CKEditor 5

Add rich text composing support using CKEditor 5

Closes #540

What this MR does

Adds opt-in rich text (HTML) composing to HyperKitty's "Create New Thread" form using CKEditor 5, allowing users to send formatted HTML emails directly from the web interface.

Licensing

  • CKEditor 5 is licensed under GPL 2+, compatible with HyperKitty's GPL v3
  • Note: open-source usage displays a small "Powered by CKEditor" attribution badge in the editor

Changes

  • Integrates CKEditor 5 (CDN) into the compose form, gated behind three conditions: site allows AND Mailman Core allows HTML AND list has it enabled
  • Adds HyperKittySiteSettings model with a site-wide rich_text_enabled toggle, configurable by superusers in Django admin
  • Adds rich_text_enabled BooleanField to HyperKitty's MailingList model, configurable by staff/superusers in Django admin on a per-list basis
  • Adds core_allows_html() helper that reads Mailman Core's filter_content, collapse_alternatives, and convert_html_to_plaintext settings — shows a warning in Django admin if Core would strip HTML, directing the admin to fix it in Postorius first
  • Sanitizes HTML input using bleach to prevent XSS
  • Sends messages as multipart/alternative with html2text plain text fallback

Testing

  • Tested locally on M1 Mac, Python 3.14, Django 5.2
  • CKEditor renders correctly in the compose form when all conditions are met
  • HTML is sanitized before sending
  • Plain text fallback is auto-generated from HTML

Notes

  • Image attachments are explicitly out of scope for this MR
  • Archive rendering of HTML emails is out of scope for this MR — HTML parts currently show as downloadable attachments. The fix requires changes to the incoming MIME parsing pipeline and will be addressed in a follow-up MR soon

Images attached:

  1. Hyperkitty Site Settings show Rich text toggle (site wide)

image.png

  1. Mailing list shows rich text toggle along with mailman core check

image.png

  1. Sample preview of CKEditor in the compose form when rich text is enabled

image.png

Edited by Ayush Chauhan

Merge request reports

Loading