You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2026/10/13 11:36:17 UTC

(james-project) 01/01: [ENHANCEMENT] AuditTrail should record which mapping were used upon rrt decision

This is an automated email from the ASF dual-hosted git repository.

chibenwa pushed a commit to branch rrt-log-mappings
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 255d03b735d13612d99f6995fb72d5b91d7fe26e
Author: Benoit TELLIER <bt...@linagora.com>
AuthorDate: Tue Oct 13 13:35:44 2026 +0200

    [ENHANCEMENT] AuditTrail should record which mapping were used upon rrt decision
---
 .../mailets/RecipientRewriteTableProcessor.java    | 45 ++++++++++++++++++----
 1 file changed, 37 insertions(+), 8 deletions(-)

diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessor.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessor.java
index 1d04029c5d..94a7e82c64 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessor.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessor.java
@@ -81,16 +81,26 @@ public class RecipientRewriteTableProcessor {
     private static class Decision {
         private final MailAddress originalAddress;
         private final RrtExecutionResult executionResult;
+        private final Optional<Mappings> appliedMappings;
 
-        private Decision(MailAddress originalAddress, RrtExecutionResult executionResult) {
+        private Decision(MailAddress originalAddress, RrtExecutionResult executionResult, Optional<Mappings> appliedMappings) {
             this.originalAddress = originalAddress;
             this.executionResult = executionResult;
+            this.appliedMappings = appliedMappings;
+        }
+
+        private Decision(MailAddress originalAddress, RrtExecutionResult executionResult) {
+            this(originalAddress, executionResult, Optional.empty());
         }
 
         MailAddress originalAddress() {
             return originalAddress;
         }
 
+        Optional<String> describeAppliedMappings() {
+            return appliedMappings.map(mappings -> originalAddress.asString() + "=" + asString(mappings));
+        }
+
         RrtExecutionResult executionResult() {
             return executionResult;
         }
@@ -220,7 +230,8 @@ public class RecipientRewriteTableProcessor {
                     .orElse(""),
                 "sender", mail.getMaybeSender().asString(),
                 "recipientsBeforeRewrite", StringUtils.join(recipientsBeforeRecipientsRewrite),
-                "recipientsAfterRewrite", StringUtils.join(recipientsAfterRecipientsRewrite))))
+                "recipientsAfterRewrite", StringUtils.join(recipientsAfterRecipientsRewrite),
+                "appliedMappings", describeAppliedMappings(decisions))))
             .log("Recipients rewritten.");
 
         processForwards(mail);
@@ -236,7 +247,8 @@ public class RecipientRewriteTableProcessor {
 
         static ForwardDecision sendACopy(MailetContext context,
                                          MailAddress originalRecipient,
-                                         Set<MailAddress> newRecipients) {
+                                         Set<MailAddress> newRecipients,
+                                         Set<Mapping> forwards) {
             return mail -> {
                 MailImpl copy = MailImpl.duplicate(mail);
                 LoopPrevention.RecordedRecipients recordedRecipients = LoopPrevention.RecordedRecipients.fromMail(mail);
@@ -248,7 +260,7 @@ public class RecipientRewriteTableProcessor {
 
                     context.sendMail(copy);
 
-                    recordInAuditTrail(mail, copy, originalRecipient);
+                    recordInAuditTrail(mail, copy, originalRecipient, forwards);
                 } finally {
                     LifecycleUtil.dispose(copy);
                 }
@@ -271,7 +283,7 @@ public class RecipientRewriteTableProcessor {
             };
         }
 
-        private static void recordInAuditTrail(Mail mail, MailImpl copy, MailAddress originalRecipient) {
+        private static void recordInAuditTrail(Mail mail, MailImpl copy, MailAddress originalRecipient, Set<Mapping> forwards) {
             AuditTrail.entry()
                 .protocol("mailetcontainer")
                 .action("RecipientRewrite")
@@ -282,7 +294,8 @@ public class RecipientRewriteTableProcessor {
                     "sender", mail.getMaybeSender().asString(),
                     "forwardedMailId", copy.getName(),
                     "forwardedMailSender", originalRecipient.asString(),
-                    "forwardedMailRecipient", StringUtils.join(copy.getRecipients()))))
+                    "forwardedMailRecipient", StringUtils.join(copy.getRecipients()),
+                    "forwardMappings", asString(forwards.stream()))))
                 .log("Mail forwarded.");
         }
 
@@ -334,7 +347,7 @@ public class RecipientRewriteTableProcessor {
         ImmutableList.Builder<ForwardDecision> result = ImmutableList.builder();
 
         if (!forwardRecipients.isEmpty()) {
-            result.add(ForwardDecision.sendACopy(mailetContext, originalRecipient, forwardRecipients));
+            result.add(ForwardDecision.sendACopy(mailetContext, originalRecipient, forwardRecipients, forwards));
         }
         boolean localCopy = newRecipients.contains(originalRecipient);
         if (!localCopy) {
@@ -366,6 +379,22 @@ public class RecipientRewriteTableProcessor {
         }
     }
 
+    private static String describeAppliedMappings(List<Decision> decisions) {
+        return decisions.stream()
+            .map(Decision::describeAppliedMappings)
+            .flatMap(Optional::stream)
+            .collect(Collectors.joining(", ", "[", "]"));
+    }
+
+    private static String asString(Mappings mappings) {
+        return asString(mappings.asStream());
+    }
+
+    private static String asString(Stream<Mapping> mappings) {
+        return mappings.map(Mapping::asString)
+            .collect(Collectors.joining(", ", "[", "]"));
+    }
+
     private void applyDecisionOnDSNParameters(Mail mail, List<Decision> decisions) {
         mail.dsnParameters()
             .map(dsnParameters -> decisions.stream()
@@ -418,7 +447,7 @@ public class RecipientRewriteTableProcessor {
 
             if (mappings != null && !mappings.isEmpty()) {
                 List<MailAddress> newMailAddresses = handleMappings(mappings, mail, recipient);
-                return new Decision(recipient, RrtExecutionResult.success(newMailAddresses));
+                return new Decision(recipient, RrtExecutionResult.success(newMailAddresses), Optional.of(mappings));
             }
             return new Decision(recipient, RrtExecutionResult.success(recipient));
         } catch (RecipientRewriteTable.ErrorMappingException e) {


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org