@@ -11,6 +11,7 @@ import (
11
11
"github.com/abhinavxd/libredesk/internal/attachment"
12
12
"github.com/abhinavxd/libredesk/internal/conversation/models"
13
13
"github.com/abhinavxd/libredesk/internal/envelope"
14
+ "github.com/abhinavxd/libredesk/internal/stringutil"
14
15
umodels "github.com/abhinavxd/libredesk/internal/user/models"
15
16
"github.com/emersion/go-imap/v2"
16
17
"github.com/emersion/go-imap/v2/imapclient"
@@ -136,8 +137,9 @@ func (e *Email) fetchAndProcessMessages(ctx context.Context, client *imapclient.
136
137
{
137
138
Specifier : imap .PartSpecifierHeader ,
138
139
HeaderFields : []string {
139
- "Auto-Submitted" ,
140
- "X-Autoreply" ,
140
+ headerAutoSubmitted ,
141
+ headerAutoreply ,
142
+ headerLibredeskLoopPrevention ,
141
143
},
142
144
},
143
145
},
@@ -148,10 +150,18 @@ func (e *Email) fetchAndProcessMessages(ctx context.Context, client *imapclient.
148
150
env * imap.Envelope
149
151
seqNum uint32
150
152
autoReply bool
153
+ isLoop bool
151
154
}
152
155
var messages []msgData
153
156
154
157
fetchCmd := client .Fetch (seqSet , fetchOptions )
158
+
159
+ // Extract the inbox email address.
160
+ inboxEmail , err := stringutil .ExtractEmail (e .FromAddress ())
161
+ if err != nil {
162
+ e .lo .Error ("failed to extract email address from the 'From' header" , "error" , err )
163
+ return fmt .Errorf ("failed to extract email address from 'From' header: %w" , err )
164
+ }
155
165
for {
156
166
// Check for context cancellation before fetching the next message.
157
167
select {
@@ -170,6 +180,7 @@ func (e *Email) fetchAndProcessMessages(ctx context.Context, client *imapclient.
170
180
var (
171
181
env * imap.Envelope
172
182
autoReply bool
183
+ isLoop bool
173
184
)
174
185
// Process all fetch items for the current message.
175
186
for {
@@ -197,6 +208,9 @@ func (e *Email) fetchAndProcessMessages(ctx context.Context, client *imapclient.
197
208
if isAutoReply (envelope ) {
198
209
autoReply = true
199
210
}
211
+ if isLoopMessage (envelope , inboxEmail ) {
212
+ isLoop = true
213
+ }
200
214
}
201
215
202
216
// Envelope.
@@ -210,7 +224,7 @@ func (e *Email) fetchAndProcessMessages(ctx context.Context, client *imapclient.
210
224
continue
211
225
}
212
226
213
- messages = append (messages , msgData {env : env , seqNum : msg .SeqNum , autoReply : autoReply })
227
+ messages = append (messages , msgData {env : env , seqNum : msg .SeqNum , autoReply : autoReply , isLoop : isLoop })
214
228
}
215
229
216
230
// Now process each collected message.
@@ -228,6 +242,12 @@ func (e *Email) fetchAndProcessMessages(ctx context.Context, client *imapclient.
228
242
continue
229
243
}
230
244
245
+ // Skip if this message is a loop prevention message.
246
+ if msgData .isLoop {
247
+ e .lo .Info ("skipping message with loop prevention header" , "subject" , msgData .env .Subject , "message_id" , msgData .env .MessageID )
248
+ continue
249
+ }
250
+
231
251
// Process the envelope.
232
252
if err := e .processEnvelope (ctx , client , msgData .env , msgData .seqNum , inboxID ); err != nil && err != context .Canceled {
233
253
e .lo .Error ("error processing envelope" , "error" , err )
@@ -484,6 +504,15 @@ func isAutoReply(envelope *enmime.Envelope) bool {
484
504
return false
485
505
}
486
506
507
+ // isLoopMessage returns true if the email is a loop prevention message. i.e., it has the `X-Libredesk-Loop-Prevention` header with the inbox email address.
508
+ func isLoopMessage (envelope * enmime.Envelope , inboxEmailaddress string ) bool {
509
+ loopHeader := envelope .GetHeader (headerLibredeskLoopPrevention )
510
+ if loopHeader == "" {
511
+ return false
512
+ }
513
+ return strings .EqualFold (loopHeader , inboxEmailaddress )
514
+ }
515
+
487
516
// extractAllHTMLParts extracts all HTML parts from the given enmime part by traversing the tree.
488
517
func extractAllHTMLParts (part * enmime.Part ) []string {
489
518
var htmlParts []string
0 commit comments