Commit Graph
88 Commits
Author SHA1 Message Date
jbpenrath 54fd3deb04 ✨(frontend) add starred/important thread feature
The backend already scopes the starred flag per mailbox via
ThreadAccess.starred_at. This commit exposes the feature in the
frontend: a useStarred hook, a toggle button in the thread action
bar, a starred badge in thread items, an important icon in the
thread view subject, and a search filter checkbox for starred
threads (is:starred / est:important).

Also fixes the undo toast in use-flag to propagate mailboxId so
that mailbox-scoped flags (unread, starred) can be properly undone.
2026-03-11 11:55:19 +01:00
jbpenrath 4f5591b722 ✨(global) store thread read state by thread access
Currently thread sharing is confusing as the read state is shared from
all thread accesses so we deprecate the `read_at` of the Message model
in favor of a `last_read_at` timestamp pointer on the thread access.

Furthermore, on the thread model, we add several date fields to store relevant
dates in which thread should be sorted according to the current view.
2026-03-05 12:10:29 +01:00
jbpenrath c050aee70b ✨(message) store and display the user who sent a message
For shared mailboxes, knowing which user actually sent a message is
important UX information. This adds a `sender_user` field on Message,
set at send time (not draft creation), and displays "Sent by <name>"
in the sender's contact popover when viewing from a shared mailbox.
2026-03-05 09:54:20 +01:00
Sylvain ZimmerandGitHub d153f5ad69 ✨(entitlements) add DeployCenter backend for syncing maildomain admins (#572)
Entitlements system with pluggable backends and automatic mail-domain admin sync on login.
Provisioning API to create/update mail domains (bulk input, custom attributes)
Feature flags to enable/disable mail-domain creation and access management; UI and public config expose these flags
2026-03-03 15:06:55 +01:00
Sylvain ZimmerandGitHub 9b5375cba3 ✨(import) add support for PST imports & stream data for mbox (#544)
Fixes #183. Replaces #517.
2026-02-19 14:03:43 +01:00
Sylvain ZimmerandGitHub d8afd35847 ✨(mailboxes) add a denylist for personal mailbox prefixes (#540)
Personal mailboxes now enforce configurable prefix restrictions; blocked prefixes return a clear error. Domains can indicate identity synchronization status; when disabled, creating personal mailboxes is prevented and returns a specific error.
2026-02-19 12:52:44 +01:00
Jean-Baptiste PENRATHandGitHub 82bb4e1204 ⚡️(global) optimize MessageTemplate serialization and body handling (#545)
Avoid transferring heavy body content (especially base64 images) when
only metadata is needed. The frontend now explicitly requests the body
fields it needs via ?bodies=raw,html,text, and modals lazily fetch
body content only when editing a template.

Key changes:
- Replace 3 read serializers with a single ReadMessageTemplateSerializer
  that dynamically includes body fields based on ?bodies= query param
- Cache parsed blob content on the model to avoid redundant JSON parsing
- Skip expensive base64 image validation on update when body is unchanged
- Refactor frontend modals to lazy-load body via retrieve on edit
2026-02-18 12:02:21 +01:00
jbpenrath c53e8bfcd4 ✨(global) allow to add image block into template and signature composers
Images are embedded as base64 data URLs directly in the BlockNote content,
unlike the message composer which uses blob uploads + CID references.
This approach keeps templates and signatures self-contained without
requiring an attachment system.

Furthermore, a email-safe safe html exporter has been created to
serialize blocknote content into html.

A new backend setting MAX_TEMPLATE_IMAGE_SIZE (default 2 MiB) controls
the maximum allowed image size for these composers.
2026-02-17 19:02:28 +01:00
jbpenrath ffca2231e6 ✨(global) add outbox conditional folder
Add outbox conditional folder to display messages having message recipients with None, retry or failed state.
Inform visually the user is something is wrong with a message.
Allow user to update MessageRecipient from failed to cancelled to hide ui warning.
2026-02-05 19:04:02 +01:00
Sylvain ZimmerandGitHub e6296f9b3a ✨(integrations) add integrations view in mailbox (#488)
For now this allows users to create feedback widgets linked to their
mailbox. We will also have API keys and recurring imports there.
2026-01-25 17:29:19 +01:00
Sylvain ZimmerandGitHub 9a48eda9c6 ♻️(permissions) refactor some permissions code for viewsets (#503)
We want to avoid relying on role__gte, so we add role list aliases.
2026-01-24 13:48:43 +01:00
Sabrina Demagny 1899fd80d7 ✨(signature) allow to create mailbox signature 2026-01-16 10:06:32 +01:00
jbpenrath 9614e9107b ✨(global) mark thread as spam
Allow users to report a thread as a spam.
Also allow the user to mark the thread has not spam. Then in case of spam,
disable the attachment download for security purpose.
2026-01-14 13:50:20 +01:00
888ff9e42d 🐛(rfc5322) improve email parsing & display multiparts in frontend (#463)
* 🩹(mime) fix inline HTML being treated as attachment

Previously, any MIME part with a Content-Disposition header (including
'inline') was treated as an attachment. This caused HTML email bodies
with 'Content-Disposition: inline' to appear as downloadable attachments
instead of being rendered as the message body.

The fix clarifies the classification logic:
- Parts with 'Content-Disposition: attachment' are always attachments
- Parts with 'Content-Disposition: inline' and text/plain or text/html
  are treated as message body
- Parts with filenames but no disposition follow existing rules

* ♻️(mime) refactor parser to use Flanker's built-in methods

Replace manual disposition parsing with Flanker's is_attachment(),
is_body(), and is_inline() methods which properly implement RFC standards.

This fixes issues where:
- text/calendar parts were incorrectly treated as attachments
- inline HTML was misclassified
- Parts without disposition were not properly categorized

The new logic uses Flanker's built-in classification:
- is_attachment(): Content-Disposition is 'attachment'
- is_body(): No filename AND (text/* or message/*)
- is_inline(): Content-Disposition is 'inline'

* fix: Add missing disposition_header variable definition

* 🛡️(mime) add defensive exception handling for MIME classification

Add try/except blocks around Flanker's is_attachment(), is_body(), and
is_inline() methods to prevent malformed MIME from crashing the parser.
When classification fails, log the error and safely fall back to treating
all checks as False, allowing parsing to continue.

Also preserve actual Content-Type for attachments instead of forcing
text/plain to application/octet-stream, and infer appropriate file
extensions from MIME types when no filename is provided.

* ♻️(mime) refactor attachment handling with helper functions

Extract duplicate attachment construction logic into reusable helper
functions and add consistent filename extension inference across all
attachment types (attachment, inline, and fallback paths).

Changes:
- Add _infer_filename_from_content_type() to map MIME types to file
  extensions for better unnamed attachment handling
- Add _build_attachment_dict() helper to eliminate ~45 lines of
  duplicated attachment dict construction code
- Apply extension inference consistently to is_attachment, is_inline,
  and fallback branches
- Update tests to expect new filename format (e.g., "unnamed.pdf")
- Clarify exception handler comment for better code documentation

* ✅(rfc5322) fix tests & lint

* 🐛(rfc5322) sanitize attachment filenames and add many more tests

* 🐛(rfc5322) improve RFC5322 parsing logic with nested parts, per JMAP spec

* ✨(rendering) render multipart messages in frontend

* fixup! ✨(rendering) render multipart messages in frontend

* 🐛(review) address PR review comments

- Fix _sanitize_filename to preserve file extension when truncating
- Fix MessageBodyItemSerializer: use required fields, remove Meta class
- Fix misleading comment about text body drive attachments
- Regenerate OpenAPI schema and frontend API client

* 🐛(types) fix null fallback

* fix lint and tests

---------

Co-authored-by: Riël Notermans <riel@zzapps.nl>
Co-authored-by: Riël Notermans <riel@mosa.cloud>
Co-authored-by: jbpenrath <jb.penrath@gmail.com>
2026-01-14 01:18:32 +01:00
812cf51915 ✨(all) allow to display external images through proxy (#469)
Allow to users to display external images from their email
through a secure proxy endpoint to ensure security and privacy
and respect iframe csp policy.

Co-authored-by: =?UTF-8?q?Ri=C3=ABl=20Notermans?= <riel@mosa.cloud>
2026-01-12 17:09:32 +01:00
Sylvain ZimmerandGitHub b6394a2f56 ✨(limits) implement MAX_RECIPIENTS_PER_MESSAGE (#474)
This is mostly cherrypicked from the larger PR #459, to reduce
complexity. We might still implement the rest in the future.
2026-01-12 12:09:52 +01:00
Jean-Baptiste PENRATHandGitHub 0e94d33736 👔(backend) add flag is_trashed to thread resource (#454)
Add a flag `is_trashed` to Thread model in order to monitor when a thread is
fully trashed. It helps to exclude those kind of threads in some views with
inactive message like archive or spam for example.

By default we exclude those kind of threads from results until user is looking
for trashed messages.
2025-12-17 10:06:13 +01:00
Niels Kersicandjbpenrath 1ac92fe44b 🔧(backend) add configurable Drive app name
Add DRIVE_APP_NAME variable that gets exposed via the config endpoint then
update frontend translation to use this variable into it.

Co-Authored-By: jbpenrath <jb.penrath@gmail.com>
2025-12-09 14:19:53 +01:00
295ffbb3cf 🐛(backend) disable pagination for thread messages
Long threads (more than 20 messages) only displayed the first 20 messages
because the MessageViewSet used the default PAGE_SIZE of 20. The frontend
doesn't handle pagination for messages, so additional messages were silently
hidden from users.

This fix disables pagination for the messages endpoint since threads typically
don't have enough messages to require pagination.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 10:59:51 +01:00
jbpenrath 24f2644f0d ✨(interop) allow to save an attachment into Drive workspace
Setup Drive resource server query to retrieve and save files from a configured
Drive instance through OIDC resource server.

https://github.com/suitenumerique/drive/pull/379
2025-12-01 19:32:07 +01:00
670ba5699a ✨(attachments) configurable size limits (#430)
Adds new config vars for incoming & outgoing attachment sizes, validated at draft stage
and when receiving emails.

---------

Co-authored-by: Riël Notermans <riel@mosa.cloud>
2025-11-21 13:55:26 +01:00
Sabrina Demagny 4d68cb4833 ✨(contacts) add contacts from the same domain as selected mailbox to contacts endpoint 2025-10-31 14:06:28 +01:00
Sabrina Demagny f7ee9dcc47 ✨(template) allow to insert recipient name in reply 2025-10-29 15:54:07 +01:00
Sylvain ZimmerandGitHub 54b14f9304 ✨(features) add new feature flag env vars (#387)
Rename old AI_FEATURE env vars and add 2 new ones
2025-10-17 23:27:37 +02:00
Sabrina Demagny 03a52f0056 ✨(template) add view and modal to manage message template for a mailbox 2025-10-16 20:46:08 +02:00
jbpenrath d997d119ee 🚸(front) add more context if available about message delivery status
We recently display recipient delivery status tooltip when the message is not
yet delivered or in failure. To help user to understand why the message is not
delivered, we now display the delivery message if there is one.
2025-10-16 17:02:35 +02:00
Sabrina Demagny 08635bee52 ✨(template) simplify message template type 2025-10-15 23:58:59 +02:00
Sylvain ZimmerandGitHub d9d3853252 ✨(images) implement cid: image support (#378)
Parses the email and replaces cid: images with blob urls
2025-10-15 21:15:48 +02:00
Jean-Baptiste PENRATHandGitHub 66b6561ecb ✨(message) Display message delivery status (#379)
- Updated Message API to return MessageRecipient instead of Contact
- In ThreadMessage component displays icon next to a recipient to display
delivered status (only if the message is not delivered yet)
2025-10-15 15:20:00 +02:00
Jean-Baptiste PENRATHandGitHub 10be269761 ✨(import) Enhance message import through multipart upload (#372)
- Added multipart upload capabilities for EML and MBOX files to the
  message imports bucket.
- Introduced new API endpoints for initiating uploads, completing
  uploads, and aborting uploads.
- Updated serializers and viewsets to handle file uploads efficiently.
- Improved frontend components to display upload progress and handle
  file uploads seamlessly.
- Adjusted backend services to process uploaded files asynchronously,
  ensuring better performance and user experience.
- Updated documentation and tests to reflect the new functionality.
2025-10-14 17:31:17 +02:00
Sabrina Demagny 6e1dc402ae ✨(import) add new mailbox ability to import messages 2025-10-14 00:03:55 +02:00
Sabrina Demagny ae1d9db95a ✨(template) add new mailbox ability to manage message templates 2025-10-13 23:16:54 +02:00
Sabrina Demagny 895efcfb5d ✨(template) CRUD for mailbox message templates 2025-10-08 18:08:25 +02:00
Jean-Baptiste PENRATHandGitHub 8ee4b37a17 ✨(send) Add send and archive action (#370)
Allow a user to ask to send a message then immediately archive
the related thread. For new message, it is not allowed to archive the thread.
Furthermore, the user can choose to use by default the send and archive action.
2025-10-08 15:58:55 +02:00
Jean-Baptiste PENRATHandGitHub bf38eaa60b ✨(archive) implement archiving functionality for messages and threads (#363)
We want to be able to archive threads. So we update Thread model to know
if the thread is archived according to its messages state. Then update the
flag endpoint api to archive messages or threads. Also update the search indexer
to be able to search within archived threads. And finally update the frontend to
allow the user to archive a thread, get and search in archived threads.
2025-10-06 18:27:30 +02:00
4db9b261b3 ✨(inbound) store message metadata as custom headers (#354)
Co-authored-by: Jean-Baptiste PENRATH <jb.penrath@gmail.com>
2025-10-02 22:15:55 +02:00
Sabrina Demagny 9bacfd24b6 ✨(template) allow to create and use signature
- Allow to create and manage signature in admin interface
- Allow to insert signature in message editor
- Blob model must have at least a mailbox or maildomain

This commit introduces a complete email template system with support
for both HTML and text content, flexible relationships with mailboxes
and mail domains, and a RESTful API for template management.
2025-10-01 00:31:14 +02:00
Sabrina Demagny 29415e21a0 ✅(tests) fix test retrieve eml and update open api schema 2025-09-29 19:41:06 +02:00
Sylvain ZimmerandGitHub f4eac6dd8f ✨(channels) add feedback widget and multiple inbound channels support (#301)
This PR adds a new build system for embeddable widgets and a first implementation of a "Feedback" popup widget.

It also refactors inbound message routes into channels, of which there are 2 for now: MTA (by default) and Widget. More to come!
2025-09-24 14:30:40 +02:00
jbpenrath 28137bfdc4 ♻️(backend) make generic user list endpoint
Currently the endpoint to search users is nested under maildomain. So since we
add the new endpoint to manage maildomain accesses, we need more granularity
on this endpoint and its current implementation does not allow that. So we move
it into the UserViewset. This endpoint is accessible to superuser and maildomain
admins only. Superusers are allowed to search into the whole user database to
assign any user as maildomain admin while maildomain admin are only allowed to
search users with maildomain or mailbox access in their scope.
2025-09-23 18:32:44 +02:00
jbpenrath 9e3dcecf2a ✨(global) add maildomain access management features
Introduce new API endpoints for managing maildomain accesses,
including read, write, and delete operations. Update translations
and UI components to support these features, enhancing the admin
interface for managing user access to maildomains.

Related issue : #327
2025-09-22 19:25:07 +02:00
jbpenrath 3eee6862ed ✨(global) allow edit mailbox from admin
Only allow patch request to update mailbox then customize serializer to only
update allowed fields and related resources (Contact, User accordingly)

Also update admin frontend to add action to edit a mailbox in the maildomain admin.

Related issue : #328, #327
2025-09-18 19:38:34 +02:00
jbpenrath c7dbb73ccc ✨(backend) add new endpoint to reset password
Add a new admin endpoint to reset user password if
domain oidc sync is enabled.
2025-09-16 17:02:44 +02:00
Stanislas Bruhiere 647abfb2eb 🚨(backend) run make api-update 2025-09-04 17:16:29 +02:00
Stanislas BruhièreandGitHub 02bce211ea ✨(frontend) add a button and modal to create maildomains (#313)
* ✨(feat) create modal, serializer and add button

* ✨(frontend) refetch on domain creation

* 🚨(frontend) fix linter

* ✅(backend) add domain creation test

* ✨(frontend) add toaster for domain creation

* 💬(frontend) add translation and fix small typo

* ✨(front+back) add custom_attributes on domain creation

* 💄(frontend) add style for create domain modal

* 💬(frontend) add missing translations + add end of file line breaks

* 🎨(frontend) move toaster to admin layout

* 🦺(frontend) validate domain name in frontend

* 💄(frontend) remove unused css

* ✅(backend) add more tests

* 🎨(backend) improve maildomain structure

* 🎨(frontend) follow nitpicks
2025-09-02 20:13:11 +02:00
Sabrina Demagny 67a7c4e9c0 ✨(api) add placeholders endpoint
This endpoint will be used for Signature and other message templates.
Update Dockerfile to include gettext for i18n compilation
2025-08-20 12:10:16 +02:00
Fabian ArfireandJean-Baptiste PENRATH cdb4e207e5 ✨(backend) add auto labelling ai feature
When a message is received, if the auto labelling feature is enabled,
we try to add all relevant labels that are flagged for auto labelling to this
message.

Co-authored-by: jbpenrath <jb.penrath@gmail.com>
2025-08-19 23:48:03 +02:00
jbpenrath 53110862d6 ✨(front) manage abilities
Improve openapi schema to pass abilities to frontend properly.
Then through the useAbility hook, hide/disable actions.
It concerns actions to send messages, write messages, share
thread access, crud labels, crud maildomain mailboxes.
2025-08-07 10:39:23 +02:00
jbpenrath d0b2a66f08 🐛(frontend) draftBody can be null
There was an error in the openapi schema and we are not aware that
message.draftBody could be null so when it was the case, the frontend
throws an error when rendering the `MessageForm` component.
2025-08-06 10:12:36 +02:00
jbpenrath 4a311e5b3c ✨(backend) define custom_attributes through env vars json schema string
User and MailDomain have both `custom_attributes` json field. Those fields
aims to store extra data about those models specific to an instance. In order
to fulfill those fields with consistency and without requiring to fork the
project, we add two new settings `SCHEMA_CUSTOM_ATTRIBUTES_*`.
Those 2 settings expects a JSON Schema string defined through env vars.
Then on model save, those schema are used to validate data saved into
custom attributes.
2025-08-06 10:12:36 +02:00