2020package org .apache .james .transport .mailets ;
2121
2222import java .time .ZonedDateTime ;
23+ import java .util .Arrays ;
2324import java .util .Collection ;
2425import java .util .Locale ;
2526import java .util .Optional ;
27+ import java .util .stream .Stream ;
2628
2729import jakarta .inject .Inject ;
2830import jakarta .mail .Address ;
5557
5658public class VacationMailet extends GenericMailet {
5759
60+ enum ReplyMode {
61+ ENVELOPE ("envelope" ),
62+ REPLY_TO_HEADER ("replyToHeader" );
63+
64+ public static Optional <ReplyMode > parse (String value ) {
65+ return Arrays .stream (ReplyMode .values ())
66+ .filter (replyMode -> replyMode .value .equalsIgnoreCase (value ))
67+ .findFirst ();
68+ }
69+
70+ private final String value ;
71+
72+ ReplyMode (String value ) {
73+ this .value = value ;
74+ }
75+ }
76+
5877 private static final Logger LOGGER = LoggerFactory .getLogger (VacationMailet .class );
5978
6079 private final VacationService vacationService ;
6180 private final ZonedDateTimeProvider zonedDateTimeProvider ;
6281 private final AutomaticallySentMailDetector automaticallySentMailDetector ;
6382 private final MimeMessageBodyGenerator mimeMessageBodyGenerator ;
6483 private boolean useUserAsMailFrom = false ;
84+ private ReplyMode replyMode = ReplyMode .REPLY_TO_HEADER ;
6585
6686 @ Inject
6787 public VacationMailet (VacationService vacationService , ZonedDateTimeProvider zonedDateTimeProvider ,
@@ -85,7 +105,7 @@ public void service(Mail mail) {
85105 if (!automaticallySentMailDetector .isAutomaticallySent (mail ) && hasReplyToHeaderField && !isNoReplySender (mail )) {
86106 ZonedDateTime processingDate = zonedDateTimeProvider .get ();
87107 mail .getRecipients ()
88- .forEach (mailAddress -> manageVacation (mailAddress , mail , processingDate ));
108+ .forEach (Throwing . consumer ( mailAddress -> manageVacation (mailAddress , mail , processingDate ) ));
89109 }
90110 } catch (AddressException e ) {
91111 if (!e .getMessage ().equals ("Empty address" )) {
@@ -99,18 +119,16 @@ public void service(Mail mail) {
99119 @ Override
100120 public void init () throws MessagingException {
101121 useUserAsMailFrom = MailetUtil .getInitParameter (getMailetConfig (), "useUserAsMailFrom" ).orElse (false );
122+ replyMode = Optional .ofNullable (getInitParameter ("replyMode" ))
123+ .map (value -> ReplyMode .parse (value ).orElseThrow (() -> new IllegalArgumentException ("Unsupported ReplyMode " + value )))
124+ .orElse (ReplyMode .REPLY_TO_HEADER );
102125 }
103126
104127 private static Address [] getReplyTo (Mail mail ) throws MessagingException {
105128 try {
106129 return mail .getMessage ().getReplyTo ();
107130 } catch (AddressException e ) {
108- InternetAddress [] replyTo = StreamUtils .ofNullable (mail .getMessage ().getHeader ("Reply-To" ))
109- .map (LenientAddressParser .DEFAULT ::parseAddressList )
110- .flatMap (Collection ::stream )
111- .filter (Mailbox .class ::isInstance )
112- .map (Mailbox .class ::cast )
113- .map (Mailbox ::getAddress )
131+ InternetAddress [] replyTo = parseReplyToField (mail )
114132 .map (Throwing .function (InternetAddress ::new ))
115133 .toArray (InternetAddress []::new );
116134
@@ -125,20 +143,40 @@ private static Address[] getReplyTo(Mail mail) throws MessagingException {
125143 }
126144 }
127145
128- private void manageVacation (MailAddress recipient , Mail processedMail , ZonedDateTime processingDate ) {
146+ private static Stream <String > parseReplyToField (Mail mail ) throws MessagingException {
147+ return StreamUtils .ofNullable (mail .getMessage ().getHeader ("Reply-To" ))
148+ .map (LenientAddressParser .DEFAULT ::parseAddressList )
149+ .flatMap (Collection ::stream )
150+ .filter (Mailbox .class ::isInstance )
151+ .map (Mailbox .class ::cast )
152+ .map (Mailbox ::getAddress );
153+ }
154+
155+ private void manageVacation (MailAddress recipient , Mail processedMail , ZonedDateTime processingDate ) throws MessagingException {
129156 if (isSentToSelf (processedMail .getMaybeSender ().asOptional (), recipient )) {
130157 return ;
131158 }
132159
133- RecipientId replyRecipient = RecipientId . fromMailAddress (processedMail . getMaybeSender (). get () );
160+ RecipientId replyRecipient = computeReplyRecipient (processedMail );
134161 VacationInformation vacationInformation = retrieveVacationInformation (recipient , replyRecipient );
135162
136- boolean shouldSendNotification = vacationInformation .vacation .isActiveAtDate (processingDate ) && !vacationInformation .alreadySent ;
163+ boolean shouldSendNotification = vacationInformation .vacation () .isActiveAtDate (processingDate ) && !vacationInformation .alreadySent ;
137164 if (shouldSendNotification ) {
138165 sendNotification (processedMail , vacationInformation );
139166 }
140167 }
141168
169+ private RecipientId computeReplyRecipient (Mail processedMail ) throws MessagingException {
170+ return switch (replyMode ) {
171+ case ENVELOPE -> RecipientId .fromMailAddress (processedMail .getMaybeSender ().get ());
172+ case REPLY_TO_HEADER -> RecipientId .fromMailAddress (
173+ parseReplyToField (processedMail )
174+ .findFirst ()
175+ .map (Throwing .function (MailAddress ::new ))
176+ .orElse (processedMail .getMaybeSender ().get ()));
177+ };
178+ }
179+
142180 record VacationInformation (Vacation vacation , MailAddress recipient , AccountId accountId , RecipientId replyRecipient , Boolean alreadySent ) {
143181
144182 }
0 commit comments