feat: add mail_sender_strategy policy to send notifications as the requester - #8106
Open
maia-andre wants to merge 5 commits into
Open
feat: add mail_sender_strategy policy to send notifications as the requester#8106maia-andre wants to merge 5 commits into
maia-andre wants to merge 5 commits into
Conversation
…quester Add the mail_sender_strategy policy (system scope only) with two values: system, the current behavior through OCP\Mail\IMailer, and requester, which tries to send the signature request notification through the mail account of the person who requested the signature using OCP\Mail\Provider\IManager. MailService::notifyUnsignedUser() and notifySignDataUpdated() resolve the policy for the requester (the file owner) so reminders sent from cron use the same strategy. Under requester, the service is looked up by the requester email address, falling back to the first account service that implements IMessageSend, and the existing IEMailTemplate is reused for the subject and bodies. When there is no provider, no account, no sendable service, or provider sending fails, the notification falls back to the system mailer (logged at info/warning level), keeping the current error handling for that path. Expose the policy in the Policy Workbench under "System behavior" with a radio editor for the two strategies. Fixes LibreSign#7954 Assisted-by: Claude Code:claude-fable-5 Signed-off-by: André Maia <andrefnkmm@gmail.com>
|
Codecov Report✅ All modified and coverable lines are covered by tests.
... and 208 files with indirect coverage changes 🚀 New features to boost your workflow:
|
…editor Codecov reported 14 uncovered lines in the new frontend files. Add specs mirroring the existing tsa/signing-mode ones: model normalization, every callback of the real definition (draft value, fallback default, summary, override message) and the rule editor (rendering, selection state, emitted strategy and ignored deselection). Ref LibreSign#7954 Assisted-by: Claude Code:claude-fable-5 Signed-off-by: André Maia <andrefnkmm@gmail.com>
maia-andre
force-pushed
the
feat/7954-mail-sender-strategy
branch
from
August 28, 2026 21:02
238d872 to
3b00b4e
Compare
…tions Some constraints only make sense when an administrator saves a value, for example requiring an external capability to be available. Running them during runtime resolution would make DefaultPolicyResolver discard an already stored value as soon as the environment changes, instead of letting the consumer fall back gracefully. Add IPolicyDefinition::validateValueForPersistence(), implemented by PolicySpec as validateValue() plus an optional persistenceValidator closure, and call it from the PolicyService save paths (system, group, user preference and user policy). Runtime resolution keeps using validateValue(). Ref LibreSign#7954 Assisted-by: Claude Code:claude-fable-5 Signed-off-by: André Maia <andrefnkmm@gmail.com>
…trategy Configuration and runtime behavior are now separated, as requested in the issue: the requester strategy can only be saved while a mail provider is registered (OCP\Mail\Provider\IManager::has()), because we already know it cannot work otherwise. The check uses the persistence hook, so an already stored value keeps resolving at runtime and MailService falls back to the system mailer when the environment changes later. The check looks for any mail provider instead of a specific app. Expose the availability as mailProviderAvailable in the resolved policy meta and use it in the Policy Workbench editor to disable the requester option with a hint. The OpenAPI spec and generated types are updated for the new meta field. Ref LibreSign#7954 Assisted-by: Claude Code:claude-fable-5 Signed-off-by: André Maia <andrefnkmm@gmail.com>
…ailer When the requester strategy is configured but the notification cannot leave the requester mail account (no provider anymore, account removed, no sendable service or a sending failure), the system mailer now sets Reply-To to the requester address, so replies still reach the person who requested the signature. The system strategy is unchanged. Ref LibreSign#7954 Assisted-by: Claude Code:claude-fable-5 Signed-off-by: André Maia <andrefnkmm@gmail.com>
maia-andre
force-pushed
the
feat/7954-mail-sender-strategy
branch
from
August 29, 2026 02:33
8cd01e5 to
1ed51a0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request Description
Implements the
mail_sender_strategypolicy described in #7954 so LibreSign can send signature request notification emails either through the system mailer (current behavior) or through the mail account of the person who requested the signature.Backend
MailSenderStrategyPolicy(lib/Service/Policy/Provider/MailSenderStrategy/), registered inPolicyProviders. Values:system(default) andrequester. System scope only in this first step (supportedScopes: ['system'], no user preference, no group delegation), since per-user choice is out of scope.MailService::notifyUnsignedUser()andnotifySignDataUpdated()now resolve the policy for the requester (resolveForUserId()on the file owner, so the same strategy applies to reminders sent from cron, where there is no session user).requester, the notification is sent throughOCP\Mail\Provider\IManager: the service is looked up by the requester's email address (findServiceByAddress()), falling back to the first service of the account that implementsIMessageSend. The message reuses the existingIEMailTemplate(renderSubject(),renderHtml(),renderText()), so content and templating are unchanged.IMailer(identical to the current code path) when there is no mail provider, the requester account is missing, no service can send messages, or provider sending throws. Logging:infofor the "not available" cases,warning(with the exception) when provider sending fails. Errors from the finalIMailerpath keep raisingLibresignExceptionas before.Configuration vs. runtime (follow-up of the review in #7954)
requesterstrategy can only be saved while a mail provider is registered (OCP\Mail\Provider\IManager::has(), independent of any specific app). This uses a new persistence-only hook in the policy framework,IPolicyDefinition::validateValueForPersistence(), called from thePolicyServicesave paths. Runtime resolution keeps usingvalidateValue(), so an already storedrequestervalue is not silently discarded byDefaultPolicyResolverwhen the environment changes later; insteadMailServicefalls back at sending time.meta.mailProviderAvailable(OpenAPI spec and generated types updated) and the Policy Workbench editor disables therequesteroption with a hint when no provider is available.requesterand the notification falls back to the system mailer,Reply-Tois set to the requester's address, so replies still reach the person who requested the signature. Thesystemstrategy is unchanged.Frontend
src/views/Settings/PolicyWorkbench/settings/mail-sender-strategy/(radio editor with the two strategies), added to thesystem-behaviorcategory inrealDefinitions.ts.Tests
MailSenderStrategyPolicyTest: definition, scope restriction, normalization and validation, provider required on save (and stored value still valid at runtime), resolved meta.PolicySpecTest: the persistence-only validation hook.MailServiceTest:systemstrategy, successfulrequestersending (from/to/subject/html/plain), recipient label handling, every fallback path (no provider, unknown requester, missing account, no sendable service, provider failure, fallback failure) and theReply-Tobehavior on fallback.realDefinitions.spec.ts,mail-sender-strategy/*.spec.ts: workbench card, definition callbacks, model and editor (including the disabled state).Checks run locally: PHPUnit unit suite, psalm and php-cs-fixer on the changed files,
npm run lint,vue-tsc --noEmit, vitest for the Policy Workbench suites.Manual verification
Devcontainer with Mailpit as the system mailer and no mail provider app installed, so the
requesterstrategy exercises the fallback path end to end.New card in the Policy Workbench (System behavior), default
System mailer:Rule editor with the two strategies:
Selecting
Requester mail accountand saving the system rule:Card after saving (
occ config:app:get libresign mail_sender_strategy→requester):Signature request sent through the API with the policy set to
requester: the notification is still delivered, through the system mailer, and the fallback is logged atinfolevel:{"level": 1, "app": "libresign", "message": "No mail provider is available to send the notification as the requester, falling back to the system mailer.", "requester": "admin"}Follow-up of the review: on the same instance (no mail provider), the
requesteroption can no longer be configured. The editor disables it with a hint, and the API rejects it with400:The screenshots in steps 3–5 were taken before this change; they show the rule saved while the check did not exist yet, which is exactly the "environment changed later" case that the runtime fallback (and now
Reply-To) covers.Related Issue
Fixes #7954
Pull Request Type
Pull request checklist
systemandrequestersystempreserves the current behaviorrequesterattempts provider-based sendingIMailerwhen no provider, account or sending service is available, or when sending failsrequestercannot be configured while no mail provider is available (persistence-time check)Reply-Toset to the requester when falling back to the system mailernotifyUnsignedUserandnotifySignDataUpdatedsystem, successfulrequesterand fallback