1
+ // Papercut
2
+ //
3
+ // Copyright © 2008 - 2012 Ken Robertson
4
+ // Copyright © 2013 - 2024 Jaben Cargman
5
+ //
6
+ // Licensed under the Apache License, Version 2.0 (the "License");
7
+ // you may not use this file except in compliance with the License.
8
+ // You may obtain a copy of the License at
9
+ //
10
+ // http://www.apache.org/licenses/LICENSE-2.0
11
+ //
12
+ // Unless required by applicable law or agreed to in writing, software
13
+ // distributed under the License is distributed on an "AS IS" BASIS,
14
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ // See the License for the specific language governing permissions and
16
+ // limitations under the License.
17
+
18
+
19
+ using Autofac ;
20
+
21
+ using MimeKit ;
22
+ using Papercut . Core . Domain . Message ;
23
+ using Papercut . Core . Domain . Rules ;
24
+ using Papercut . Message ;
25
+ using Papercut . Message . Helpers ;
26
+ using Papercut . Rules . App . Relaying ;
27
+ using Papercut . Rules . Domain . Conditional . Forwarding ;
28
+
29
+ using Polly ;
30
+
31
+ namespace Papercut . Rules . App . Conditional . Forwarding ;
32
+
33
+ public class ConditionalForwardWithRetryRuleDispatch : IRuleDispatcher < ConditionalForwardWithRetryRule >
34
+ {
35
+ private readonly ILogger _logger ;
36
+
37
+ private readonly Lazy < MimeMessageLoader > _mimeMessageLoader ;
38
+
39
+ public ConditionalForwardWithRetryRuleDispatch ( Lazy < MimeMessageLoader > mimeMessageLoader , ILogger logger )
40
+ {
41
+ _mimeMessageLoader = mimeMessageLoader ;
42
+ _logger = logger ;
43
+ }
44
+
45
+ public async Task DispatchAsync ( ConditionalForwardWithRetryRule rule , MessageEntry messageEntry , CancellationToken token )
46
+ {
47
+ if ( rule == null ) throw new ArgumentNullException ( nameof ( rule ) ) ;
48
+ if ( messageEntry == null ) throw new ArgumentNullException ( nameof ( messageEntry ) ) ;
49
+
50
+ var message = await _mimeMessageLoader . Value . GetClonedAsync ( messageEntry , token ) ;
51
+
52
+ if ( ! RuleMatches ( rule , message ) )
53
+ {
54
+ return ;
55
+ }
56
+
57
+ rule . PopulateFromRule ( message ) ;
58
+
59
+ var polly = Policy
60
+ . Handle < Exception > ( )
61
+ . WaitAndRetryAsync (
62
+ rule . RetryAttempts ,
63
+ ( attempt ) => TimeSpan . FromSeconds ( rule . RetryAttemptDelaySeconds ) ,
64
+ ( exception , span ) =>
65
+ {
66
+ _logger . Error (
67
+ exception ,
68
+ "Failed to send {@MessageEntry} after {RetryAttempts}" ,
69
+ messageEntry ,
70
+ rule . RetryAttempts ) ;
71
+ } ) ;
72
+
73
+ async Task SendMessage ( )
74
+ {
75
+ using ( var client = await rule . CreateConnectedSmtpClientAsync ( token ) )
76
+ {
77
+ await client . SendAsync ( message , token ) ;
78
+ await client . DisconnectAsync ( true , token ) ;
79
+ }
80
+ }
81
+
82
+ await polly . ExecuteAsync ( async ( ) => await SendMessage ( ) ) ;
83
+ }
84
+
85
+ protected virtual bool RuleMatches ( ConditionalForwardWithRetryRule rule , MimeMessage mimeMessage )
86
+ {
87
+ return rule . IsConditionalForwardRuleMatch ( mimeMessage ) ;
88
+ }
89
+
90
+ #region Begin Static Container Registrations
91
+
92
+ /// <summary>
93
+ /// Called dynamically from the RegisterStaticMethods() call in the container module.
94
+ /// </summary>
95
+ /// <param name="builder"></param>
96
+ [ UsedImplicitly ]
97
+ static void Register ( ContainerBuilder builder )
98
+ {
99
+ if ( builder == null ) throw new ArgumentNullException ( nameof ( builder ) ) ;
100
+
101
+ builder . RegisterType < ConditionalForwardWithRetryRuleDispatch > ( )
102
+ . As < IRuleDispatcher < ConditionalForwardWithRetryRule > > ( ) . AsSelf ( ) . InstancePerDependency ( ) ;
103
+ }
104
+
105
+ #endregion
106
+ }
0 commit comments