diff --git a/services/mailer/incoming/incoming.go b/services/mailer/incoming/incoming.go index 555cdfee8b..6530b7cc60 100644 --- a/services/mailer/incoming/incoming.go +++ b/services/mailer/incoming/incoming.go @@ -219,7 +219,7 @@ loop: } err := func() error { - if handledSet.Contains(msg.SeqNum) { + if isAlreadyHandled(handledSet, msg) { log.Debug("Skipping already handled message") return nil } @@ -282,6 +282,11 @@ loop: return nil } +// isAlreadyHandled tests if the message was already handled +func isAlreadyHandled(handledSet *imap.SeqSet, msg *imap.Message) bool { + return handledSet.Contains(msg.SeqNum) +} + // isAutomaticReply tests if the headers indicate an automatic reply func isAutomaticReply(env *enmime.Envelope) bool { autoSubmitted := env.GetHeader("Auto-Submitted") diff --git a/services/mailer/incoming/incoming_test.go b/services/mailer/incoming/incoming_test.go index 5d84848e3f..f2bb7fc498 100644 --- a/services/mailer/incoming/incoming_test.go +++ b/services/mailer/incoming/incoming_test.go @@ -7,10 +7,24 @@ import ( "strings" "testing" + "github.com/emersion/go-imap" "github.com/jhillyerd/enmime" "github.com/stretchr/testify/assert" ) +func TestNotHandleTwice(t *testing.T) { + handledSet := new(imap.SeqSet) + msg := imap.NewMessage(90, []imap.FetchItem{imap.FetchBody}) + + handled := isAlreadyHandled(handledSet, msg) + assert.Equal(t, false, handled) + + handledSet.AddNum(msg.SeqNum) + + handled = isAlreadyHandled(handledSet, msg) + assert.Equal(t, true, handled) +} + func TestIsAutomaticReply(t *testing.T) { cases := []struct { Headers map[string]string @@ -95,6 +109,32 @@ func TestGetContentFromMailReader(t *testing.T) { assert.Equal(t, "attachment.txt", content.Attachments[0].Name) assert.Equal(t, []byte("attachment content"), content.Attachments[0].Content) + mailString = "Content-Type: multipart/mixed; boundary=message-boundary\r\n" + + "\r\n" + + "--message-boundary\r\n" + + "Content-Type: multipart/alternative; boundary=text-boundary\r\n" + + "\r\n" + + "--text-boundary\r\n" + + "Content-Type: text/plain\r\n" + + "Content-Disposition: inline\r\n" + + "\r\n" + + "mail content\r\n" + + "--text-boundary--\r\n" + + "--message-boundary\r\n" + + "Content-Type: text/plain\r\n" + + "Content-Disposition: inline; filename=attachment.txt\r\n" + + "\r\n" + + "attachment content\r\n" + + "--message-boundary--\r\n" + + env, err = enmime.ReadEnvelope(strings.NewReader(mailString)) + assert.NoError(t, err) + content = getContentFromMailReader(env) + assert.Equal(t, "mail content", content.Content) + assert.Len(t, content.Attachments, 1) + assert.Equal(t, "attachment.txt", content.Attachments[0].Name) + assert.Equal(t, []byte("attachment content"), content.Attachments[0].Content) + mailString = "Content-Type: multipart/mixed; boundary=message-boundary\r\n" + "\r\n" + "--message-boundary\r\n" +