This is an automated email from the ASF dual-hosted git repository.
chibenwa pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push:
new 861aab6332 [ENHANCEMENT] Attribute for forwarded mail (#3036)
861aab6332 is described below
commit 861aab6332a60c3e7934a39ba8a1ea85600d8133
Author: Benoit TELLIER <[email protected]>
AuthorDate: Mon May 11 08:58:18 2026 +0200
[ENHANCEMENT] Attribute for forwarded mail (#3036)
Co-authored-by: Rene Cordier <[email protected]>
---
.../servers/partials/RecipientRewriteTable.adoc | 6 ++++-
.../transport/mailets/RecipientRewriteTable.java | 3 +++
.../mailets/RecipientRewriteTableProcessor.java | 7 ++++++
.../RecipientRewriteTableProcessorTest.java | 27 ++++++++++++++++++++++
4 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/docs/modules/servers/partials/RecipientRewriteTable.adoc
b/docs/modules/servers/partials/RecipientRewriteTable.adoc
index ec94fac455..429882f827 100644
--- a/docs/modules/servers/partials/RecipientRewriteTable.adoc
+++ b/docs/modules/servers/partials/RecipientRewriteTable.adoc
@@ -19,4 +19,8 @@ from external senders to external addresses as the DKIM and
SPF records will not
domain.
The *forwardAutoSubmittedEmails* option (default to false) can be used to
prevent forwarding bounces as such a scenario
-can lead to an infinite loop if the forward recipient bounces the email.
\ No newline at end of file
+can lead to an infinite loop if the forward recipient bounces the email.
+
+When *rewriteSenderUponForward* is enabled, forwarded copies carry the
`org.apache.james.forwarded` mail attribute set to `true`.
+Downstream mailets can match on this attribute to apply specific processing to
forwarded traffic (routing, rate-limiting, header rewriting…)
+without relying on fragile heuristics such as inspecting `Return-Path` or
envelope topology.
\ No newline at end of file
diff --git
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java
index a0a1f3a7d5..eede0636c4 100644
---
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java
+++
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java
@@ -57,6 +57,9 @@ import com.google.common.collect.ImmutableList;
*
* The <b>forwardAutoSubmittedEmails</b> option (default to false) can be used
to prevent forwarding bounces as such a scenario
* can lead to an infinite loop if the forward recipient bounces the email.
+ *
+ * When <b>rewriteSenderUponForward</b> is enabled, forwarded copies have the
{@code org.apache.james.forwarded} mail attribute set to {@code true},
+ * allowing downstream mailets to condition their behaviour on forwarded
traffic without heuristics.
*/
public class RecipientRewriteTable extends GenericMailet {
public static final String ERROR_PROCESSOR = "errorProcessor";
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 bea226ff77..1d04029c5d 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
@@ -49,6 +49,9 @@ import org.apache.james.rrt.lib.Mappings;
import org.apache.james.server.core.MailImpl;
import org.apache.james.util.AuditTrail;
import org.apache.james.util.MemoizedSupplier;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
import org.apache.mailet.DsnParameters;
import org.apache.mailet.DsnParameters.RecipientDsnParameters;
import org.apache.mailet.LoopPrevention;
@@ -69,6 +72,9 @@ import com.google.common.collect.Sets;
public class RecipientRewriteTableProcessor {
private static final Logger LOGGER =
LoggerFactory.getLogger(RecipientRewriteTableProcessor.class);
+
+ public static final AttributeName FORWARDED_ATTRIBUTE_NAME =
AttributeName.of("org.apache.james.forwarded");
+ private static final Attribute FORWARDED_ATTRIBUTE = new
Attribute(FORWARDED_ATTRIBUTE_NAME, AttributeValue.of(true));
private static final boolean REWRITE_SENDER_UPON_FORWARD = true;
private static final boolean FORWARD_AUTOMATED_EMAILS = true;
@@ -237,6 +243,7 @@ public class RecipientRewriteTableProcessor {
try {
copy.setSender(originalRecipient);
copy.setRecipients(newRecipients);
+ copy.setAttribute(FORWARDED_ATTRIBUTE);
recordedRecipients.merge(originalRecipient).recordOn(copy);
context.sendMail(copy);
diff --git
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessorTest.java
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessorTest.java
index c3ddac0d7b..a673b5209f 100644
---
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessorTest.java
+++
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessorTest.java
@@ -44,6 +44,7 @@ import org.apache.mailet.Attribute;
import org.apache.mailet.AttributeName;
import org.apache.mailet.AttributeValue;
import org.apache.mailet.Mail;
+import org.apache.mailet.ProcessingState;
import org.apache.mailet.base.MailAddressFixture;
import org.apache.mailet.base.test.FakeMail;
import org.apache.mailet.base.test.FakeMailContext;
@@ -348,6 +349,32 @@ class RecipientRewriteTableProcessorTest {
assertThat(mail.getRecipients()).isEmpty();
}
+ @Test
+ void processForwardsShouldSetForwardedAttributeOnForwardedCopy() throws
Exception {
+ RecipientRewriteTableProcessor processorWithRewrite = new
RecipientRewriteTableProcessor(
+ virtualTableStore, domainList, mailetContext, new
ProcessingState(Mail.ERROR), true, false);
+
+ virtualTableStore.addMapping(
+ MappingSource.fromMailAddress(MailAddressFixture.OTHER_AT_LOCAL),
+ Mapping.forward(MailAddressFixture.ANY_AT_JAMES.asString()));
+
+ mail = FakeMail.builder()
+ .name("mail")
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .mimeMessage(message)
+ .recipients(MailAddressFixture.OTHER_AT_LOCAL)
+ .build();
+
+ processorWithRewrite.processForwards(mail);
+
+ assertThat(mailetContext.getSentMails())
+ .hasSize(1)
+ .allSatisfy(sentMail -> assertThat(sentMail.getAttributes())
+ .containsEntry(
+ RecipientRewriteTableProcessor.FORWARDED_ATTRIBUTE_NAME,
+ new
Attribute(RecipientRewriteTableProcessor.FORWARDED_ATTRIBUTE_NAME,
AttributeValue.of(true))));
+ }
+
private void defineDefaultDomain(String jamesLocal) throws
ConfigurationException {
domainList.configure(DomainListConfiguration.builder().defaultDomain(Domain.of(jamesLocal)));
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]